untiy3D 学习笔记

1.操作Scene视图的快捷键

Alt+鼠标左键–旋转视图
Alt+鼠标右键–放大缩小视图

2.标签tag的作用:

利用标签,可以将对象分为几类,以便让脚本仅在触碰到正确的对象时才能触发操作;没有标签,就无法区分对象。

3.物体发生碰撞的必要条件:

两个物体都必须带有碰撞器(Collider),其中一个物体还必须带有Rigidbody刚体或者charactercontroller组件。

4.unity中游戏是由多个scene来组成的
5.Comeponent组件

该组件定义了包含它们的游戏对象的行为,是每个游戏对象的功能单元。

6.Transform 组件

Transform 变换组件用于存储游戏对象的位置、旋转、缩放和父子化状态,因此非常重要。游戏对象始终附加一个变换组件,无法删除变换组件或创建没有变换组件的游戏对象。
变换组件的位置、旋转和缩放值是相对于变换组件的父项测量的。如果变换组件没有父项,则按照世界空间来测量属性。
Inspector 中任何子游戏对象的 Transform 值都是相对于父项 Transform 值显示的结果。这些值称为“局部坐标”。

7.GameObject 游戏对象

在文档中,被称为“最重要的概念”,原因也很简单,即“万物皆对象”。Unity 中,游戏由场景组成,而场景中的任何元素,都是游戏对象。游戏对象是 Unity 中的基础对象,表示角色、道具和景物。它们本身并没有取得多大作为,但它们充当组件的容器,而组件可实现功能。游戏对象始终附加一个变换组件(表示位置和方向),并且无法删除此组件。

8.子对象中的坐标是相对于父对象而言的,并不是世界坐标
9.关于刚体(3D)Rigidbody中的 Is Kinematic

启用 Is Kinematic,则刚体对象将不会被物理引擎驱动,只能通过变换 (Transform) 对其进行操作。

9.关于球体碰撞器Sphere Collider

使用时,需要使作用物体被包括在该碰撞器中,即用“编辑碰撞器”选项来改变大小。

10.关于预制体Prefabs(又称预制件)

在这里插入图片描述

在这里插入图片描述 更多信息见链接预制件

11.unity打印在控制台

Debug.Log();

12.精灵 Sprite 是 Unity 中 2D 素材的默认存在形式,是 Unity 中的 2D 图形对象。

在 2D 游戏中,使用 2D 素材的过程:PNG(JPG 等)----> Sprite ----> GameObject

13.关于Transform
  1. 2D 游戏中,没有 Z 轴来表示深度,只有 X 轴和 Y 轴,以中心点为原点(0,0),左 x 负,右 x 正,上 y 正,下 y 负
  2. Unity 中,通过游戏对象的 Transform 组件,可以获取该对象在场景中的位置 Position,并通过更改 Transform 组件 Position 的值,可以更改其位置,依据的坐标轴就是上面所描述的 2D 坐标轴
  3. transform.position用来获取当前对象的位置
14.关于Start函数、Update函数、Awake函数、FixedUpdate函数

1.见链接
2.见链接

15.使用键盘控制物体移动的基础代码

方法1:(不太推荐)
在这里插入图片描述
方法2:(推荐)
在这里插入图片描述

16.使用Input.Getkey来获取键盘按下的哪个键

在这里插入图片描述

17. unity中时间和帧率知识(包括Time.delataTime知识总结)

时间和帧率

18.瓦片地图

1.参考文档:
文档1
文档2

19.伪透视图和Sprite 轴心 pivot

