unity学习笔记(3)unity脚本

(一)脚本介绍

1.脚本介绍:

附加在游戏物体上用于定义游戏对象行为的指令代码(.cs文件)就是一个类 

支持三种高级编程语言:c# 、JavaScript;

unity自带开发工具:MonoDevelop 支持多个集成开发环境;visual studio 主要用这个

更改模板:unity--属性--打开文件位置--data--tools64--resource--scripttemplates--81-C#.txt


2.语法结构:

using 命名空间;//避免类重名

public class 类名:MonoBehaviour

{

    void 方法名(){

           Debug.Log("调试显示信息");

           print(“本质就是Debug.Log方法”);

    }

}

文件名和类名一致;写好的脚本必须附加到物体上才执行;附加到游戏物体的脚本类必须从MOnoBehavior类继承(实际上是,把类的实例对象交给了gameobject

编译过程:源代码--CLS--中间语言(dll)--Mono Runtime--机器码


 

3.脚本生命周期:脚本从唤醒到销毁的过程

必然事件、消息:当满足某种条件unity自动调用的函数  

搜索:unity5圣典--monobehaviour / un11ity组件旁边的小书

三个问题:名字 时机 适用性

初始阶段:Awake(物体载入立即调用;常用于游戏开始前进行初始化,可以判断当满足某种条件执行此脚本 this.enble=true) OnEnable(脚本启用就执行) Start

物理阶段:FixedUpdate  Update  LateUpdate(延迟更新 在update函数被调用后执行 适用于跟随逻辑 实际操作差别不大)

输入事件:OnMouseDown(前提是物体有碰撞器组件)OnMouseEnter OnMouseOver OnMouseUp OnMouseExit

场景渲染:OnBecameVisible 当Mesh Renderer在任何摄像机上可见  OnBecameInVisible:都不可见

结束阶段:OnDestroy (当脚本或者游戏对象销毁) Ondisable(当对象不可用时激活 或者复数游戏对象非激活)OnApplicationQuit(当程序结束)

 

新建Lifecycle.cs文件,代码示例1:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// 
/// 脚本生命周期/必然事件/消息 Message
/// 

public class Lifecycle : MonoBehaviour
{
    //C#:字段 属性 构造函数 方法
    //脚本:字段 方法
    
    public int a=100;//public的对象,在检查器中能显示,可快速更改数据 100是默认情况


    //序列化字段 作用:在编辑器中显示私有变量
    [SerializeField]
    private int b = 100;//不希望被访问 但是希望检查器能看见

    //在编译器中隐藏字段 可访问
    [HideInInspector] 
    public int c = 100;

    //在编译器中修改的时候有范围限制
    [Range(0,100)]
    public int d = 50;

    //属性在检查器看不见,在脚本中一般不写
    public int A
    {
        get
        {
            return this.a;
        }
        set 
        {
            this.a = value;
        }
    }

    //错误情况:不能在子线程中访问主线程成员
    //不要在脚本中写构造函数
    /*
    public float e;
    public Lifecycle()
    {
        e = Time.time;
        Debug.Log("构造函数");//相当于writeline 运行时在控制台
    }
    */
    

    //**********************初始阶段***********************//
    //执行时机:创建游戏对象 执行1次
    //作用:初始化
    private void Awake()
    {
        Debug.Log("Awake"+Time.time+"--"+this.name);//Awake0 表示0秒被执行 
    }

    //所有物体的awake执行后再start 但是awake暂时不可以规定谁先

    //执行时机:游戏物体创建 脚本启用后 执行1次
    //作用:初始化
    private void Start()
    {
        Debug.Log("Start" + Time.time + this.name);//先Awake再Start  
    }


    //**********************物理阶段***********************//
    //执行时机:每隔固定时间(0.02)执行(可以修改 不建议)
    //适用性:适用于对对象进行物理操作(移动、旋转等) 不会受到渲染影响
    //渲染时间不固定 (每帧渲染量不同、机器性能不同)
    private void FixedUpdate()
    {
        Debug.Log("FixedUpdate" + Time.time + "--" + this.name);
    }
    //执行时机:渲染帧执行,执行间隔不固定
    //适用性:处理游戏逻辑 按帧移动
    private void Update()
    {
      
    }

    private void OnMouseDown()
    {
        Debug.Log("OnMouseDown");
    }

    private void OnMouseEnter()
    {
        
    }


}

4.调试:将程序投入到实际运行,通过开发工具进行测试,修正逻辑错误的过程

1.控制台调试:debug.log print(仅仅在脚本中可以直接使用)

控制台面板:清除 折叠 播放时清除(√) 创建时清空 错误暂停 editor  右边的小图标框也要选中

unity源代码查看:Resource--IL Spy.exe///Library--UnityAssemblies--UnityEngine.dll 

/Library--ScriptAssemblies--Assembly-CSharp.dll(自己写了的所有脚本)

2.定义共有变量,程序运行后在检查器面板查看
3.vs:准备工作:安装vs201X工具(2019vs安装好unity部分就可以自动附加)右键--快速监视(或者即时窗口) 可以监视组件(this.transform);调试工作:在出错的行加断点 启动调试 在unity中play场景

单帧调试:启动调试 运行场景 暂停游戏 加断点 单帧执行 结束调试

 

 

(二)常用API

核心类图

1.Component(2)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// 
/// Component类提供了查找(在当前物体、后代、先辈)组件的功能
/// 
public class ComponentDemo : MonoBehaviour
{
    // Start is called before the first frame update
    private void OnGUI()
    {
        if(GUILayout.Button("transform"))
        {
            this.transform.position = new Vector3(0, 0, 10);
          
        }
        if (GUILayout.Button("GetComponent"))
        {
           
            this.GetComponent().material.color = Color.red;

        }
        if (GUILayout.Button("GetComponents"))
        {
            //获取当前物体所有组件
            var allComponent=this.GetComponents();
            foreach(var item in allComponent)
            {
                Debug.Log(item.GetType());
            }

        }
        if (GUILayout.Button("GetComponentsInChildren"))
        {
            //从自身开始找后辈
            //获取后代物体的指定类型组件
            //GetComponentsInParent 找父母
            var allComponent = this.GetComponentsInChildren();
            foreach (var item in allComponent)
            {
                item.material.color=Color.red;
            }

        }
    }

}

2.Transform(3)

 

position:在世界坐标系里的位置

localposition:检查器中的position 相对的

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// 
/// Transform类提供了查找变换组件功能(查找父、根、子) 改变位置角度大小功能
/// 
public class TransformDemo : MonoBehaviour
{
    public Transform tf;
    private void OnGUI()
    {
        ////////////////////查找变换组件/////////////////////////
        if(GUILayout.Button("foreach-transform"))
        {
            foreach(Transform child in this.transform)
            {
                //child为子物体的变换组件                
                print(child.name);
            }
        }
        if (GUILayout.Button("root"))
        {
            //获取根物体变换组件
            Transform rootTF = this.transform.root;
        }

        if (GUILayout.Button("parent"))
        {
            //获取父物体变换组件
            Transform parentTF = this.transform.parent;
        }

        if (GUILayout.Button("SetParent"))
        {
            //获取父物体变换组件
            //this.transform.SetParent(tf);
            //true 当前物体的位置视为世界坐标
            //this.transform.SetParent(tf, true);
            //false 当前物体的位置视为localposition
            this.transform.SetParent(tf,false);
        }


        if (GUILayout.Button("Find"))
        {
            Transform childTF = this.transform.Find("子物体名称");
            //Transform childTF = this.transform.Find("子物体名称/子物体名称");

        }
        
        if(GUILayout.Button("childTF"))
        {
            int count = this.transform.childCount;
            //根据索引获得子物体
            for(int i = 0; i < count; i++)
            {
                this.transform.GetChild(i);
            }

        }
        //解除子对象父子关系 DetachChildren
        //不要这个爸爸了:setParent=null;

        ////////////////////////////////////////

        //////////////////// 改变位置角度大小功能/////////////////////////

        if (GUILayout.Button("pos/scale"))
        {

            //物体相对于世界坐标系原点的位置
            //this.transform.position;
            //物体相对于父物体轴心点的位置
            //this.transform.localPosition;

            //物体相对于父物体轴心点的位置 1 2 1 沿着y轴 是父物体的两倍
            //this.transform.localScale;
            //理解为:物体与模型缩放比例(自身缩放比例*父物体缩放比例)
            //this.transform.LossyScale;
            //比如:父物体localscale为3 当前物体localscale为2  lossyscale为6


            //向自身坐标系z轴 移动1米
            this.transform.Translate(0, 0, 1);
            //向世界坐标系z轴移动1米
            this.transform.Translate(0, 0, 1, Space.World);
        }

        if (GUILayout.Button("Rotate"))
        {
            //沿着自身坐标系z轴 旋转10度
            this.transform.Rotate(0, 0, 1);
            //沿着世界坐标系z轴 旋转10度
            this.transform.Rotate(0, 0, 1, Space.World);
        }
        if (GUILayout.RepeatButton("RotateAround"))
        {
            //绕零点y轴转1度
            this.transform.RotateAround(Vector3.zero,Vector3.up,1);
            //绕零点z轴转1度
            this.transform.RotateAround(Vector3.zero, Vector3.forward, 1);
        }
        if (GUILayout.RepeatButton("RotateAround"))
        {
            //绕零点y轴转1度
            this.transform.RotateAround(Vector3.zero, Vector3.up, 1);
            //绕零点z轴转1度
            this.transform.RotateAround(Vector3.zero, Vector3.forward, 1);
        }
    }

}

 

 

3.GameObject2

activeInHierarchy:实际上的激活状态

activeSelf:自身的激活状态

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameObjectDemo : MonoBehaviour
{
    private void OnGUI()
    {
        //场景中物体激活状态
        //this.gameObject.activeInHierarchy
        //物体自身激活状态
        //this.gameObject.activeSelf
        //设置物体禁用启用
        //this.gameObject.SetActive(true);
        
        if (GUILayout.Button("添加光源"))
        {
            //创建物体
            GameObject lightGo = new GameObject();
            //添加组件
            Light light= lightGo.gameObject.AddComponent();
            light.color = Color.red;
            light.type = LightType.Point;
        }
        //在场景中根据名称找物体(不建议使用)
        //GameObject.Find("游戏名称");
        //this.transform.Find("");//可以
        //获取所有使用该标签的物体
        GameObject[] allEnemy = GameObject.FindGameObjectsWithTag("");
        //获取所有使用该标签的物体(单个)
        GameObject playerGO = GameObject.FindWithTag("");
    }
}

 

4.Object1

Destory:删除一个游戏对象、组件、资源

DontDestoryOnLoad:加载新场景的时候不删除

FindObjectOfType:根据类型找对象

  //根据类型查找对象
        Object.FindObjectOfType();
        FindObjectsOfType();
        //销毁对象
        //Object.Destroy

代码示例2:查找血量最低的敌人

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Findenemy : MonoBehaviour
{
    private void OnGUI()
    {
        if(GUILayout.Button("查找血量最低的敌人"))
        {
            //查找场景中所有Enemy类型的引用
            Enemy[] allEnemy = Object.FindObjectsOfType();
            //获取血量最低的引用
            Enemy min = FindEnemyByMinHP(allEnemy);
            //根据Enemy类型引用 获取 其他组件类型的引用
            min.GetComponent().material.color = Color.red;
        }
    }
    public Enemy FindEnemyByMinHP(Enemy[] allEnemy)
    {
        //假设第一个就是血量最低
        Enemy min= allEnemy[0];      
        for(int i=0;i allEnemy[i].HP)
                min = allEnemy[i]; 
        }
        return min;
    }
   
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy : MonoBehaviour
{
    public int HP;
}

代码示例2:层级未知 查找子物体

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TransformHelper 
{
    /// 
    /// 在层级未知情况下查找子物体
    /// 
    /// 父物体变换组件
    /// 子物体名称
    /// 
    public static Transform AutoGetChild(Transform parentTF,string childName)
    {
        //在子物体中查找
        Transform childTF= parentTF.Find(childName);
        if (childTF != null) return childTF;
        //将问题交由子物体

        int count = parentTF.childCount;

        for(int i = 0; i < count; i++)
        {
            childTF= AutoGetChild(parentTF.GetChild(i),childName);
            if(childTF != null) return childTF;
        }
        return null;

    }
}
    private void OnGUI()
    {

        if (GUILayout.Button("查找血量最低的敌人 层级未知 查找子物体"))
        {

            var childTF= TransformHelper.AutoGetChild(this.transform, "Sphere (4)");
            childTF.GetComponent().material.color = Color.yellow;
        }
    }

 

5.Time

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.SocialPlatforms;

public class TimeDemo : MonoBehaviour
{
    public float t;

    //Update不会受到timescale影响,Time.deltaTime会受到影响
    public void Update()
    {
        t = Time.time; //受缩放影响的游戏运行时间
        t = Time.deltaTime;//完成最后一帧的时间 一次渲染的时间
        t = Time.unscaledDeltaTime;//不受缩放影响的游戏运行时间
        t =Time.realtimeSinceStartup;//实际游戏运行时间

        //每渲染帧 执行1次 旋转一度
        //帧多 1s旋转速度很快 希望慢 希望一帧旋转量小(Time.deltaTime) 
        //帧少            慢
        this.transform.Rotate(0, 0, 1);
        //旋转速度*每帧消耗时间,可以保证旋转速度不受机器性能,以及渲染影响

         this.transform.Rotate(0, 0, 1*Time.deltaTime,0);
    }

    public int speed = 200;

    //固定0.02s执行一次,与渲染无关,可以不乘Time.deltaTime
    //FixedUpdate会收timescale影响
    public void FixedUpdate()
    {
        this.transform.Rotate(0, speed, 0);
       
    }
    private void OnGUI()
    {
        if(GUILayout.Button("暂停游戏"))
        {
            Time.timeScale = 0;
        }
        if (GUILayout.Button("继续游戏"))
        {
            Time.timeScale = 1;
        }
       
    }
    //游戏暂停,个别物体不受影响:代码在update中;Time.deltaTime换成unscaledDeltaTime 不受缩放影响的每帧间隔
   
}

ui-text :挂在文本上的脚本:倒计时,两种方法

方法1 Time.time :如果到了某时间

方法2 Time.deltatime   :如果按下左键 如果到了修改时间 比较适合子弹发射这种场合

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
/// 
/// 倒计时
/// 
public class CountDownTimer : MonoBehaviour
{
    // Update is called once per frame
    private Text txtTimer;
    public int second = 120;
    public float nextTime=1;//下次修改时间

    private void Start()
    {
        txtTimer = this.GetComponent();
    }


    private void Update()
    {
        //需求:1s修改一次文本内容
        //1.查找组件引用
        //2.定义变量:秒second
        //3.120--02.00
        //4.修改文本

        //5.如何每秒修改一次
        if (Time.time>=nextTime) 
        { 
            second--;
            txtTimer.text = string.Format("{0:d2}:{1:d2}", second / 60, second % 60);
            if (second <= 10)
                txtTimer.color = Color.red;
            
            nextTime = Time.time + 1;//设置下次修改时间
        }

    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
/// 
/// 倒计时
/// 
public class CountDownTimer : MonoBehaviour
{
    // Update is called once per frame
    private Text txtTimer;
    public int second = 120;
    public float nextTime=1;//下次修改时间

    private void Start()
    {
        txtTimer = this.GetComponent();
    }


    private void Update()
    {

        //Timer1();

        Timer2();
    }
    private void Timer1()
    {

      //需求:1s修改一次文本内容
        //1.查找组件引用
        //2.定义变量:秒second
        //3.120--02.00
        //4.修改文本

        //5.如何每秒修改一次
        if (Time.time>=nextTime) 
        { 
            second--;
            txtTimer.text = string.Format("{0:d2}:{1:d2}", second / 60, second % 60);
            if (second <= 10)
                txtTimer.color = Color.red;
            
            nextTime = Time.time + 1;//设置下次修改时间
        }
    }
    private float totalTime;
    private void Timer2()
    {
        //累加每帧间隔
        totalTime+=Time.deltaTime;
        if(totalTime>=1)
        {
            second--;
            txtTimer.text = string.Format("{0:d2}:{1:d2}", second / 60, second % 60);
            if (second <= 10)
                 txtTimer.color = Color.red;
            totalTime = 0;
        }
    }
 }

start中方法重复使用:

方法三invoke

        InvokeRepeating("Timer1", 1, 1);//方法名,开始时间,间隔时间
        //Invoke(被执行的方法,开始调用时间);

取消所有某方法的执行:

            if (second < 0)
            {
                CancelInvoke("Timer1");
            }

将层级中的游戏对象保存到项目中以便下次使用:直接拖给项目

预制件prefabs:一种资源类型,可以多次在场景中出现 

对预制件修改可以同步到所有实例

如果单独修改某实例 则该值不再随预制件变化

select:通过预制件实例选择对应预制件

revert:放弃实例属性值,还原预制件属性值

apply:将某一实例的修改应用到所有实例

 

(三)动画

动画视图中直接创建和修改动画片段  :windows--animation

创建动画片段:为物体添加Animation组件 在动画视图中创建片段

添加属性->设置动画(具体操作跟AE相似)-->将片段拖动给对象的组件

时间线:60帧1s,使用按钮上下跳帧

动画播放模式:default once(点一次做一次) loop(循环的) pingpong(从头到尾从尾到头) clamp forever(从头播放到尾一直播放最后一帧)

unity学习笔记(3)unity脚本_第1张图片

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// 
/// 门
/// 
public class Door : MonoBehaviour
{
    public bool doorState = false;
    private Animation anim;
    public string animName = "Door";


    private void Start()
    {
        anim = GetComponent();
    }

    private void OnMouseDown()
    {
        //关门操作1--->0
        if(doorState)
        {
            //当动画正在播放的时候不要重置
            if (anim.isPlaying == false)
            { 
                //从最后开始
                anim[animName].time = anim[animName].length;
            }   
            anim[animName].speed = -1;//逆着播放           
        }
        else
        //开门操作0--->1
        {
            anim[animName].speed = 1;//正着播放 
        }
        //播放动画
        anim.Play(animName);
        doorState = !doorState;
    }
}

 

你可能感兴趣的:(unity)