Unity官方教程《Tanks》学习笔记(二)
2018-02-09 16:22
465 查看
本系列文章是根据官方视频教程而写下的学习笔记,原官方视频教程网址:https://unity3d.com/cn/learn/tutorials/s/tanks-tutorial
系列其他笔记传送门
Unity官方教程《Tanks》学习笔记(一)
Unity官方教程《Tanks》学习笔记(三)
Unity官方教程《Tanks》学习笔记(四)
Unity官方教程《Tanks》学习笔记(五)
接着,我们选中Hierarchy中的Tank,为其添加若干个Component,分别是:Rigidbody、Box Collider、Audio Source、Audio Source,并对这些部件进行设置如下:
然后,我们把配置好的Tank从Hierarchy拖拽到Prefabs文件夹下,让它成为一个预制件,这样以后我们可以重复利用该Tank,而不用每次都重新配置。然后保存当前场景。
因为整个游戏场景是在沙漠中的,所以坦克的行驶会有沙尘滚滚的效果,所以我们需要添加这一效果。在Prefabs文件夹内,把DustTrail预制件拖拽到Hierarchy下的Tank内,让其成为Tank的子对象,然后复制粘贴DustTrail,并分别重命名为LeftDustTrail和RightDustTrail,根据下面的官方教程,把两个DustTrail的position进行调节:
设置完毕后,接下来就是对Tank的移动脚本进行设置。在/Assets/Scripts/Tank文件夹内,找到TankMoveMent.cs文件,并把它拖拽到Hierarchy下的Tank内。我们打开并编辑该脚本,把里面的注释符号去掉,并添加逻辑如下:
修改完毕并保存文件,下一步我们需要初始化在脚本中声明的几个公有变量:Movement Audio、Engine Idling、Engine Driving:
接着,我们把Main Camera拖拽到CameraRig内,成为它的子对象,并修改Main Camera的Transform数据如下:
接下来我们需要补充一些关于摄像机的知识:
1、perspective视图和orthographic视图
要想了解如何控制摄像机,我们要首先知道摄像机的两种不同视图形式,上一章也有所提及:透视视图和正交视图,下面就用官方教程的一幅图来直观地解释:
2、正交摄像机的尺寸(Size)
调节Main Camera的size参数,如果size变小,那么可视范围变小且物体变大,有放大作用。而size变大,可视范围变大且物体变小,有缩小作用。
3、摄像机的长宽比(aspect)
那么接下来,我们的摄像机应该做些什么?
1、跟随坦克。
找出两辆坦克位置的中心点,把CameraRig移到该点。
2、调整摄像机的尺寸以适应坦克在屏幕上的位置。
从上面补充的知识可以知道,正交摄像机的视图的长为Size,宽为Size * aspect。接着,在正交摄像机视角看来,坦克的运动可以分解为x轴和y轴的运动,这时,我们需要把坦克的坐标切换成摄像机视角的本地坐标。
从上面两幅图我们可以知道,size的选择有两种情况,分别是沿y轴方向(size1 = y);以及沿x轴方向,而x轴方向需要做一步计算,即size2 = x / aspect。接着比较这两个size的大小,用大的size值决定摄像机的缩放。当然了,这也需要考虑到另外一个tank的不同size值,总之,取最大的size值作为摄像机的缩放范围。
我们来看一下脚本是如何对摄像机进行控制的,打开/Assets/Scripts/Camera文件夹,选中CameraControl,把它拖拽到CameraRig中,而不是Main Camera。
然后,我们返回Unity,把Tank拖拽到如下位置:
最后,保存场景并运行。
系列其他笔记传送门
Unity官方教程《Tanks》学习笔记(一)
Unity官方教程《Tanks》学习笔记(三)
Unity官方教程《Tanks》学习笔记(四)
Unity官方教程《Tanks》学习笔记(五)
一、创建坦克以及控制坦克
首先,在Models文件夹内找到Tank这个model,把它拖拽到Hierarchy内,我们在Tank的inspector视图中,对其层级进行修改,选择Players,并仅对当前对象修改。如下图所示:接着,我们选中Hierarchy中的Tank,为其添加若干个Component,分别是:Rigidbody、Box Collider、Audio Source、Audio Source,并对这些部件进行设置如下:
然后,我们把配置好的Tank从Hierarchy拖拽到Prefabs文件夹下,让它成为一个预制件,这样以后我们可以重复利用该Tank,而不用每次都重新配置。然后保存当前场景。
因为整个游戏场景是在沙漠中的,所以坦克的行驶会有沙尘滚滚的效果,所以我们需要添加这一效果。在Prefabs文件夹内,把DustTrail预制件拖拽到Hierarchy下的Tank内,让其成为Tank的子对象,然后复制粘贴DustTrail,并分别重命名为LeftDustTrail和RightDustTrail,根据下面的官方教程,把两个DustTrail的position进行调节:
设置完毕后,接下来就是对Tank的移动脚本进行设置。在/Assets/Scripts/Tank文件夹内,找到TankMoveMent.cs文件,并把它拖拽到Hierarchy下的Tank内。我们打开并编辑该脚本,把里面的注释符号去掉,并添加逻辑如下:
using UnityEngine; public class TankMovement : MonoBehaviour { public int m_PlayerNumber = 1; //游戏者的序号 public float m_Speed = 12f; //坦克移动速度 public float m_TurnSpeed = 180f; //坦克转向的角速度 public AudioSource m_MovementAudio; public AudioClip m_EngineIdling; //静止的音效 public AudioClip m_EngineDriving; //移动的音效 public float m_PitchRange = 0.2f; private string m_MovementAxisName; private string m_TurnAxisName; private Rigidbody m_Rigidbody; private float m_MovementInputValue; private float m_TurnInputValue; private float m_OriginalPitch; /** * Scene加载的时候调用 */ private void Awake() { m_Rigidbody = GetComponent<Rigidbody>(); } /** * 在Awake()之后,Update()之前调用 */ private void OnEnable () { m_Rigidbody.isKinematic = false; m_MovementInputValue = 0f; m_TurnInputValue = 0f; } private void OnDisable () { m_Rigidbody.isKinematic = true; } private void Start() { m_MovementAxisName = "Vertical" + m_PlayerNumber; m_TurnAxisName = "Horizontal" + m_PlayerNumber; m_OriginalPitch = m_MovementAudio.pitch; } private void Update() { // Store the player's input and make sure the audio for the engine is playing. m_MovementInputValue = Input.GetAxis(m_MovementAxisName); m_TurnInputValue = Input.GetAxis (m_TurnAxisName); EngineAudio (); } private void EngineAudio() { // Play the correct audio clip based on whether or not the tank is moving and what audio is currently playing. // 如果坦克处于静止状态 if (Mathf.Abs (m_MovementInputValue) < 0.1f && Mathf.Abs (m_TurnInputValue) < 0.1f) { //如果坦克播放的是行驶状态的音效,则替换 if (m_MovementAudio.clip == m_EngineDriving) { // ... change the clip to idling and play it. m_MovementAudio.clip = m_EngineIdling; m_MovementAudio.pitch = Random.Range (m_OriginalPitch - m_PitchRange, m_OriginalPitch + m_PitchRange); m_MovementAudio.Play (); } } else { // 如果坦克播放的是静止状态的音效,则替换 if (m_MovementAudio.clip == m_EngineIdling) { // ... change the clip to driving and play. m_MovementAudio.clip = m_EngineDriving; m_MovementAudio.pitch = Random.Range(m_OriginalPitch - m_PitchRange, m_OriginalPitch + m_PitchRange); m_MovementAudio.Play(); } } } /** * 以固定的时间间隔调用,用于物理上的步骤,比如行走、转向 */ private void FixedUpdate() { // Move and turn the tank. Move (); Turn (); } private void Move() { // Adjust the position of the tank based on the player's input. Vector3 movement = transform.forward * m_MovementInputValue * m_Speed * Time.deltaTime; m_Rigidbody.MovePosition (m_Rigidbody.position + movement); } private void Turn() { // Adjust the rotation of the tank based on the player's input. float turn = m_TurnInputValue * m_TurnSpeed * Time.deltaTime; Quaternion turnRotation = Quaternion.Euler (0f,turn,0f); m_Rigidbody.MoveRotation (m_Rigidbody.rotation * turnRotation); } }
修改完毕并保存文件,下一步我们需要初始化在脚本中声明的几个公有变量:Movement Audio、Engine Idling、Engine Driving:
二、控制摄像机
首先在Hierarchy的根目录下创建一个空的GameObject,并重命名为“CameraRig”,修改其部分Transform数据如下:接着,我们把Main Camera拖拽到CameraRig内,成为它的子对象,并修改Main Camera的Transform数据如下:
接下来我们需要补充一些关于摄像机的知识:
1、perspective视图和orthographic视图
要想了解如何控制摄像机,我们要首先知道摄像机的两种不同视图形式,上一章也有所提及:透视视图和正交视图,下面就用官方教程的一幅图来直观地解释:
2、正交摄像机的尺寸(Size)
调节Main Camera的size参数,如果size变小,那么可视范围变小且物体变大,有放大作用。而size变大,可视范围变大且物体变小,有缩小作用。
3、摄像机的长宽比(aspect)
那么接下来,我们的摄像机应该做些什么?
1、跟随坦克。
找出两辆坦克位置的中心点,把CameraRig移到该点。
2、调整摄像机的尺寸以适应坦克在屏幕上的位置。
从上面补充的知识可以知道,正交摄像机的视图的长为Size,宽为Size * aspect。接着,在正交摄像机视角看来,坦克的运动可以分解为x轴和y轴的运动,这时,我们需要把坦克的坐标切换成摄像机视角的本地坐标。
从上面两幅图我们可以知道,size的选择有两种情况,分别是沿y轴方向(size1 = y);以及沿x轴方向,而x轴方向需要做一步计算,即size2 = x / aspect。接着比较这两个size的大小,用大的size值决定摄像机的缩放。当然了,这也需要考虑到另外一个tank的不同size值,总之,取最大的size值作为摄像机的缩放范围。
我们来看一下脚本是如何对摄像机进行控制的,打开/Assets/Scripts/Camera文件夹,选中CameraControl,把它拖拽到CameraRig中,而不是Main Camera。
using UnityEngine; public class CameraControl : MonoBehaviour { public float m_DampTime = 0.2f; //移动Camera到目的position的时间 public float m_ScreenEdgeBuffer = 4f; //确保Tanks不会在屏幕边界之外 public float m_MinSize = 6.5f; //Camera的最小尺寸 /*[HideInInspector]*/ public Transform[] m_Targets; //坦克,先把[HideInInspector]注释掉 private Camera m_Camera; private float m_ZoomSpeed; private Vector3 m_MoveVelocity; private Vector3 m_DesiredPosition; //需要移动到的位置 private void Awake() { m_Camera = GetComponentInChildren<Camera>(); } private void FixedUpdate() { Move(); Zoom(); } private void Move() { FindAveragePosition(); /** * function Vector3.SmoothDamp(Vector3 current,Vector3 target * ,ref Vector3 currentVelocity,float smoothTime) * @parameters * current:当前的位置 * target:试图接近的位置 * currentVelocity:当前速度,这个值由你每次调用这个函数时修改 * smoothTime:到达目标的大约时间,较小的值将快速到达目标 */ transform.position = Vector3.SmoothDamp(transform.position, m_DesiredPosition, ref m_MoveVelocity, m_DampTime); } private void FindAveragePosition() { Vector3 averagePos = new Vector3(); int numTargets = 0; for (int i = 0; i < m_Targets.Length; i++) { //判断当前坦克是否已经不是激活状态(死亡),如果未激活, //则不需要跟随该坦克 if (!m_Targets[i].gameObject.activeSelf) continue; averagePos += m_Targets[i].position; numTargets++; } if (numTargets > 0) averagePos /= numTargets; //CameraRig的Y position不会被改变 averagePos.y = transform.position.y; m_DesiredPosition = averagePos; } private void Zoom() { //根据目标位置来计算合适的Size float requiredSize = FindRequiredSize(); m_Camera.orthographicSize = Mathf.SmoothDamp(m_Camera.orthographicSize, requiredSize, ref m_ZoomSpeed, m_DampTime); } private float FindRequiredSize() { //把目标位置的世界坐标转换成本地坐标 Vector3 desiredLocalPos = transform.InverseTransformPoint(m_DesiredPosition); float size = 0f; for (int i = 0; i < m_Targets.Length; i++) { if (!m_Targets[i].gameObject.activeSelf) continue; //把坦克所在的位置转换成CameraRig的本地坐标 Vector3 targetLocalPos = transform.InverseTransformPoint(m_Targets[i].position); //在CameraRig的本地坐标下,求出坦克与CameraRig的目标位置的距离 Vector3 desiredPosToTarget = targetLocalPos - desiredLocalPos; size = Mathf.Max (size, Mathf.Abs (desiredPosToTarget.y)); size = Mathf.Max (size, Mathf.Abs (desiredPosToTarget.x) / m_Camera.aspect); } //加上ScreenEdgeBuffer值,即坦克与屏幕边界的距离 size += m_ScreenEdgeBuffer; size = Mathf.Max(size, m_MinSize); return size; } public void SetStartPositionAndSize() { FindAveragePosition(); transform.position = m_DesiredPosition; m_Camera.orthographicSize = FindRequiredSize(); } }
然后,我们返回Unity,把Tank拖拽到如下位置:
最后,保存场景并运行。
相关文章推荐
- Unity官方教程《Tanks》学习笔记(一)
- Unity官方教程《Tanks》学习笔记(三)
- Unity官方教程《Tanks》学习笔记(四)
- Unity官方教程《Tanks》学习笔记(五)
- unity官方换装教程Character Customization 学习笔记
- Unity官方示例教程《Stealth》学习笔记
- Unity 3D官方教程——Tanks!学习记录
- Unity Graphics (Unity 图形渲染 ) 官方教程文档笔记系列之八
- Unity官方实例教程 Roll-a-Ball 学习笔记(一)+(二)
- Unity官方教程学习笔记之Roll A Ball篇---(二)创建地面
- [我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之纹理Textures
- 不知道怎么开发VR游戏?Unity5.3官方VR教程重磅登场-系列3 VR中的交互方式
- Unity官方实例教程 Roll-a-Ball
- [我给Unity官方视频教程做中文字幕]beginner Graphics – Lessons系列之摄像机介绍Cameras
- Unity官方实例教程 Roll-a-Ball(一)
- unity官方教程Space shooter学习笔记-01
- Unity官方教程Roll-a-ball (一)
- Unity Graphics (Unity 图形渲染 ) 官方教程文档笔记系列之四
- Unity5.3官方VR教程重磅登场-系列4 VR中的用户界面
- unity官方教程 太空射击---问题填坑 之 计分以及游戏胜利