1.透视图指的是有深度、距离感的图,一般要三维中的深度轴来表现场景的深度,而二维游戏中没有这个深度,只能通过前后来仿造深度效果,称为“伪透视图”。
先前通过调整瓦片的 Order in Layer 属性来解决了瓦片地图的排序问题,但并非总是希望一个游戏对象在另一个游戏对象之上,比如,在同一个瓦片地图中,
玩家角色在一个物体之前(比如一棵树)时,应该是玩家遮挡树,而玩家移动到树后时,应该是树遮挡玩家,这就需要“伪造”透视图(两物体的图层顺序相同时才生效)。
在 2D 游戏中,场景里的 “前后” 是由 Y 轴决定的,需要让 Unity 根据游戏对象的 y 坐标来绘制游戏对象Y 轴 y 坐标值越小,越靠前,
应该遮挡 y 坐标值较大的游戏对象,也就是 y 坐标较小的游戏对象后绘制,就会位于上层在游戏中,如果要设置 2D 伪透视试图,需要在项目设置中进行更改:
Edit > Project Settings > Graphics > Camera Settings > Transparency Sort Mode = Custom Axis > Transparency Sort Axis x = 0 / y = 1 / z = 0
例如:
在这里插入图片描述

2.轴心,可在Sprite Editor中进行修改(在游戏中,为了更好地玩家交互,可以将有些物体的轴心设置为底部中间位置,即x:0.5,y:0)
20.两物体碰撞时发生抖动解决方法代码

1.代码如图:
在这里插入图片描述

2.具体解决方法可见链接
两物体碰撞时发生抖动问题

21.两物体碰撞时发生旋转解决方法:冻结刚体中z轴旋转

在这里插入图片描述

22.unity中Sprite Editor来的使用(用来切割图片)

(1)在这里插入图片描述
(2)在这里插入图片描述

23.unity中Mathf.Clamp函数(将一个值限制在两个界限值中间)

1.具体使用方法如代码所示:

//注:currentHealth、maxHealth均为自定义的整形数值
 currentHealth=Mathf.Clamp(currentHealth,0,maxHealth);//限制currentHealth的值在0和maxHealth之间, 如果currentHealth小于0,返回0;如果currentHealth大于maxHealth,返回maxHealth;否则返回value
24.unity中触发器

1.触发器(Trigger),是一种特殊类型的碰撞体,触发器不会阻止移动,但是物理系统仍会检查角色是否与碰撞器发生碰撞,比如当角色进入触发器时,你将收到一条消息,以便可以处理该事件。
总之一句话就是:触发器碰撞体只检测碰撞,不组织移动;碰撞时,可接受到消息,根据需求添加相关处理代码
2.触发器相关函数():
(1)当绑定着碰撞器的游戏对象进入触发器区域的时候,会运行触发器对象上的MonoBeavior中的OnTriggerEnter()函数;
(2)当其处在触发器区域的时候会运行OnTriggerStay()函数,每帧调用一次OnTriggerStay()函数;注:OnTriggerStay()函数每帧调用一次
(3)当其离开触发器区域的时候会运行OnTriggerExit()函数;

25.C#中模板字符串$的用法(很好用)

在这里插入图片描述

详细可见链接

26.面向对象c#等语言中,数据成员变量都应尽可能地设置为私有,只能通过当前类的方法或属性进行访问。
27.c#中属性

1.属性的定义

public int MyIntProp{
    set{
            //给属性设置值的时候,就会调用属性中的set块,因此可以在set块中通过value访问到我们所设置的值。
        }
    get{
            //当取得属性的值得时候,就会调用属性中的get块,因此get块需要返回值,其返回值类型就是属性的类型。
        }
    }

2.具体用法举例:

namespace Ch05Ex03
{
    class D
    {
        private  double _nameField = 3.14;
        public double NameFild
        {
            set
            {
                _nameField = value > 100 ? 100 : value;  //执行计算
            }
            get
            {
                return _nameField;
            }
        }
    }
  
    class Program
    {
        static void Main(string[] args)
        {
            D myD = new D();
            myD.NameFild = 200;  //给访问器中的字段赋值
            WriteLine(myD.NameFild);  //输出赋值后的字段的值
            ReadKey();
        }
    }
}
 

应用场所举例:出于保护数据的原因,设置封装了一个private类型的数据成员number,但是要在该类外调用并修改此数据成员numbe,此时便可以在number所属的类内定义一个public类型的属性,并在该属性内部实现对数据成员number的修改,然后就可以在类外调用该属性并修改number的值了。

