IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> Unity与C# -> 正文阅读

[游戏开发]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文件夹中。

五个面板

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

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

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

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

定义一个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再普通类里进行输出");
    }
}

生命周期函数

功能说明:事件函数(生命周期函数),每个游戏物体上的同一钩子函数调用顺序不确定,但可以确定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");
    }
}

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

public class No2_ExternalCall : MonoBehaviour
{
    public No2_EventFunction api;  
    // 将ExternalCall挂载到和EventFunction相同的游戏物体上,再将EventFunction的C#脚本拖拽赋值到api引用上。
    // 这样就能在ExternalCall中使用EventFunction中的方法和变量

    void Start()
    {
        //通过外部获取组件引用对变量进行赋值
        api.attackValue = -1;
    }

    void Update()
    {

    } 
}

创建游戏物体的3种方式

        //a.使用构造函数(声明+实例化) 创建一个空的游戏对象,MyGameObject:游戏物体名称
        GameObject myGo = new GameObject("MyGameObject");

        //b.根据现有的预制体(游戏物体)资源或者游戏场景已有的游戏物体来实例化(克隆)
        GameObject.Instantiate(grisGo); // 简写:Instantiate(grisGo)

        //c.使用特别的API创建一些基本的游戏物体类型(原始几何体) PrimitiveType上有许多几何体的类型包括球体、胶囊体、圆柱体等等
        GameObject.CreatePrimitive(PrimitiveType.Plane);

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

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() { }
}

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();
    }
}

组件的获取与使用(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<No2_EventFunction>();  // 不能直接获取不挂载在自身游戏物体上的组件
        //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<Transform>();  // 这也可以
    }
}

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

变换组件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);
    } 
}

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关键字
    }
}

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

访问输入系统的接口类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("当前玩家抬起鼠标中键(从按下状态松开滚轮)");
        }
    } 
}

给其他组件传送消息

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
    }
}
public class No9_MessageChild : MonoBehaviour
{
    public void GetMsg()
    {
        print("测试对象的子对象接收到消息了");
    }
}
public class No9_MessageParent : MonoBehaviour
{
    public void GetMsg()
    {
        print("测试对象的父对象接收到消息了");
    }
}
public class No9_MessageParent : MonoBehaviour
{
    public void GetMsg()
    {
        print("测试对象的父对象接收到消息了");
    }
}
public class No9_MessageTest : MonoBehaviour
{
    public void GetMsg()
    {
        print("测试对象身上的其他组件接收到消息了");
    }

    public void GetSrcMsg(string str)
    {
        print("测试对象身上的其他组件接收到的消息为:" + str);
    }
}

Animator

在这里插入图片描述
持续…

UI部分

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

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

在这里插入图片描述
文字很清晰:
在这里插入图片描述
复制一张图片成为遮罩:在这里插入图片描述
为文字添加边框效果:在这里插入图片描述
为物体创建脚本处理技能冷却效果:
在这里插入图片描述
将类在编辑器中打开:
在这里插入图片描述
在物体上绑定点击事件,指定点击事件调用的具体方法。
在这里插入图片描述

释放技能代码:

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;
        }
    }
}

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

为图片添加单选效果
在这里插入图片描述
网格组件,可以为每一项网格设置父空物体来控制网格的每一项处于正中心:
在这里插入图片描述
创建预制体

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

快捷键

按住shift:等比例缩放图片
按住option+左键:能拖拽整个画面
选中文件,再点击一下就能修改文件名
页面上选中物体,commond+D为复制物体

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-09-24 21:25:15  更:2022-09-24 21:25:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/17 3:48:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码