Alt+鼠标左键–旋转视图
Alt+鼠标右键–放大缩小视图
利用标签,可以将对象分为几类,以便让脚本仅在触碰到正确的对象时才能触发操作;没有标签,就无法区分对象。
两个物体都必须带有碰撞器(Collider),其中一个物体还必须带有Rigidbody刚体或者charactercontroller组件。
该组件定义了包含它们的游戏对象的行为,是每个游戏对象的功能单元。
Transform 变换组件用于存储游戏对象的位置、旋转、缩放和父子化状态,因此非常重要。游戏对象始终附加一个变换组件,无法删除变换组件或创建没有变换组件的游戏对象。
变换组件的位置、旋转和缩放值是相对于变换组件的父项测量的。如果变换组件没有父项,则按照世界空间来测量属性。
Inspector 中任何子游戏对象的 Transform 值都是相对于父项 Transform 值显示的结果。这些值称为“局部坐标”。
在文档中,被称为“最重要的概念”,原因也很简单,即“万物皆对象”。Unity 中,游戏由场景组成,而场景中的任何元素,都是游戏对象。游戏对象是 Unity 中的基础对象,表示角色、道具和景物。它们本身并没有取得多大作为,但它们充当组件的容器,而组件可实现功能。游戏对象始终附加一个变换组件(表示位置和方向),并且无法删除此组件。
启用 Is Kinematic,则刚体对象将不会被物理引擎驱动,只能通过变换 (Transform) 对其进行操作。
使用时,需要使作用物体被包括在该碰撞器中,即用“编辑碰撞器”选项来改变大小。
Debug.Log();
在 2D 游戏中,使用 2D 素材的过程:PNG(JPG 等)----> Sprite ----> GameObject
1.见链接
2.见链接
时间和帧率
1.参考文档:
文档1
文档2
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)
2.具体解决方法可见链接
两物体碰撞时发生抖动问题
1.具体使用方法如代码所示:
//注:currentHealth、maxHealth均为自定义的整形数值
currentHealth=Mathf.Clamp(currentHealth,0,maxHealth);//限制currentHealth的值在0和maxHealth之间, 如果currentHealth小于0,返回0;如果currentHealth大于maxHealth,返回maxHealth;否则返回value
1.触发器(Trigger),是一种特殊类型的碰撞体,触发器不会阻止移动,但是物理系统仍会检查角色是否与碰撞器发生碰撞,比如当角色进入触发器时,你将收到一条消息,以便可以处理该事件。
总之一句话就是:触发器碰撞体只检测碰撞,不组织移动;碰撞时,可接受到消息,根据需求添加相关处理代码
2.触发器相关函数():
(1)当绑定着碰撞器的游戏对象进入触发器区域的时候,会运行触发器对象上的MonoBeavior中的OnTriggerEnter()函数;
(2)当其处在触发器区域的时候会运行OnTriggerStay()函数,每帧调用一次OnTriggerStay()函数;注:OnTriggerStay()函数每帧调用一次
(3)当其离开触发器区域的时候会运行OnTriggerExit()函数;
详细可见链接
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的值了。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
///
///
///
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);//旋转游戏对象
}
}
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投掷齿轮发出的声音,以及受到伤害时发出的声音
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
///
///
///
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);
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
///
///
///
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);//显示对话框
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
///
///
///
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();//特效停止产生新的粒子,原有已经生成的粒子会正常走完它的生命周期
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
///
///
///
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);//设置新的导航位置
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
///
///
///
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);//旋转该游戏对象
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
///
///
///
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脚本中抓到玩家的方法
}
}
}
}
}
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;//物体变为黑色
}
}