28.Unity中Update函数每帧调用一次,而FIxedUpdate函数每0.02秒调用一次
29.unity2D 动画(文档参考链接)
30.Unity 使用 Quaternion 类来存储游戏对象的三维方向,也使用它们来描述从一个方向到另一个方向的相对旋转。Quaternion.identity就是指Quaternion(0,0,0,0)
31.Mathf.Approximately用于比较两个浮点值,如果它们相似,则返回 true。
32.在3D中让玩家角色走动并使朝向旋转的代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

///<summary>
///
///</summary>
public class PlayerMovement : MonoBehaviour
{
    //TODO:
    //1.获取玩家输入,在场景中移动玩家角色游戏对象
    //2.移动时,除了位置之外position,还需要考虑转动rotation
    //3.需要将动画也考虑进去

    Vector3 m_Movement;    //创建一个3D矢量,来表示玩家角色的移动

    //获取用户输入方向
    float horizontal;//x轴方向
    float vertical;//z轴方向

    Rigidbody m_Rigidbody;//创建一个刚体对象
    Animator m_Animator;//创建一个animator组件对象
    Quaternion m_Rotation=Quaternion.identity;//用四元数对象m_Rotation来表示游戏对象中的旋转,Quaternion.identity就是指Quaternion(0,0,0,0),
    public float turnSpeed = 20.0f;//旋转速度

    private void Start()
    {
        m_Animator = GetComponent<Animator>();//获取游戏对象的动画器组件
        m_Rigidbody = GetComponent<Rigidbody>();//获取游戏对象的刚体组件
    }
    private void Update()
    {
        //获取用户输入方向
        horizontal = Input.GetAxis("Horizontal");//获取x轴方向输入,Input.GetAxis("Horizontal")代表X轴方向移动
        vertical = Input.GetAxis("Vertical");//获取z轴方向,Input.GetAxis("Vertical")代表Z轴方向移动


    }
    private void FixedUpdate()
    {
        m_Movement.Set(horizontal, 0.0f, vertical);//设置该3D矢量的坐标,参数为用户输入的三维矢量
        m_Movement.Normalize();//将该向量的长度设置为1
        bool hasHorizontal = !Mathf.Approximately(horizontal, 0.0f);//判断是否有横向移动
        bool hasVertical = !Mathf.Approximately(vertical, 0.0f);//判断是否有纵向移动;Mathf.Approximately用于比较两个浮点值,如果它们相似,则返回 true
        bool isWalking = hasHorizontal || hasVertical;//横向或者纵向有一个移动,玩家角色便是处于移动状态
        m_Animator.SetBool("IsWalking", isWalking);//将变量传递给动画管理器
        Vector3 desiredForward = Vector3.RotateTowards(transform.forward, m_Movement, turnSpeed * Time.deltaTime, 0f);//用三维矢量表示转向后的玩家角色朝向;
        m_Rotation = Quaternion.LookRotation(desiredForward);//设置四元数对象的值
    }
        private void OnAnimatorMove()//当动画播放引发根移动时执行
    {
        m_Rigidbody.MovePosition(m_Rigidbody.position + m_Movement * m_Animator.deltaPosition.magnitude);//使用从用户输入获取到的三维矢量作为移动方向,使用动画中每次0.02秒移动的距离作为距离来移动
        m_Rigidbody.MoveRotation(m_Rotation);//旋转游戏对象
    }

}

