• Unity与C#


    PlasticSCM:版本管理工具

    工程目录结构

    (主要)Assets:资源(存放场景、脚本、模型、素材)
    Assets中.meta文件为属性文件,标识文件id,方便unity管理
    (主要)Library:系统的一些库
    Logs:日志
    Packages:导入的一些包
    ProjectSettings:工程相关的设置。
    Temp:临时的文件夹(可能放一些临时文件与缓存)
    UserSettings:也是编辑器设置相关的
    SampleScene:游戏场景,通过create=》scene创建游戏场景
    packages:包含了一些包和内置插件

    unity编辑器的使用

    game与Scene窗口可拖动,窗口布局可以通过Layers修改,一般使用Tall
    project:一般存放工程资源,这块可调整列数与图标大小,project与Assets文件夹是对应的,创建的C#脚本放在Assets文件夹中。在Edit的Snap Setting能设置设置每次移动的长度,默认是一次移动一米。

    快捷键

    按住shift:等比例缩放图片
    按住option+左键:能拖拽整个画面
    选中文件,再点击一下就能修改文件名
    页面上选中物体,commond+D为复制物体
    unity打开控制台:Window=>General=>Console(command+shift+c)
    option + 回车 引入Image所在的命名空间:UnityEngine.UI
    按住control再移动物体,能实现单位化移动。可以在Edit => Snap Setting中设置每次移动的多少,默认是一次移动一米。
    按下V能实现顶点吸附,再按一下V恢复正常。
    control+N:创建新场景
    Q、W、E、R、T对应拖动、旋转那几个按钮。
    选中摄像机再command+shift+f:让摄像机聚焦到我们的物体

    五个面板

    Hierarchy: 层级面板,显示当前场景有哪些东西,层级可嵌套、切换。
    inspector:检视面板,查看一个游戏物体由哪些“组件”组成。例如Transform、Mesh Renderer、Sphere、Collider这些都是一个组件。
    gameObject:游戏物体,场景中的任何东西都叫一个游戏物体,
    scene:场景面板,用来显示与编辑当前场景。
    game:点击运行按钮,当场景运行起来时,玩家看到的游戏场景样子。不可编辑

    render:控制渲染的样子(添加的material就放在这里面)
    collider:控制碰撞(空气墙)
    unity游戏引擎帮助我们做了碰撞检测,我们只要写游戏的逻辑
    Rigidbody组件能给游戏物体添加重力属性。
    每个被创建的C#脚本也相当于一个组件,我们在“游戏物体”上通过Add Component添加。
    使用组件前要把组件勾选上,不然没有效果。
    删除脚本组件时,要把“游戏物体”上对应的脚本文件删除,不然会出现警告。
    unity打开控制台:Window=>General=>Console(command+shift+c)

    C#代码介绍:
    using System.Collections; // 引用系统的类
    using System.Collections.Generic;
    using UnityEngine;

    创建的注意文件名要保持与类名一致,创建一个脚本相当于创建了一个类。初次在unity中创建文件时他们的名称是一致的,二次修改文件名时要保证类名也要同样修改。

    Start:开始方法
    作用:游戏启动时做一些初始化的工作。

    Update:更新方法
    作用:控制游戏的一些更新,具体根据功能来定。游戏运行时会一直重复调用Update方法(每一帧调用一次)

    游戏物体有的有钢体组件,有些没有,通过代码让他们产生关联.
    预制体(Prefabs):相当于一个模板,通过模板可以统一修改物体上一些组件、属性之类的,有模板生成的游戏物体会被统一修改。
    在Project模板中修改预制体会同步“孩子”都会修改,在Hierarchy模板中修改“孩子”就不会同步其他“孩子”。但“孩子”也能映射到“母亲”身上通过overrides=>Apply All
    制作了一个预制体,然后把预制体删了,那么和预制体关联的游戏物体就会变红,通过GameObject => Break Prefab Instance 取消关联

    系统事件:
    每个游戏物体都有标签和名字,且可重复。
    给预制体添加标签:
    在这里插入图片描述
    勾上 is Trigger,碰撞器变为触发器,可穿模。
    在这里插入图片描述

    编辑UI中的text:设置2D,双击canvas,因为canvas是2D的,画布对应game窗口。
    设置text位置:
    在这里插入图片描述

    获取其它游戏物体身上的组件:
    在这里插入图片描述
    红色小球:
    在这里插入图片描述

    using System.Collections; 
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.SocialPlatforms.Impl;
    using UnityEngine.UI; // 引入UI命名空间,不然找不到Text组件
    
    public class Player : MonoBehaviour
    {
        // Start is called before the first frame update
    
        // public定义的为公开的属性,可以在Inspector面板中看到,private为私有属性,在面板中不能看到。
        // 通常只设置必要的属性为公开,一般为私有,防止误操作。
       
        public Rigidbody rd; // 定义一个钢体组件,简写为rd,控制小球运动
        public int score;
        public Text scoreText;// 定义一个text组件
        public GameObject winText; // 定义一个游戏物体,因为一会我们要控制游戏物体,目前胜利的游戏物体是禁用的。
    
        void Start()
        {
            // 指定要得到的组件为钢体组件,也可以通过拖拽钢体组件的方式,但一般用代码
            rd = GetComponent<Rigidbody>();
        }
    
    
        // Update is called once per frame
        void Update()
        {
            // 方向:right、left 前:forword、后:back
            // 方向的方法只监听八个键,四个方向键与W、S、A、D,其他的键不管用
            //Input:与按键相关的监听与处理,GetAxis:轴、Horizontal:水平轴、vertical:垂直轴
    
            float h = Input.GetAxis("Horizontal"); // GetAxis方法返回一个小于1的小数(-1,1)数字是渐变的,赋值给h
            //Debug.Log(h);
            float v = Input.GetAxis("Vertical");
    
            // 施加一个向右的力,大小相当于1牛
            //rd.AddForce(Vector3.right);
    
            // 加速:(1,2,3) * 2 = (2,4,6)
    
            //rd.AddForce(new Vector3(h, 0, v)*10); // 向右指定一个10N的力
    
            rd.AddForce(new Vector3(h, 0, v));
    
            // 左右上下键的按下可设置,通过edit=>Project settings=>Input Manager
        }
    
    
        // 碰撞系统事件,unity引擎帮我们检测碰撞,当发生碰撞会调用这个方法,Collision collision:碰撞信息,可知撞到了谁
        //private void OnCollisionEnter(Collision collision) // 发生碰撞时执行一次
        //{
        //    //Debug.Log("发生碰撞了");
        //    // collision.collider.tag 通过碰撞组件获取被碰撞物体的标签。
        //    if (collision.gameObject.tag == "Food") { // 通过游戏物体获得标签
        //        Destroy(collision.gameObject);
        //    }
        //}
    
        //private void OnCollisionStay(Collision collision) // 正在接触一直执行
        //{
    
        //}
    
        //private void OnCollisionExit(Collision collision) // 碰撞离开时执行一次
        //{
    
        //}
    
        // 触发检测,当进入某个范围就触发
        private void OnTriggerEnter(Collider other) // 进入触发区域执行一次
        {
            if (other.tag == "Food") {
                score++;
                Destroy(other.gameObject);
                scoreText.text = "分数:" + score;
    
                if (score == 9) {
                    winText.SetActive(true);
                }
            }
            Debug.Log("进入");
        }
    
        //private void OnTriggerStay(Collider other) // 在触发区域中一直执行
        //{
            
        //}
    
        //private void OnTriggerExit(Collider other) // 离开出发区域执行一次
        //{
            
        //}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94

    食物:
    在这里插入图片描述

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class Food : MonoBehaviour
    {
        // Start is called before the first frame update
        void Start()
        {
            
        }
    
        // Update is called once per frame
        void Update() // Update方法大概一秒执行60次,一次旋转一度,相当于一秒旋转60度
        { 
            transform.Rotate(Vector3.up); // 设置食物的旋转角度,方向:up(向上),多少度:Vector3(一度)。让它围绕自身上方一度一度的旋转,  
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    相机跟随:
    在这里插入图片描述

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class FollowTarget : MonoBehaviour
    {
        // Start is called before the first frame update
    
        public Transform PlayerTransform;
        private Vector3 offset; // 在类中定义一个变量,类中的方法都可以使用这个变量。
        void Start()
        {
    
            // transform.position : 由于FollowTarget放在相机上,属于相机自己的组件,就直接用transform组件获取相机位置
            // Vector3 offset; 在方法中定义一个变量,只能在这个方法内部使用
            offset = transform.position - PlayerTransform.position;
            
        }
    
        // Update is called once per frame
        void Update()
        {
            transform.position = PlayerTransform.position + offset;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    定义一个text组件
    public Text scoreText;
    定义一个游戏物体,因为一会我们要控制游戏物体,目前胜利的游戏物体是禁用的。
    public GameObject winText;
    碰撞系统事件,unity引擎帮我们检测碰撞,当发生碰撞会调用这个方法,Collision collision:碰撞信息,可知撞到了谁。
    private void OnCollisionEnter(Collision collision) 发生碰撞时执行一次
    collision.collider.tag 通过碰撞组件获取被碰撞物体的标签。
    collision.gameObject.tag == “Food” 通过游戏物体获得标签
    OnTriggerEnter 触发检测,当进入某个范围就触发,进入触发区域执行一次
    transform.Rotate(Vector3.up); 设置食物的旋转角度,方向:up(向上),多少度:Vector3(一度)。让它围绕自身上方一度一度的旋转
    Update方法大概一秒执行60次,一次旋转一度,相当于一秒旋转60度。

    UnityAPI常用方法类与组件

    public class No1_PrintDebug : MonoBehaviour
    {
        void Start()
        {
            //1.测试
            Calculate();
            //2.检错
            Debug.Log("2+3的计算开始了");
            int a = 1;
            Debug.Log("a赋值完成,具体值是:"+a);
            int b = 3;
            Debug.Log("b赋值完成,具体值是:"+b);
            int num = a + b;
            Debug.Log("2+3="+num);
    
            Debug.LogWarning("这是一个警告!");
            Debug.LogError("这里有报错!");
        }
        
        private void Calculate()
        {
            //Debug.Log("计算");
            Add();
            Subtract();
        }
    
        private int Add()
        {
            //Debug.Log("加法");
            return 1 + 1;
        }
    
        private int Subtract()
        {
            //Debug.Log("减法");
            return 1 - 1;
        }
    }
    
    public class TestDebugAndPrintClass:MonoBehaviour
    { 
        public void TestPrint()
        {
            print("使用print必须让当前类继承自monobehavior");
        }
    
        public void TestDebug()
        {
            Debug.Log("使用debug再普通类里进行输出");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    生命周期函数

    功能说明:事件函数(生命周期函数),每个游戏物体上的同一钩子函数调用顺序不确定,但可以确定Start一定在Update前被调用,在Awake后执行这种顺序。

    public class No2_EventFunction : MonoBehaviour
    {
        public float attackValue=10000;
        public float currentHP;
    
        //对变量赋值的顺序(左边最先赋值,右边最后赋值,以此类推):
        //变量声明并直接赋值>检视面板赋值>Awake>OnEnable>Start>外部赋值
        //我们一般对一个对象赋值,或者说想要从外部对一个对象的属性或者成员变量的值
        //进行更改的前提是,这个对象已经有了(意味着start方法已经调用),所以外部赋值
        //会后于Start方法进行调用
    
        private void Reset()
        {
            //1.调用情况:此函数只能在编辑器模式下(不运行)调用。
            //2.调用时间,次数与作用
            //当脚本第一次挂载到对象或者使用了Reset命令之后调用,
            //来初始化脚本的各个属性,Reset最常用于在检视面板中提供良好的默认值。
    
            Debug.Log("调用了Reset方法");
            Debug.Log("攻击值重置为默认值");
        }
    
        private void Awake() // 游戏物体或者脚本第一次被激活调用一次
        {
            //1.调用情况
            //a.在加载场景时初始化包含脚本的激活状态的GameObject时
            //b.GameObject从非激活转变为激活状态
            //c.在初始化使用Instantiate创建的GameObject之后
            //2.调用时间,次数与作用
            //在脚本实例的生存期内,Unity 仅调用 Awake 一次。脚本的生存期持续到包含它的场景被卸载为止。
            //Unity 调用每个GameObject的Awake的顺序是不确定的,人为干涉(即设计)来保证程序的正确性和稳定性
            // Awake 来代替构造函数进行初始化,在Unity这里,组件的初始化不使用构造函数 
    
            Debug.Log("调用了Awake方法"); 
            attackValue = 1;
        }
    
           
        private void OnEnable()  //游戏物体或者脚本每次被激活都会调用一次
        {
            //1.调用情况
            //a.游戏物体被激活
            //b.脚本组件被激活
            //2.调用时间,次数与作用
            //重复赋值 变为初始状态
            //Debug.Log("调用了OnEnable方法");
    
            currentHP = 100;
            Debug.Log("当前血量为:"+currentHP);
            attackValue = 2;
        }
    
        void Start() //在脚本实例激活时在第一帧的Update前被调用,在Awake后执行,只在首次调用一次
        {
            //1.调用情况
            //a.游戏物体被激活
            //b.脚本组件被激活
            //2.调用作用
            //方便控制逻辑的前后调用顺序
    
            Debug.Log("调用了Start方法");
            attackValue = 3;
        }
    
        void Update() // 每帧调用,是最常用函数,每秒调用60次左右(根据当前电脑的的性能和状态)
        {
            //1.调用情况
            //a.游戏物体被激活
            //b.脚本组件被激活
            //2.调用作用:实时更新数据,接受输入数据
    
            Debug.Log("调用了Update方法");
        }
    
        private void LateUpdate()  //在调用所有Update函数后调用,每秒调用60次左右,安排脚本的执行顺序
        {
            //1.调用情况
            //a.游戏物体被激活
            //b.脚本组件被激活
            //2.调用作用: 比如摄像机跟随,一定是人物先移动了,摄像机才会跟随
    
            Debug.Log("调用了LateUpdate方法");
        }
    
        private void OnDisable() //满足调用情况时即时调用一次,
        {
            //1.调用情况
            //a.游戏物体被禁用
            //b.脚本组件被禁用
            //c.游戏物体被销毁
            //2.调用作用:用于一些对象的状态重置,资源回收与清理,OnDisable能做功能,基本上OnEnable也能做
    
            Debug.Log("调用了OnDisable方法");
        }
    
        void OnApplicatoinQuit()
        {
            //1.调用情况
            //a.在程序退出之前所有的游戏对象都会调用这个函数
            //b.在编辑器中会在用户终止播放模式时调用
            //c.在网页视图关闭时调用
            //2.调用时间,次数与作用
            //满足调用情况时即时调用一次,用于处理一些游戏退出后的逻辑
    
            Debug.Log("OnApplicationQuit");
        }
    
    
        void OnDestroy()
        {
            //1.调用情况
            //a.场景或游戏结束
            //b.停止播放模式将终止应用程序
            //c.在网页视图关闭时调用
            //d.当前脚本被移除
            //e.当前脚本挂载到的游戏物体被删除
            //2.调用时间,次数与作用
            //满足调用情况时即时调用一次,用于一些游戏物体的销毁
            
            Debug.Log("OnDestroy");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122

    功能说明:用于测试外部调用或者外部复制时的顺序

    public class No2_ExternalCall : MonoBehaviour
    {
        public No2_EventFunction api;  
        // 将ExternalCall挂载到和EventFunction相同的游戏物体上,再将EventFunction的C#脚本拖拽赋值到api引用上。
        // 这样就能在ExternalCall中使用EventFunction中的方法和变量
    
        void Start()
        {
            //通过外部获取组件引用对变量进行赋值
            api.attackValue = -1;
        }
    
        void Update()
        {
    
        } 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    创建游戏物体的3种方式

            //a.使用构造函数(声明+实例化) 创建一个空的游戏对象,MyGameObject:游戏物体名称
            GameObject myGo = new GameObject("MyGameObject");
    
            //b.根据现有的预制体(游戏物体)资源或者游戏场景已有的游戏物体来实例化(克隆)
            GameObject.Instantiate(grisGo); // 简写:Instantiate(grisGo)
    
            //c.使用特别的API创建一些基本的游戏物体类型(原始几何体) PrimitiveType上有许多几何体的类型包括球体、胶囊体、圆柱体等等
            GameObject.CreatePrimitive(PrimitiveType.Plane);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    游戏物体的查找和获取(怎样调用自身游戏物体与其他游戏物体的方法与属性)

    public class No3_GameObject : MonoBehaviour
    {
        public GameObject grisGo; // 已将「grisGo游戏物体」拖拽赋值到「grisGo游戏变量」
    
        void Start()
        {
            //1.创建游戏物体的3种方式
            //a.使用构造函数(声明+实例化) 创建一个空的游戏对象,MyGameObject:游戏物体名称
            GameObject myGo = new GameObject("MyGameObject");
    
            //b.根据现有的预制体(游戏物体)资源或者游戏场景已有的游戏物体来实例化(克隆)
            GameObject.Instantiate(grisGo); // 简写:Instantiate(grisGo)
    
            //c.使用特别的API创建一些基本的游戏物体类型(原始几何体) PrimitiveType上有许多几何体的类型包括球体、胶囊体、圆柱体等等
            GameObject.CreatePrimitive(PrimitiveType.Plane);
    
            //2.游戏物体的查找和获取
            //this;//当前组件No3_GameObject
       
            // Test();this.Test();
            Debug.Log("挂载这个脚本的游戏物体:"+this.gameObject); // this 可以省略
            Debug.Log("当前脚本挂载到的游戏物体名称是:"+gameObject.name);
            Debug.Log("当前游戏物体标签是:"+gameObject.tag);
            Debug.Log("当前游戏物体层级是:"+gameObject.layer);
            Debug.Log("当前游戏物体的状态是:"+gameObject.activeInHierarchy); // 物体状态是否为激活:true 或 false
            Debug.Log("当前游戏物体的状态是:" +gameObject.activeSelf);
            Debug.Log("gris游戏物体的状态是:"+ grisGo.activeSelf);
    
            // 静态方法:
            //GameObject.Instantiate; // 克隆
            //GameObject.CreatePrimitive; // 创建几何体
            gameObject.SetActive(true); // 游戏物体的激活
            gameObject.SetActive(true); // 游戏物体的失活
    
            //有引用
            //对自己 this.gameObject
            //对其他游戏物体 有直接引用
            Debug.Log("grisGo游戏物体的状态:", grisGo.activeSelf);
    
            //对其他游戏物体,没有直接引用(4种查找方式)
            //对其他游戏物体查找(这时游戏物体必须是激活状态)
            // a.通过名称查找
            GameObject mainCameraGo= GameObject.Find("Main Camera");
            Debug.Log("mainCamera游戏物体的标签是:" + mainCameraGo.tag);
    
            //b.通过标签查找
            GameObject mainCameraGo = GameObject.FindGameObjectWithTag("MainCamera");
            Debug.Log("mainCamera游戏物体的名字是:" + mainCameraGo.name);
    
            //c.通过类型查找
            No2_EventFunction no2_EventFunction= GameObject.FindObjectOfType<No2_EventFunction>();
            Debug.Log("no2_EventFunction游戏物体的名字是:" + no2_EventFunction.name);
    
            //d.多数查找与获取
            GameObject[] enemyGos= GameObject.FindGameObjectsWithTag("Enemy"); // 定义一个游戏物体数组enemyGos,接收标签为Enemy的游戏物体
            for (int i = 0; i < enemyGos.Length; i++)
            {
                Debug.Log("查找到的敌人游戏物体名称是:"+enemyGos[i].name);
            }
    
            //e.通过组件查找游戏物体
            BoxCollider[] colliders= GameObject.FindObjectsOfType<BoxCollider>(); // 查找拥有BoxCollider组件的游戏物体。
            for (int i = 0; i < colliders.Length; i++)
            {
                Debug.Log("查找到的敌人游戏物体名称是:" + colliders[i].name);
            }
        }
    
        void Update()
        {
    
        }
    
        private void Test() { }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    GameObject.FindObjectsOfType(); // 查找拥有BoxCollider组件的游戏物体。
    为游戏物体添加名为的BoxCollider组件:
    在这里插入图片描述

    MonoBehaviour(子类),派生自Behaviour类,Behaviour类派生自组件脚本Component(基类)

    public class No4_MonoBehaviour : MonoBehaviour // 某个类、类型或组件需要挂载到游戏身上的话一定要继承自MonoBehaviour
    {
        void Start()
        {
            //MonoBehaviour派生自组件脚本,因此组件脚本所有的公有,保护的属性,成员变量
            //方法等功能,MonoBehaviour也都有,继承mono之后这类可以挂载到游戏物体上   
            Debug.Log("No4_MonoBehaviour组件的激活状态是:"+this.enabled);
            Debug.Log("No4_MonoBehaviour组件挂载的对象名称是:" + this.name);
            Debug.Log("No4_MonoBehaviour组件挂载的标签名称是:" + this.tag);
            Debug.Log("No4_MonoBehaviour组件是否已激活并启用Behaviour:" + this.isActiveAndEnabled);
    
             // 以下四个方法都是 MonoBehaviour 类中的方法
            // print("1")
            // Destroy();
            // FindObjectsOfType();
            // Instantiate();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    组件的获取与使用(2种方法)

    public class No5_Component : MonoBehaviour
    {
        public int testValue;
    
        public GameObject enemyGos; // 定义游戏物体 名为enemyGos,再在unity上拖拽 enemy游戏物体,赋值到enemyGos上下面的GetComponentInChildren才能找到
    
        void Start()
        {
            //Mono继承自Behaviour,Behaviour继承自Compontent,Compontent继承自Object
            //子辈拥有父辈以及父辈以上(派生程度低的基类)所有的公有,保护的属性,成员变量
            //方法等功能,挂载功能其实是Component,也就是我们写的脚本组件其实指的是Component组件
            //而Mono是在此基础上进行的封装与扩展
    
            //a.组件都是在某一个游戏物体身上挂载的,可以通过游戏物体查找获取之后使用
            No5_Component no5_Component = gameObject.GetComponent<No5_Component>(); // 获取自己身上的No5_Component组件(就是当前的c#文件)赋值给新创建No5_Component组件变量
            Debug.Log(no5_Component.testValue);// 获取自身组件上的testValue属性
            
            //No2_EventFunction no2_EventFunction = gameObject.GetComponent();  // 不能直接获取不挂载在自身游戏物体上的组件
            //Debug.Log(no2_EventFunction); 为空
            //Debug.Log(no2_EventFunction.attackValue); 报错
    
            // 获取其他游戏物体
            GameObject grisGo = GameObject.Find("Gris"); 
            Debug.Log(grisGo.GetComponent<SpriteRenderer>());
            Debug.Log(enemyGos.GetComponentInChildren<BoxCollider>()); // 获取满足条件的第一个游戏物体的BoxCollider组件
            Debug.Log(enemyGos.GetComponentsInChildren<BoxCollider>()); // 获得满足条件的所有游戏物体的BoxCollider组件,数组
            Debug.Log(enemyGos.GetComponentInParent<BoxCollider>()); // 获取enemyGos游戏物体父级游戏物体上的BoxCollider组件
            
            //b.通过其他组件查找
            SpriteRenderer sr= grisGo.GetComponent<SpriteRenderer>();
            sr.GetComponent<Transform>(); // 从SpriteRenderer组件上获取Transform组件
            // this.GetComponent();  // 这也可以
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    在这里插入图片描述
    在这里插入图片描述

    变换组件Transform

    场景中的每个对象都有一个变换组件。 它用于存储和操作对象的位置、旋转和缩放。

    public class No6_Transform : MonoBehaviour
    {
        public GameObject grisGo;
    
        public float moveSpeed=1;
    
        void Start()
        {
            //1.访问与获取
            Debug.Log(this.transform); // 当前物体上的transform组件
            Debug.Log(grisGo.transform);
            Transform grisTrans = grisGo.transform; // 获取grisGo物体上的transform组件,赋值给grisTrans变量
    
            //2.成员变量
            Debug.Log("Gris变换组件所挂载的游戏物体名字是:"+grisTrans.name);
            Debug.Log("Gris变换组件所挂载的游戏物体引用是:"+grisTrans.gameObject);
            Debug.Log("Gris下的子对象(指Transform)的个数是:"+grisTrans.childCount);
            Debug.Log("Gris世界空间中的坐标位置是:"+grisTrans.position);
            Debug.Log("Gris以四元数形式表示的旋转是:"+grisTrans.rotation);
            Debug.Log("Gris以欧拉角形式表示的旋转(以度数为单位)是"+grisTrans.eulerAngles);
            Debug.Log("Gris的父级Transform是:"+grisTrans.parent);
            Debug.Log("Gris相对于父对象的位置坐标是:"+grisTrans.localPosition);
            Debug.Log("Gris相对于父对象以四元数形式表示的旋转是:" + grisTrans.localRotation);
            Debug.Log("Gris相对于父对象以欧拉角形式表示的旋转(以度数为单位)是:" + grisTrans.localEulerAngles);
            Debug.Log("Gris相对于父对象的变换缩放是:"+grisTrans.localScale);
            Debug.Log("Gris的自身坐标正前方(Z轴正方向)是:"+grisTrans.forward);
            Debug.Log("Gris的自身坐标正右方(X轴正方向)是:" + grisTrans.right);
            Debug.Log("Gris的自身坐标正上方(Y轴正方向)是:" + grisTrans.up);
            
            //共有方法
            //3.查找
            Debug.Log("当前脚本挂载的游戏对象下的叫Gris的子对象身上的Transform组件是:"+transform.Find("Gris"));
            Debug.Log("当前脚本挂载的游戏对象下的第一个(0号索引)子对象的Transform引用是:"+transform.GetChild(0));
            Debug.Log("Gris在当前父对象里的索引位置:"+ grisTrans.GetSiblingIndex()); // 1
    
            //静态方法
            //Transform.Destroy(grisTrans); // 销毁grisTrans组件,一般不这么做
            //Transform.Destroy(grisTrans.gameObject); // 销毁grisTrans组件对应的游戏物体
            //Transform.FindObjectOfType();
            //Transform.Instantiate();
        }
    
        void Update()
        {
            //移动
            //0.第二个参数不填(实际情况按自身坐标系移动,space.self)
            //grisGo.transform.Translate(Vector2.left*moveSpeed);//自身坐标系
            //grisGo.transform.Translate(-grisGo.transform.right*moveSpeed);//世界坐标系
            //1.第一个参数按世界坐标系移动,第二个参数指定世界坐标系(实际情况按世界坐标系移动)
            //grisGo.transform.Translate(Vector2.left*moveSpeed,Space.World);
            //2.第一个参数按世界坐标系移动,第二个参数指定自身坐标系(实际情况按自身坐标系移动)
            //grisGo.transform.Translate(Vector2.left * moveSpeed, Space.Self);
            //3.第一个参数按自身坐标系移动,第二个参数指定世界坐标系(实际情况按自身坐标系移动)
            //grisGo.transform.Translate(-grisGo.transform.right * moveSpeed, Space.World);
            //4.第一个参数按自身坐标系移动,第二个参数指定自身坐标系(实际情况按世界坐标系移动)(一般不使用)
            //grisGo.transform.Translate(-grisGo.transform.right * moveSpeed, Space.Self);
            //旋转
            //grisGo.transform.Rotate(new Vector3(0,0,1));
            grisGo.transform.Rotate(Vector3.forward,1);
        } 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    Vector2(表示2D向量和点)

    public class No7_Vector2 : MonoBehaviour
    {
        public Transform grisTrans;
        public Transform targetTrans;
        public float percent; // 插值百分比
        public float lerpSpeed = 0.01; // 当前插值速度
        Vector2 currentVelocity = new Vector2(1, 0);
    
        //结构体 值类型:复制修改不影响原来的值
        public struct MyStruct
        {
            public string name;
            public int age;
        }
        
        //类 引用类型:复制修改影响原来的值
        public class MyClass
        {
            public string name;
            public int age;
        }
    
        void Start()
        {
            静态变量
            print(Vector2.down); // 向下的方向 (0,-1)
            print(Vector2.up);//Y轴正方向 (0,1)
            print(Vector2.left); // (-1,0)
            print(Vector2.right);//X轴正方向(1,0)
            print(Vector2.one); // 单位化一个向量(1,1)
            print(Vector2.zero); // (0,0)
    
            //构造函数
            Vector2 v2 = new Vector2(2, 2);
            print("V2向量是:" + v2); // (2,2)
    
            //成员变量
            print("V2向量的模长是:" + v2.magnitude); // (x平方+y平方)开根号
            print("V2向量的模长的平方是:" + v2.sqrMagnitude);
            print("V2向量单位化之后是:" + v2.normalized); // 转化为长度为1的向量(不改变v2原来的值)的模长相加 根号2/2 => (0.7, 0.7)
            print("V2向量的X、Y值分别是:" + v2.x + "," + v2.y); // 2  2
            print("V2向量的X、Y值分别是(使用索引器形式访问):" + v2[0] + "," + v2[1]); // v2[0]为x, v2[1]为y,结果: 2  2
            
            //公共函数
            bool equal = v2.Equals(new Vector2(1, 1)); 
            print("V2向量与向量(1,1)是否相等?" + equal); // false
    
            Vector2 v2E = new Vector2(1, 3);
            bool equalv2E = v2E.Equals(new Vector2(3, 1));
            print("v2E向量与向量(3,1)是否相等?" + equal); // false
            print("V2向量的单位化向量是:" + v2.normalized + "但是V2向量的值还是:" + v2); // V2向量的单位化向量是(0.7, 0.7)  但是V2向量的值还是(2,2)
            v2.Normalize(); // 调用方法改变原始值
            print("V2向量是:" + v2); // (0.7, 0.7) 
            v2.Set(5, 9); // 设置v2向量的值
            print("V2向量是:" + v2); // (5, 9)
            transform.position = v2;
    
            transform.position.x = 4; //不可以单独赋值某一个值,比如x,但可以整体赋值
            //结论1:用属性和方法返回的结构体是不能修改其字段的 
    
            MyStruct myStruct = new MyStruct();//A 结构体
            myStruct.name = "wuky";
            myStruct.age = 100;
            结论2:直接访问公有的结构体是可以修改其字段的
    
            MyStruct yourStruct = myStruct;// A与B不是同一块内存空间,拷贝修改不影响原值
            yourStruct.name = "小可爱";
            yourStruct.age = 18;
            print("原本的结构体对象名字是:" + myStruct.name); // wuky
            print("修改后的结构体对象名字是:" + yourStruct.name); // 小可爱
    
            MyClass myClass = new MyClass(); //A  类
            myClass.name = "wuky8";
            myClass.age = 100;
            MyClass yourClass = myClass;//B跟A是同一块内存空间,引用,拷贝修改影响原值
            yourClass.name = "小阔爱";
            yourClass.age = 18;
            print("原本的结构体对象名字是:" + myClass.name); // 小阔爱
            print("修改后的结构体对象名字是:" + yourClass.name); // 小阔爱
    
            //总结导致这个问题的原因:
            //1,Transform中的position是属性(换成方法也一样,因为属性的实现本质上还是方法)而不是公有字段
            //2,position的类型是Vector的,而Vector是Struct类型
            //3,Struct之间的赋值是拷贝而不是引用
    
            修改位置(重点)
            transform.position = new Vector2(3, 3); // 不可以单独赋值某一个值,比如单独给x或y赋值,但可以整体赋值
            Vector2 vector2 = transform.position; // 将position赋值给Vector2类型的变量
            vector2.x = 2; // 就可以单独修改它的值
            transform.position = vector2;
    
            静态函数(方法),计算夹角,但无正负之分,只考虑正值,计算出的是偏小的夹角(原则上有两个角)
            Vector2 va = new Vector2(1, 0);
            Vector2 vb = new Vector2(0, 1);
            Debug.Log("从va指向vb方向计算的无符号夹角是:" + Vector2.Angle(va, vb)); // 90(度)
            print("va点与vb点之间的距离是:" + Vector2.Distance(va, vb));// 根号2
            print("向量va与向量vb的点积是:" + Vector2.Dot(va, vb));
            print("向量va和向量vb在各个方向上的「最大分量」组成的新向量是:" + Vector2.Max(va, vb)); // (1, 1)
            print("向量va和向量vb在各个方向上的「最小分量」组成的新向量是:" + Vector2.Min(va, vb)); // (0, 0)
            
            //具体得到的新向量的结果的计算公式是:a+(b-a)*t,t:插值比例
            print("va向vb按照0.5的比例进行线性插值变化之后的结果是" + Vector2.Lerp(va, vb, 0.5f));
            print("va向vb按照参数为-1的形式进行(无限制)线性插值变化之后的结果是" + Vector2.LerpUnclamped(va, vb, -1)); // (2,-1)
            //float maxDistance = 0.5f;
            print("将点va以最大距离不超过maxDistance为移动步频移向vb" + Vector2.MoveTowards(va, vb, maxDistance));
            print("va和vb之间的有符号角度(以度为单位,逆时针为正)是" + Vector2.SignedAngle(va, vb));
            print("vb和va之间的有符号角度(以度为单位,逆时针为正)是" + Vector2.SignedAngle(vb, va));
            print("va和vb在各个方向上的分量相乘得到的新向量是:" + Vector2.Scale(va, vb));
            Vector2 currentVelocity = new Vector2(1, 0);
            print(Vector2.SmoothDamp(va, vb, ref currentVelocity, 0.1f)); // 向量a往b向量平滑转化,currentVelocity:当前插值速度,0.1f:平滑时间
    
            运算符
            print("va加上vb向量是:" + (va + vb));
            print("va减去vb向量是:" + (va - vb));
            print("" + va * 10);
            print("va与vb是同一个向量吗" + (va == vb));
        }
    
        void Update()
        {
            grisTrans.position = Vector2.Lerp(grisTrans.position,targetTrans.position,0.01f); // 每次都会差值前一帧的0.01,所以移动不是匀速也是加速
            percent += 1 * lerpSpeed * Time.deltaTime; //Time.deltaTime:以每秒为单位进行插值
            grisTrans.position = Vector2.Lerp(grisTrans.position, targetTrans.position, percent);
    
            //lerp是先快后慢,moveTowards匀速
            grisTrans.position = Vector2.MoveTowards(grisTrans.position, targetTrans.position, 0.05f);
    
            //平滑阻尼       
            grisTrans.position = Vector2.SmoothDamp(grisTrans.position,targetTrans.position,ref currentVelocity,1); // ref 参数一定要带上ref关键字
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131

    最大分量组成的新向量:
    在这里插入图片描述
    线性插值:
    在这里插入图片描述
    (无限制)线性插值:
    在这里插入图片描述

    访问输入系统的接口类Input

    public class No8_Input : MonoBehaviour
    {
        void Start()
        {
    
        }
    
        void Update()
        {
            连续检测(移动)
            print("当前玩家输入的水平方向的轴值是:"+Input.GetAxis("Horizontal")); // -1到0范围的值,渐变
            print("当前玩家输入的垂直方向的轴值是:" + Input.GetAxis("Vertical"));
            print("当前玩家输入的水平方向的边界轴值是:" + Input.GetAxisRaw("Horizontal")); // 得到0,1,-1中的值。没有渐变过程
            print("当前玩家输入的垂直方向的边界轴值是:" + Input.GetAxisRaw("Vertical"));
            print("当前玩家鼠标水平移动增量是:"+Input.GetAxis("Mouse X")); // 鼠标滑动距离,正值:右、下,负值:左、上
            print("当前玩家鼠标垂直移动增量是:" + Input.GetAxis("Mouse Y"));
    
            //连续检测(事件)
            if (Input.GetButton("Fire1"))
            {
                print("当前玩家正在使用武器1进行攻击!");
            }
            if (Input.GetButton("Fire2"))
            {
                print("当前玩家正在使用武器2进行攻击!");
            }
            if (Input.GetButton("RecoverSkill"))
            {
                print("当前玩家使用了恢复技能回血!");
            }
            
            //间隔检测(事件)
            if (Input.GetButtonDown("Jump"))
            {
                print("当前玩家按下跳跃键");
            }
            if (Input.GetButtonUp("Squat"))
            {
                print("当前玩家松开蹲下建");
            }
            if (Input.GetKeyDown(KeyCode.Q))
            {
                print("当前玩家按下Q键");
            }
            if (Input.anyKeyDown)
            {
                print("当前玩家按下了任意一个按键,游戏开始");
            }
            if (Input.GetMouseButton(0))
            {
                print("当前玩家按住鼠标左键");
            }
            if (Input.GetMouseButtonDown(1))
            {
                print("当前玩家按下鼠标右键");
            }
            if (Input.GetMouseButtonUp(2))
            {
                print("当前玩家抬起鼠标中键(从按下状态松开滚轮)");
            }
        } 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    给其他组件传送消息

    public class No9_Message : MonoBehaviour
    {
        void Start()
        {
            //仅发送消息给自己(以及自身身上的其他MonoBehaviour对象)
            gameObject.SendMessage("GetMsg"); // 相当于调用自身类上的GetMsg方法,因为No9_MessageChild脚本也挂载到了当前游戏物体身上,所以它的GetMsg方法这里也能调用。
    
            SendMessage("GetSrcMsg","wuky"); // 
            SendMessage("GetTestMsg",SendMessageOptions.DontRequireReceiver); // 加上SendMessageOptions参数,当前物体上没有GetTestMsg方法也不会报错
    
            //广播消息
            //(向下发,所有子对象包括自己)
            BroadcastMessage("GetMsg");
            //向上发送消息(父对象包含自己)
            SendMessageUpwards("GetMsg");
        }
    
        void Update()
        {
    
        }
    
        public void GetMsg()
        {
            print("测试对象本身接收到消息了");
        }
    
        public void GetSrcMsg(string str)
        {
            print("测试对象本身接收到的消息为:"+str); // 测试对象本身接收到的消息为:wuky
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    public class No9_MessageChild : MonoBehaviour
    {
        public void GetMsg()
        {
            print("测试对象的子对象接收到消息了");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    public class No9_MessageParent : MonoBehaviour
    {
        public void GetMsg()
        {
            print("测试对象的父对象接收到消息了");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    public class No9_MessageParent : MonoBehaviour
    {
        public void GetMsg()
        {
            print("测试对象的父对象接收到消息了");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    public class No9_MessageTest : MonoBehaviour
    {
        public void GetMsg()
        {
            print("测试对象身上的其他组件接收到消息了");
        }
    
        public void GetSrcMsg(string str)
        {
            print("测试对象身上的其他组件接收到的消息为:" + str);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    UI部分

    在这里插入图片描述

    创建新的场景,创建后保存到Assets中
    在这里插入图片描述
    为场景添加背景图片:
    在这里插入图片描述
    在这里插入图片描述

    注意:需要按住option再选择
    在这里插入图片描述
    通常先让图片保持原本大小,再按住shift等比例缩放
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    直接拖凭感觉那么位置不精准,就要直接设置坐标
    在这里插入图片描述
    为图片添加文字:
    在这里插入图片描述
    在这里插入图片描述
    注意:这里按住option与shift选择锚点的效果是不一样的,option类似于设置图片具体位置,或是填充。shift是设置锚点位置,当背景整体移动时他也能跟随移动,而不是保持在原位置。
    在这里插入图片描述
    为图片添加slider组件,让其滑动。图片能修改颜色,同一张图片能搭建出许多效果

    在这里插入图片描述
    文字很清晰:
    在这里插入图片描述
    复制一张图片成为遮罩:在这里插入图片描述

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class SkillItem : MonoBehaviour
    {
    
        public float coldTime = 2; // 总冷却时间
        public float time = 0;// 计时器
        private bool isColding = false; // 是否处于冷却期间
        private Image coldMask;   // option + 回车  引入Image所在的命名空间:UnityEngine.UI
    
        // Start is called before the first frame update
        void Start()
        {
            //coldMask = transform.Find("coldMask"); // 通过名字查找子物体
            coldMask = transform.Find("ColdMask").GetComponent<Image>(); // 查找子物体后获取它身上的Image组件
        }
    
        // Update is called once per frame
        void Update()
        {
            if (isColding)
            {
                time += Time.deltaTime;
                coldMask.fillAmount = (coldTime - time) / coldTime;
            }
            if (time > coldTime) {
                isColding = false;
                coldMask.fillAmount = 0;
                time = 0;
            }
          
        }
    
        public void OnSkillClick() {
            if (isColding == false) {
                isColding = true;
                time = 0;
                coldMask.fillAmount = 1;
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    为文字添加边框效果:在这里插入图片描述
    为物体创建脚本处理技能冷却效果:
    在这里插入图片描述
    将类在编辑器中打开:
    在这里插入图片描述

    在物体上绑定点击事件,指定点击事件调用的具体方法。
    在这里插入图片描述

    释放技能代码:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class SkillItem2 : MonoBehaviour
    {
        private Image coldMask;
        private bool isCold = false;
        public float coldTime = 2;
        public float time = 0;
        public KeyCode KeyCode = KeyCode.Alpha1;
    
        // Start is called before the first frame update
        void Start()
        {
            coldMask = transform.Find("ColdMask").GetComponent<Image>();
        }
    
        // Update is called once per frame
        void Update()
        {
            if (isCold == true) {
                time += Time.deltaTime;
                coldMask.fillAmount = (coldTime - time) / coldTime;
            }
    
            if (time > coldTime) {
                isCold = false;
                time = 0;
                coldMask.fillAmount = 0;
            }
    
            //if (Input.GetKeyDown(KeyCode.Alpha1)) // Input:监测按键事件,KeyCode.Alpha1:按下数字键1,KeyCode.A按下字母键A
            if(Input.GetKeyDown(KeyCode)) // 这样就能在属性面板上修改具体按键了
            {   
                ReleaseSkill();
            }
        }
    
        public void OnSkillClick() { // 挂载到button的click事件上,监测点击事件
            ReleaseSkill();
        }
    
        public void ReleaseSkill() { // 做成公共方法
            if (isCold == false)
            {
                isCold = true;
                time = 0;
                coldMask.fillAmount = 1;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    给图片设置边框,防止边框变糊:
    在这里插入图片描述
    在这里插入图片描述
    (蝴蝶结)就是锚点
    在这里插入图片描述
    Toggle组件:为图片添加选中与没选中效果。

    为图片添加单选效果,注意这里是为父物体添加Toggle Group组件,且要将它拖拽到每个子物体的Group中,让他们成为一组单选。
    在这里插入图片描述
    网格组件,可以为每一项网格设置父空物体来控制网格的每一项处于正中心:
    在这里插入图片描述
    为网格添加滑动效果:
    这里注意需要先在同级目录下创建一个image组件,调整宽高确定“显示”区域,再添加Scroll Rect 、Mask组件,最后把LevelGrid拖拽到Image组件下。
    在这里插入图片描述

    创建预制体

    在这里插入图片描述
    使用预制体前需要断开连接:
    在这里插入图片描述

    为事件绑定方法:
    在这里插入图片描述
    代码实现接口:这连个接口不需要挂载,脚本绑定到相应的物体上自动触发。
    在这里插入图片描述
    定义组件方法:
    在这里插入图片描述
    表格滚动设置滚动到那一页:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.EventSystems;
    using UnityEngine.UI;
    
    public class LevelScroll : MonoBehaviour,IBeginDragHandler,IEndDragHandler
    {
        private ScrollRect scroll; // 定义组件
        public float[] pagePosition = new float[] { 0, 0.333f, 0.666f, 1 };
        public Toggle[] toggleArray;
    
        // Start is called before the first frame update
        void Start()
        {
            scroll = GetComponent<ScrollRect>(); // 获取组件
        }
    
        // Update is called once per frame
        void Update()
        {
            
        }
    
        public void OnBeginDrag(PointerEventData eventData)
        {
            throw new System.NotImplementedException();
        }
    
        public void OnEndDrag(PointerEventData eventData) // 结束拖拽事件
        {
            float currentPosition = scroll.horizontalNormalizedPosition;
            int index = 0;
            float offset = currentPosition - pagePosition[0];
            for (int i = 1; i < 4; i++)
            {
                if (Mathf.Abs(currentPosition - pagePosition[i]) < offset)
                {
                    index = i;
                    offset = Mathf.Abs(currentPosition - pagePosition[i]);
                }
            }
            scroll.horizontalNormalizedPosition = pagePosition[index];
            toggleArray[index].isOn = true;
        }
    
        public void moveToPage1(bool isOn) {
            if (isOn) {
                scroll.horizontalNormalizedPosition = pagePosition[0];
            }
        }
    
        public void moveToPage2(bool isOn)
        {
            if (isOn)
            {
                scroll.horizontalNormalizedPosition = pagePosition[1];
            }
        }
    
        public void moveToPage3(bool isOn)
        {
            if (isOn)
            {
                scroll.horizontalNormalizedPosition = pagePosition[2];
            }
        }
    
        public void moveToPage4(bool isOn)
        {
            if (isOn)
            {
                scroll.horizontalNormalizedPosition = pagePosition[3];
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    脚本关联Toggle组件的点击事件:
    在这里插入图片描述

    Slider滑动组件:
    在这里插入图片描述
    在这里插入图片描述
    public GameObject offObject; // 游戏物体的获取直接在这里定义,然后在面板上通过拖拽游戏物体赋值,所以它们一般是public
    public Toggle toggle; // 获取游戏身上的组件必须要引入UnityEngine.UI,在Start方法中通过GetComponent获取。

    void Start()
    {
        toggle = GetComponent(); // 获取到游戏物体上的Toggle组件
        OnValueChange(toggle.isOn); // 获取组件上的属性
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class MyToggle : MonoBehaviour
    {
        public GameObject offObject; // 游戏物体的获取直接在这里定义,然后在面板上通过拖拽游戏物体赋值,所以它们一般是public
        public GameObject onObject;
        public Toggle toggle; // 获取游戏身上的组件必须要引入UnityEngine.UI,在Start方法中通过GetComponent获取。
    
        // Start is called before the first frame update
        void Start()
        {
            toggle = GetComponent<Toggle>(); // 获取到游戏物体上的Toggle组件
            OnValueChange(toggle.isOn); // 获取组件上的属性
        }
    
        // Update is called once per frame
        void Update()
        {
            
        }
    
       public void OnValueChange(bool isOn) {
            onObject.SetActive(!isOn);
            offObject.SetActive(isOn);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    在这里插入图片描述

    常用事件

    1、当脚本和需要找的组件在同一个物体上:

    public class EditMessage : MonoBehaviour
    {
        Light light;
        
        void Start()
        {
            light = GetComponent<Light>(); // 本物体可以这么找
            light.color = Color.green;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2、找到其他物体身上的组件:使用public,直接将其他物体上的组件拖拽赋值。

    public class EditMessage : MonoBehaviour
    {
        public Light lightName;
    
        void Start()
        {
            lightName.color = Color.green;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3、不使用拖拽赋值,找到其他物体身上的组件:先找到组件所在的游戏物体,通过游戏物体再找到组件。

    public class EditMessage : MonoBehaviour
    {
        GameObject FindObject; // 定义一个空的游戏物体
        Light lightName;
    
        void Start()
        {
            // GameObject.Find将Hierarchy窗口的所有物体遍历一遍找到第一个符合条件的物体为止,所以不管目标物体所在层级嵌套多复杂也没事。
            FindObject = GameObject.Find("Light"); // 找到目标游戏物体,赋值到空的游戏物体上,Light:游戏物体的名字
            lightName = FindObject.GetComponent<Light>(); // 在目标物体上找到对应的组件
            lightName.color = Color.green;
    		
    		// 如果想找到其它同名的游戏物体,就把路径加上
    		FindObject = GameObject.Find("1(1)/2/3/Light"); 
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    天空盒

    到网上下载天空盒照片,修改图片的Texture Shape为cube
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    天空盒反射

    选择固定颜色(color),可调节环境光的颜色
    在这里插入图片描述
    新建材质:
    在这里插入图片描述
    给物体赋予材质
    在这里插入图片描述
    材质颜色,光滑程度:
    在这里插入图片描述
    环境光反射:
    在这里插入图片描述
    Lighting各个属性介绍,在觉得场景较暗的情况下,增强间接光照的强度(Indirect Multiplier),整个场景也会变亮。
    在这里插入图片描述
    修改线性空间:
    在这里插入图片描述
    在这里插入图片描述
    如果场景中物体没有阴影
    情况一:Shadows勾选为Disable shadows,修改它
    情况
    情况二:模型的Cast Shadows被设置成了Off,改为On
    在这里插入图片描述
    在这里插入图片描述
    情况三:如果其它物体遮挡在自己身上,却没有产生遮挡的阴影,那有可能是模型的Shader没有选择Standard。
    在这里插入图片描述
    Light Mode:
    在这里插入图片描述
    他们之前选择谁要取决于项目的性能与后期的硬件考虑,如果是在手机平台收到内存与效能的限制, baked GI 耗能更小,就会选择baked GI。在PC端,为了去营造更好的游戏效果,就会选择Realtime GI。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    使用代码控制Shadowmask Mode,制作碰撞盒,当物体进入一定范围再开启遮挡阴影(将它改为Distance Shadowmask):

    在这里插入图片描述
    Lighting的Scene中各个参数详解:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    如果场景中某个物体烘焙得太慢了就调节下Scale In Lightmap,但会损失一些细节。在这里插入图片描述
    掉光照情况:
    在这里插入图片描述

    灯光探针:
    当Quality的Shadowmask Mode 不是Distance Shadowmask(节约性能),并且Lighting Mode 是shadowmask时,当动态物体被静态物体遮蔽,不会产生遮蔽的阴影。灯光探针能修补这个情况。
    1、给场景添加灯光探针:
    在这里插入图片描述
    在这里插入图片描述
    选中探针小球:
    在这里插入图片描述
    反射探针:一般应用于具体的室内效果,准确反射室内效果对象,对周围效果进行取样,从光照探针的位置把周围物体拍下来,拍成一个cube map,就像天空盒一样,但凡有反射功能的物体就会受到cube map的影响,去正确的反射周围的环境,需要反射的物体要设置为静态的。

    调节摄像机拍摄深度:
    在这里插入图片描述
    自发光物体:
    在这里插入图片描述
    在这里插入图片描述
    这里调高了间接光的精度后如果烘焙时间太长了,就可以将Lightmap Size调成512,加快烘焙

    AO:
    在这里插入图片描述

    Unity中的坐标系

    世界坐标系(transform.position)

    子物体的世界坐标会跟随父物体位置改变

    局部坐标系(transform.localPosition)

    在这里插入图片描述

    屏幕坐标

    Screen.width 与 Screen.height
    在这里插入图片描述
    在这里插入图片描述

    鼠标坐标

    鼠标移到屏幕右上角,鼠标位置的x、y就是屏幕的宽高

    视口坐标

    camera_.ScreenToViewportPoint(Input.mousePosition) // 鼠标坐标的归一化。在这里插入图片描述
    在这里插入图片描述

    UI坐标

    TODO

    屏幕坐标转世界坐标

     public class Player : MonoBehaviour
    {
        public Camera camera_; 
        private void OnGUI(){ // 鼠标一移动就刷新
            GUI.contentColor = Color.black;
            GUI.Label(new Rect(10, 10, 200, 20), "世界坐标" + transform.position); // new Rect(位置,宽高)
            GUI.Label(new Rect(10, 30, 200, 20), "局部坐标" + transform.localPosition);
            GUI.Label(new Rect(10, 50, 200, 20), "屏幕宽高" + Screen.width + "*" + Screen.height);
            GUI.Label(new Rect(10, 70, 200, 20), "鼠标位置" + Input.mousePosition);
            GUI.Label(new Rect(10, 90, 300, 20), "鼠标位置(视口坐标)" + camera_.ScreenToViewportPoint(Input.mousePosition));
            
            // 单纯这样写的话得到的是一个固定值(不会跟随鼠标移动而改变),因为屏幕坐标是二维只有x与y,缺z,但世界坐标是三维
            GUI.Label(new Rect(10, 110, 300, 20), "屏幕转世界,转换后:" + camera_.ScreenToWorldPoint(Input.mousePosition)); 
            
            // 传入鼠标屏幕坐标
            GUI.Label(new Rect(10, 130, 300, 20), "屏幕转世界,转换后:" + ToWorldPoint(Input.mousePosition));  
        }
    
        Vector3 ToWorldPoint(Vector3 sPos){
            Vector3 wPos = camera_.WorldToScreenPoint(transform.position); // 把立方体的世界坐标转化为屏幕坐标
            sPos.z = wPos.z; // 获取转化后的z坐标
            return camera_.ScreenToWorldPoint(sPos);
        }
    
        void Update()
        {
            transform.position = ToWorldPoint(Input.mousePosition); // 让小方块跟随鼠标运动
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    世界坐标转屏幕坐标

    camera_.WorldToScreenPoint(transform.position) //将小方块的世界坐标转化为屏幕坐标 
    
    • 1

    视口坐标转屏幕坐标

    camera_.ScreenToViewportPoint(Input.mousePosition)
    
    • 1

    视口坐标转世界坐标

    这个需要中转一下,先将视口坐标转化为屏幕坐标,再将屏幕坐标转为世界坐标。

    camera_.ScreenToViewportPoint(Input.mousePosition) // 视口转屏幕
    
     Vector3 ToWorldPoint(Vector3 sPos){ // 屏幕转世界
            Vector3 wPos = camera_.WorldToScreenPoint(transform.position); // 把立方体的世界坐标转化为屏幕坐标
            sPos.z = wPos.z; // 获取转化后的z坐标
            return camera_.ScreenToWorldPoint(sPos);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    世界坐标转视口坐标

    这个也需要中转一下,中间套一层屏幕坐标。现将世界转屏幕,再将屏幕转视口。

     Vector3 wPos = camera_.WorldToScreenPoint(transform.position); // 世界转屏幕
     camera_.ScreenToViewportPoint(wPos) // 屏幕转视口
    
    • 1
    • 2

    屏幕坐标转视口坐标

     camera_.ScreenToViewportPoint(wPos)
    
    • 1

    视口坐标转屏幕坐标

    camera_.ScreenToViewportPoint(Input.mousePosition)
    
    • 1

    // 注意:位置的赋值不能直接改变x,y,z,只能整体改变,即以下方式不支持

    this.transform.position.x = 5
    
    • 1

    必须:

    this.transform.position.x = new Vector3(5,0,0)
    // 如果只想改一个值,x,y,z要保持原有坐标一致
    
    • 1
    • 2

    (1)直接复制

    this.transform.position = new Vector3(5, this.transform.position.y,this.transform.position.z)
    
    • 1

    鼠标事件

      // 鼠标悬浮
        void OnMouseOver()
        {
            print("鼠标悬浮");
            transform.GetComponent<MeshRenderer>().material.color = Color.blue;
        }
    
        // 鼠标点击
        void OnMouseDown()
        {
           transform.GetComponent<MeshRenderer>().material.color = Color.green;
        }
    
        //鼠标离开
        void OnMouseExit()
        {
            print("鼠标离开");
            transform.GetComponent<MeshRenderer>().material.color = Color.black;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
  • 相关阅读:
    性能优化:Redis使用优化(1)
    Lab: page tables
    【学习总结】辐射、辐照等常见光学物理量的定义与关系
    Airtest1.2.7新增断言API介绍
    初学者如何打开ABAQUS力学有限元仿真的大门
    【附源码】Python计算机毕业设计汽车租赁管理系统
    分布式文件系统FastDFS 技术整理
    MySQL数据库 | 手把手教你如何去下载安装MySQL数据库
    Fleet公测啦!真的轻量?
    C++ 模板 (一)
  • 原文地址:https://blog.csdn.net/xiaoguoyangguang/article/details/126854347