- Survival Shooter Tutorial 是Unity官方提供的一个3D生存类游戏的一个资源包,里面包含了做一个简单3D射击游戏的通常所需要使用到的功能代码以及资源,也可以了解到资源的一些调整和设置,总体来说是一个对于没有做过3D游戏的初学者来说是一个很不错的资源,并且代码注释也比较完整,理解难度也不高。
- 适用Unity版本:4.7.1
- 资源下载界面
花了点时间看了下这个资源,理解起来并不难,也是刚开始学习3D游戏的制作,以前都是2D,记录下在这个资源包中所了解到的一些关于3D或者2D的知识点。其实现在随着Unity的发展,很多的要实现的功能已经被封装成了各式各样的接口,调用起来也很方便,但是,这些接口背后所做的工作或是其他的一些数学物理基础和概念,如果了解的话更容易理解这个接口的实现原理和为什么这样去实现。
主要记录一些脚本方面的笔记。
脚本部分主要接触资源包脚本代码的片段进行各个脚本想要记录的知识点,需要注意的是资源包导入到工程中是有如果有两份同名代码的时候,需要记得区别游戏运行的是哪个地址的脚本,否则打印调试的时候可能出现没有反应的情况。
CameraFollow.cs
这个脚本主要实现了摄像头跟随游戏主角移动的功能。
void FixedUpdate ()
{
// Create a postion the camera is aiming for based on the offset from the target.
// 刷新相机当前应该所在位置
Vector3 targetCamPos = target.position + offset;
// Smoothly interpolate between the camera's current position and it's target position.
// 平滑移动相机的位置(当前位置,目标位置,移动速度)
transform.position = Vector3.Lerp (transform.position, targetCamPos, smoothing * Time.deltaTime);
}
Note
- FixedUpdate:这个方法将按照固定的帧率被调用,通常用来处理跟RigidBody,或者物理引擎相关的物体运动等方面的操作。
- Vector3.Lerp:用作两个坐标点之间的线性插值,通过不断的修改坐标值,获得一个相对于平滑的物体移动轨迹,第三个参数值越大,移动速度越快。2D环境下可以使用Vector2.Lerp。
EnemyManager.cs
这个脚本负责了怪物的创建,主要是调用循环执行在规定的时间周期内重复调用创建敌人。所有怪物的创建都通过该脚本,只是创建的怪物不一样而已。
// Call the Spawn function after a delay of the spawnTime and then continue to call after the same amount of time.
// 间隔时间执行
InvokeRepeating ("Spawn", spawnTime, spawnTime);
// Find a random index between zero and one less than the number of spawn points.
// 随机选择出生地点
int spawnPointIndex = Random.Range (0, spawnPoints.Length);
Note
- InvokeRepeating("执行方法名", 延后执行时间, 周期时间)
- Random.Range(下限, 上限),结果包含下限不包含上限
GameOverManager.cs
这个脚本主要负责的是玩家控制游戏的角色死亡之后的代码逻辑。
// ... tell the animator the game is over.
// 播放游戏结束动画
anim.SetTrigger ("GameOver");
Note
- Animator.SetTrigger("状态名") 方法是用作从当前动画状态切换到目标动画状态,跟bool的区别是bool需要手动去设置bool的值是True还是False,而SetTrigger则自动回复状态,如果说setBool是两个状态的来回切换的话,SetTrigger就是点一次触发一次到目标状态。SetTrigger也可以从自身状态转到自身状态,在Transition的Sitting中设置。
PauseManager.cs
这个脚本主要是停止游戏时间然后切换游戏音乐状态
Time.timeScale = Time.timeScale == 0 ? 1 : 0;
void Lowpass()
{
if (Time.timeScale == 0)
{
paused.TransitionTo(.01f);
}
else
{
unpaused.TransitionTo(.01f);
}
}
Note
- Time.scale,用来调整依赖于时间进行的一系列物理运动,这是所指的时间并不是现实时间而是Unity中的时间概念,通常会影响FixedUpdate的调用频率而不影响Update和LateUpdate。
- AudioMixerSnapshot.TransitionTo(),在指定的时间间隔内对此快照执行插值转换。暂时还不是很理解。(待解决)有兴趣再挖一下。
EnemyAttack.cs
这个脚本主要判断是否接触了玩家,如果是的话则开始攻击也就是扣血。
Note
- void OnTriggerEnter (Collider other)
- void OnTriggerExit(Collider other)
- void OnTriggerStay(Collider other)
- 这三个触发器方法仅当碰撞体使用Trigger作为输入的时候才有效也就是碰撞体上面的isTrigger
EnemyHealth.cs
这个脚本主要控制怪物的存亡和受到攻击播放例子特效。
// Turn the collider into a trigger so shots can pass through it.
// 修改碰撞体isTrigger,使其被物理引擎忽略,从而让子弹穿过,也使得可以穿过碰撞体
capsuleCollider.isTrigger = true;
Note
- 当碰撞体上的IsTrigger被设置为True,那么该物体就会不受到物理引擎的影响,从可以可以穿过其他碰撞体。这里是为了可以让怪物死后下沉以及让射击穿过已经死亡的怪物。
EnemyMovement.cs
这个脚本主要控制怪物的朝向以及向玩家寻路靠近。
Update()
{
// ... set the destination of the nav mesh agent to the player.
// 使用Unity AI自动寻路
nav.SetDestination (player.position);
}
Note
- UnityEngine.AI.NavMeshAgent.setSetDestination(),提供了将绑定的物体寻路到固定坐标的方法,通过Update逐帧调用,从而不断刷新寻路坐标而逐渐靠近目标坐标或者物体。
PlayerMovement.cs
这个脚本主要负责响应玩家的输入,对控制的角色进行移动以及瞄准方向的改变。
// Create a layer mask for the floor layer.
// 得到的值是2的需要获取的Layer的次方,用于模拟射线忽略其他的碰撞体
floorMask = LayerMask.GetMask ("Floor");
void Move (float h, float v)
{
// Set the movement vector based on the axis input.
// 设置方向
movement.Set (h, 0f, v);
// 归一化方向向量,乘以速度和时间获得移动距离
// Normalise the movement vector and make it proportional to the speed per second.
movement = movement.normalized * speed * Time.deltaTime;
// Move the player to it's current position plus the movement.
// 移动物体到新的坐标,使用刚体的movePostion更自然流畅
playerRigidbody.MovePosition (transform.position + movement);
}
if(Physics.Raycast (camRay, out floorHit, camRayLength, floorMask))
Note
- 通过LayerMask.GetMask()获得的Layer ID是Int 32位的二进制形式保存的,这也是为什么一共只有32个Layer可以设置,获得的值也是2的幂次方。
- 使用RigidBody.MovePosition会比直接设置Transform的坐标更流畅自然。
- 模拟射线时传入Layer的ID就可以模拟射线的时候忽略其他层的影响。
PlayerHealth.cs
这个脚本控制玩家的血量,判断玩家是否游戏结束。
// ... transition the colour back to clear.
// 从红色到透明
damageImage.color = Color.Lerp (damageImage.color, Color.clear, flashSpeed * Time.deltaTime);
Note
- Color.Lerp用来做颜色的插值过渡。
PlayerShooting.cs
这个脚本主要负责玩家射击功能,射线模拟,确认击中的坐标,通知怪物播放受击例子特效和扣血。
Input.GetButton ("Fire1")
gunLine.SetPosition (0, transform.position);
Note
- Input.GetButton用来获取定义好的输入信号。
- LineRenderer.SetPosition用来设定描线的节点。