33.从代码中学习
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RubyController : MonoBehaviour
{
    public GameObject projectTilePrefab;//声明一个公开的游戏对象,用来获取子弹的预制件
    bool isInvincible;//设置玩家是否处于无敌状态
    public float timeInvincible=2.0f;//设置玩家无敌状态的时间间隔
    float invincibleTimer;//定义变量,进行无敌时间的计时,无敌时间计时器
    public int maxHealth=5;//生命值的上限(最大生命值)
    private int currentHealth;//目前生命值
    AudioSource audioSource;//声明音频源对象,用来后期进行音频播放控制
    public AudioClip throwCogClip;//声明一个公开的音频剪辑变量,用来在unity inspector中,挂接要播放的音频剪辑
    public float throwCogSoundVol = 1.0f;//播放音频的音量大小
    public AudioClip playerHitClip;//声明一个公开的音频剪辑变量,用来在unity inspector中,挂接要播放的音频剪辑
    public float playerHitSoundVol = 1.0f;//播放音频的音量大小

    public int health//设置当前生命值的属性health;在c#中支持面向对象程序设计中的封装概念,对数据成员的保护;
    {
        get{return currentHealth;}
    }
    public float speed=0.1f;
    Rigidbody2D rigidbody2D1;
     float horizontal;
     float vertical;

     Animator animator;//声明一个动画管理者组件对象
     //与机器人相比,Ruby可以站着不动,当站着不动时,Move X和Move Y均为0,这时状态机就没法获取Ruby静止时的朝向,所以需要手动设置一个
     Vector2 lookDirection=new Vector2(1,0);//创建一个二维矢量,用来存储Ruby静止不移动时的方向(即面向的方向)
     Vector2 move;//移动二维矢量
     
    void Start()//系统函数,游戏刚开始运行时调用
    {
        rigidbody2D1=GetComponent<Rigidbody2D>();//获取该物体的刚体组件
        currentHealth=maxHealth;//在游戏刚开始时设置当前生命值为最大生命值(即满血状态)
        animator =GetComponent<Animator>();//获取组件对象
        audioSource=GetComponent<AudioSource>();//获取声音源组件对象
    }
    void Update()//系统函数,每帧调用一次
    {
         horizontal=Input.GetAxis("Horizontal");
         vertical=Input.GetAxis("Vertical");

        //判断是否处于无敌状态,来进行计时器的更改
        if(isInvincible)//如果无敌,则进入倒计时
        {
            invincibleTimer-=Time.deltaTime;//每次Update减去一帧所消耗的时间
            if(invincibleTimer<0)//如果计时器中时间用完
            {
                isInvincible=false;//取消无敌状态
            }
        }

        move=new Vector2(horizontal,vertical);//创建一个二维矢量对象来表示Ruby移动的数据信息
        //如果move中的x/y不为0,表示正在运动
        //将ruby面向方向设置为移动方向
        //停止移动,保持以前方向,所以这个if结构用于转向时重新赋值面朝方向
        if(!Mathf.Approximately(move.x,0.0f)||!Mathf.Approximately(move.y,0.0f))
        {
            lookDirection.Set(move.x,move.y);
            //使向量长度为1,可以将此方法成为向量的”归一化”方法
            //通常用在表示方向,而非位置的向量上
            //因为blender tree中表示方向的参数取值范围是-1.0到1.0
            //所以一般用向量作为Animator.SetFloat的参数时,一般要对向量先进行”归一化处理”
            lookDirection.Normalize();
        }
        //传递ruby面朝方向给blend tree
        animator.SetFloat("Look X",lookDirection.x);
        animator.SetFloat("Look Y",lookDirection.y);
        //传递ruby速度给blend tree
        //矢量的magniute属性,用来返回矢量的长度
        animator.SetFloat("Speed",move.magnitude);

        //添加发射子弹的逻辑
        if(Input.GetKeyDown(KeyCode.C) || Input.GetAxis("Fire1")!=0)//玩家按下键盘上的C键,或者按下发射键(左ctrl或鼠标左键)发射子弹
        {
            Launch();//调用下边定义好的发射子弹函数
        }

        if (Input.GetKeyDown(KeyCode.X))//使用x键激活射线投射
        {
            //创建一个射线投射碰撞对象,来接收射线投射碰撞信息
            //射线投射使用的是Physics2D.Raycast方法
            //参数1:射线投射的位置
            //参数2:投射方向
            //参数3:投射距离
            //参数4:射线生效的层
            RaycastHit2D hit = Physics2D.Raycast(rigidbody2D1.position + Vector2.up * 0.2f, lookDirection,1.5f,LayerMask.GetMask("NPC"));
            if (hit.collider != null)
            {
                Debug.Log($"射线投射碰撞到的对象是:{hit.collider.gameObject}");
                NonPlayerCharacter npc=hit.collider.GetComponent<NonPlayerCharacter>();//创建NPC代码组件
                if (npc != null)
                {
                    npc.DisplayDialog();//调用NPC组件的显示对话框的方法
                }
            }
        }

    }
    void FixedUpdate()//系统函数,固定时间间隔(默认为0.02秒)执行一次
    {
        Vector2 position=transform.position;//获取当前对象的位置
        position.x=position.x+speed*horizontal*Time.deltaTime;
        position.y=position.y+speed*vertical*Time.deltaTime;
        transform.position=position;
    }

   public void changeHealth(int amount)//自定义函数,改变玩家当前生命值
    {
        if(amount<0)//如果玩家要减血
        {
            if(isInvincible)//如果处在无敌状态,则无需进行加血或掉血的操作,跳出当前changeHealth方法
            {
                return;
            }
            isInvincible=true;//当不是无敌状态时,重置无敌状态为真
            invincibleTimer=timeInvincible;//重置无敌时间
            animator.SetTrigger("Hit");//播放受伤动画
            PlaySound(playerHitClip, playerHitSoundVol);//播放受伤掉血的音频
        }
        currentHealth=Mathf.Clamp(currentHealth+amount,0,maxHealth);//此句代码的意思是:限制玩家当前生命值的范围为0-最大生命值。//函数解析:限制currentHealth+amount的值在0和maxHealth之间, 如果currentHealth+amount小于0,返回0;如果currentHealth+amount大于maxHealth,返回maxHealth;否则返回value
        //Debug.Log("当前生命值:"+currentHealth+"/"+maxHealth);//控制台输出生命值
        UiHealthBar.Instance.SetValue(currentHealth/(float)maxHealth);

    }

    void Launch()//玩家发射子弹
    {
        GameObject projectTileObject=Instantiate(projectTilePrefab,rigidbody2D1.position+Vector2.up*0.5f,Quaternion.identity);//Instantiate为实例化一个游戏对象
        ProjectTile projecttile=projectTileObject.GetComponent<ProjectTile>();//获取子弹游戏对象的脚本组件对象(ProjectTile是自定义的一个类,在ProjectTile脚本中)
        projecttile.Launch(lookDirection,300);//通过脚本对象调用子弹移动的方法,第一个参数是移动的方向,取得是玩家面朝的方向;第二个参数是力,如果想要速度快些,可以加大
        animator.SetTrigger("Launch");
        PlaySound(throwCogClip, throwCogSoundVol);//播放发射子弹的音频
    }

    
    public void PlaySound(AudioClip audioClip,float soundVol)//新增一个公有方法,一经调用,会播放指定的音频剪辑
    {
        audioSource.PlayOneShot(audioClip, soundVol);//调用音频源的PlayOneShot方法,播放指定的音频
    }

    //添加Ruby投掷齿轮发出的声音,以及受到伤害时发出的声音


}

34.从代码中学习
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

///<summary>
///
///</summary>
public class ProjectTile : MonoBehaviour//子弹预制件脚本
{
    Rigidbody2D rigidbody2d;    //声明刚体对象
    void Awake()//在创建对象时(调用 Instantiate 时)就会立即调用 Awake函数
    {
        rigidbody2d=GetComponent<Rigidbody2D>();//获取刚体对象实例
    }

    public void Launch(Vector2 direction,float force)//把当前子弹发射出去
    {
        rigidbody2d.AddForce(direction*force);//通过刚体对象调用物理系统的AddForce方法,给游戏对象施加一个力,使其移动
    }

    private void OnCollisionEnter2D(Collision2D other)//OnCollisionEnter2D为2D碰撞事件(是系统函数)
    {
        EnemyController2 enemyController2=other.collider.GetComponent<EnemyController2>();//获取齿轮飞弹碰到的机器人对象的脚本组件
        if(enemyController2!=null)
        {
            enemyController2.Fix();
        }
        Debug.Log($"齿轮子弹碰撞到了:{other.gameObject}");//&为c#中的一种输出格式
        Destroy(gameObject);//碰撞后,销毁子弹游戏对象
    }
    
    private void Update()
    {
        if(transform.position.magnitude>50.0f)//如果没有碰到碰撞体的齿轮,在飞行距离超过50单位后,自动销毁
        {
            Destroy(gameObject);
        }
    }
}

35.从代码中学习
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;

///<summary>
///
///</summary>
public class NonPlayerCharacter : MonoBehaviour//控制对话框的显示
{
    public float displayTime = 4.0f;//默认显示时间是0.4秒
    public GameObject dialogBox;//获取对话框游戏对象
    float timerDisplay;//计时器,用来倒计时文本框显示的时间
    public GameObject dlgTxtProGameObject;//创建一个游戏对象,来获取TMP控件
    TextMeshProUGUI _tmTxtBox;//创建游戏组件累对象
    int _currentPage = 1;//设置变量存储当前页数
    int _totalPages;//设置变量,用来存储总页数

    private void Start()
    {
        dialogBox.SetActive(false);//游戏一开始时,不显示对话框
        timerDisplay = -1.0f;//设置计时器刚开始不可用
        _tmTxtBox=dlgTxtProGameObject.GetComponent<TextMeshProUGUI >();//获取对话框TMP组件
    }
    private void Update()//每帧调用一次
    {
        _totalPages = _tmTxtBox.textInfo.pageCount;//获取对话框组件中,对话文字的总页数(start方法中获取不到)
        if (timerDisplay >= 0.0f)//如果倒计时没结束
        {
            if (Input.GetKeyUp(KeyCode.Space))//如果按下键盘的空格键
            {
                if (_currentPage < _totalPages)//如果没到最后一页,就向后翻页
                {
                    _currentPage++;
                }else
                {
                    _currentPage = 1;
                }
                _tmTxtBox.pageToDisplay = _currentPage;//文本框中显示当前页
            }
            timerDisplay -= Time.deltaTime;//倒计时
        }else
        {
            dialogBox.SetActive(false);//否则,倒计时结束,让对话框隐藏
        }
    }

    public void DisplayDialog()//NPC说话方法
    {
        timerDisplay = displayTime;//重置计时器
        dialogBox.SetActive (true);//显示对话框
    }


}

36.从代码中学习
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

///<summary>
///
///</summary>
public class EnemyController2 : MonoBehaviour
{
    public float speed;//移动速度
    public bool Vertical;//是否垂直移动,如果是true就沿y轴移动,如果是false就按x轴移动
    Rigidbody2D rigidbody2d;//声明刚体对象
    public float changeTime=3.0f;//朝一个方向移动的总时间
    private float timer;//计时器
    int direction=1;//移动方向
    Animator animator;//动画器组件
    bool broked=true;//设定一个bool值,初始值true代表机器人刚开始是”坏”的
    public ParticleSystem smokeEffect;//开放一个属性用来获取烟雾属性,方便用代码来操作
    void Start()
    {
        rigidbody2d=GetComponent<Rigidbody2D>();//获取刚体组件
        timer=changeTime;
        animator=GetComponent<Animator>();//获取当前机器人对象的动画器组件

    }
    void Update()//每帧调用一次
    {
        if(!broked)//如果已经修复机器人,则直接退出update方法
        {
            return;
        }
        timer-=Time.deltaTime;
        if(timer<0)
        {
            direction=-direction;//调头
            timer=changeTime;
        }
    }
     private void FixedUpdate()//移动刚体(该函数默认0.02秒执行一次)
    {
        if(!broked)//如果已经修复机器人,则直接退出update方法
        {
            return;
        }
        Vector2 position=rigidbody2d.position;//获取当前对象所在位置
        if(Vertical)//纵向移动,沿着y轴移动
        {
            position.y+=Time.deltaTime*speed*direction;//Time.deltaTime是每帧的时间间隔,float类型
            animator.SetFloat("Move X",0);
            animator.SetFloat("Move Y",direction);
        }else//横向移动,沿着x轴移动
        {
            position.x+=Time.deltaTime*speed*direction;
            animator.SetFloat("Move X",direction);
            animator.SetFloat("Move Y",0);
        }
        rigidbody2d.MovePosition(position);//刚体进行移动
    }


    //用OnCollisionEnter2D添加对玩家的伤害
    private void OnCollisionEnter2D(Collision2D other)//刚体碰撞事件
    {
        RubyController rubyController=other.gameObject.GetComponent<RubyController>();//获取玩家角色对象
        if(rubyController!=null)
        {

            rubyController.changeHealth(-1);//如果玩家碰到该敌人,就使玩家血量减1
        }
    }

    public void Fix()//修复机器人的犯法
    {
        broked=false;//更改状态为修复,让机器人不会再被碰撞
        rigidbody2d.simulated=false;//刚体对象取消物理引擎效果
        animator.SetTrigger("Fixed");
        // Destroy(smokeEffect);//摧毁该机器人头顶的烟雾特效
        smokeEffect.Stop();//特效停止产生新的粒子,原有已经生成的粒子会正常走完它的生命周期
    }
}

37. UnityEditor.EditorApplication.isPlaying = false;//在untiy编译器中,停止游戏的运行;Application.Quit();//结束当前游戏(该函数在打包发布时才能生效)
38.人物寻迹行走代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

///<summary>
///
///</summary>
public class WayPointPatrol : MonoBehaviour
{
    NavMeshAgent navMeshAgent;//获取当前游戏对象的导航网格代理组件
    public Transform[] waypoints;//路径点数组

    int m_CurrentWaypointIndex;//当前的路径点索引数,范围是0到waypoints.length -1

    void Start()
    {
        navMeshAgent = GetComponent<NavMeshAgent>();//获取组件对象
        navMeshAgent.SetDestination(waypoints[0].position);//设置导航组件导航路径的起始点位
    }

    void Update()//每次刷新,都要获取下一个路径点,并通过算法,让路径点循环往复
    {
        if (navMeshAgent.remainingDistance < navMeshAgent.stoppingDistance)        //当前游戏对象到指定的路径点的距离,如果小于最终停止距离
        {
            m_CurrentWaypointIndex = (m_CurrentWaypointIndex + 1) % waypoints.Length;//获取下一个路径点在数组中的索引,并通过取余%实现循环效果
            navMeshAgent.SetDestination(waypoints[m_CurrentWaypointIndex].position);//设置新的导航位置
        }
    }
}

39.人物在3D场景中行走并实现旋转、动画的代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

///<summary>
///
///</summary>
public class PlayerMovement : MonoBehaviour
{
    //TODO:
    //1.获取玩家输入,在场景中移动玩家角色游戏对象
    //2.移动时,除了位置之外position,还需要考虑转动rotation
    //3.需要将动画也考虑进去

    Vector3 m_Movement;    //创建一个3D矢量,来表示玩家角色的移动

    //获取用户输入方向
    float horizontal;//x轴方向
    float vertical;//z轴方向

    Rigidbody m_Rigidbody;//创建一个刚体对象
    Animator m_Animator;//创建一个animator组件对象
    Quaternion m_Rotation=Quaternion.identity;//用四元数对象m_Rotation来表示游戏对象中的旋转,Quaternion.identity就是指Quaternion(0,0,0,0),
    public float turnSpeed = 20.0f;//旋转速度
    AudioSource m_AudioSource;//声明音源组件对象

    private void Start()
    {
        m_Animator = GetComponent<Animator>();//获取游戏对象的动画器组件
        m_Rigidbody = GetComponent<Rigidbody>();//获取游戏对象的刚体组件
        m_AudioSource= GetComponent<AudioSource>();//获取当前对象音源组件
    }
    private void Update()
    {
        //获取用户输入方向
        horizontal = Input.GetAxis("Horizontal");//获取x轴方向输入,Input.GetAxis("Horizontal")代表X轴方向移动
        vertical = Input.GetAxis("Vertical");//获取z轴方向,Input.GetAxis("Vertical")代表Z轴方向移动


    }
    private void FixedUpdate()
    {
        m_Movement.Set(horizontal, 0.0f, vertical);//设置该3D矢量的坐标,参数为用户输入的三维矢量
        m_Movement.Normalize();//将该向量的长度设置为1
        bool hasHorizontal = !Mathf.Approximately(horizontal, 0.0f);//判断是否有横向移动
        bool hasVertical = !Mathf.Approximately(vertical, 0.0f);//判断是否有纵向移动;Mathf.Approximately用于比较两个浮点值,如果它们相似,则返回 true
        bool isWalking = hasHorizontal || hasVertical;//横向或者纵向有一个移动,玩家角色便是处于移动状态
        m_Animator.SetBool("IsWalking", isWalking);//将变量传递给动画管理器
        Vector3 desiredForward = Vector3.RotateTowards(transform.forward, m_Movement, turnSpeed * Time.deltaTime, 0f);//用三维矢量表示转向后的玩家角色朝向;
        m_Rotation = Quaternion.LookRotation(desiredForward);//设置四元数对象的值
        if (isWalking)//如果走动,播放脚步音效,否则停止播放
        {
            if (!m_AudioSource.isPlaying)
            {
                m_AudioSource.Play();
            }
        }else
        {
            m_AudioSource.Stop();
        }
    }
        private void OnAnimatorMove()//当动画播放引发根移动时执行
    {
        m_Rigidbody.MovePosition(m_Rigidbody.position + m_Movement * m_Animator.deltaPosition.magnitude);//使用从用户输入获取到的三维矢量作为移动方向,使用动画中每次0.02秒移动的距离作为距离来移动
        m_Rigidbody.MoveRotation(m_Rotation);//旋转该游戏对象
    }

}

40.监测人物进入视野代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

///<summary>
///
///</summary>
public class Observer : MonoBehaviour//用来通过触发器代表敌人的视线监事玩家的代码
{
    public Transform player;//玩家的变换组件对象
    public GameEnding gamEnding;//设置一个开关,boo变量,表示玩家是否被视线扫到

    bool m_IsPlayerInRange;//声明游戏结束脚本组件类对象,为了调用游戏结束脚本中的共有方法

    void OnTriggerEnter(Collider other)//禁入触发器事件
    {
        if (other.transform == player)//如果进入触发区域的是玩家
        {
            m_IsPlayerInRange = true;//开关变量设置为真
        }
    }

    void OnTriggerExit(Collider other)//离开触发器事件
    {
        if (other.transform == player)//当触发器区域中的是玩家
        {
            m_IsPlayerInRange = false;//开关变量设置为假
        }
    }

    void Update()//在Update中监控开关的值,一旦玩家进入视线触发器区域,执行对应的逻辑
    {
        if (m_IsPlayerInRange)//触发器已经被触发
        {
            Vector3 direction = player.position - transform.position + Vector3.up;//设置投射射线用到的方向矢量
            Ray ray = new Ray(transform.position, direction);//创建射线
            RaycastHit raycastHit;//射线击中对象,包括射线碰撞信息

            if (Physics.Raycast(ray, out raycastHit))//使用物理系统发射射线,如果碰到物体进入第一层if。out代表第二个参数是输出参数,可以带出数据到参数中
            {
                if (raycastHit.collider.transform == player)//如果碰到的是玩家
                {
                    gamEnding.CaughtPlayer();//调用GameEnding脚本中抓到玩家的方法
                }
            }
        }
    }
}

41.键盘控制物体外观颜色代码
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.R))//按下R键
        {
            GetComponent<Renderer>().material.color = Color.red;//物体变为红色
        }else if (Input.GetKeyDown(KeyCode.G))//按下G键
        {
            GetComponent <Renderer>().material.color = Color.green;//物体变为绿色
        }
        else if (Input.GetKeyDown(KeyCode.B))//按下B键
        {
            GetComponent<Renderer>().material.color = Color.black;//物体变为黑色
        }

    }
42.gameObject.SetActive(false);用于激活游戏对象
43.transform.Translate表示将物体移动;transform.Rotate表示将物体旋转
44.transform.LookAt函数使一个游戏对象的变换组件面向另一个游戏对象的变换组件
45.Destroy() 函数删除游戏对象和组件
46. Instantiate() 函数用于创建预制件的克隆体。
47.Invoke()函数可用于延时调用方法(或某个函数)
48.Quaternion 四元数来管理游戏对象的旋转
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值