1 场景设置
新建项目,删除光源。从资源商店下载并导入免费资源:Tanks! Tutorial。
导入后将 Assets/Prefabs 中的 LevelArt 拖入 Hierarchy,会看到准备好的一张地图:
确保 LevelArt 位于 (0, 0, 0) 处。
点击 Window,打开 Lighting 面板,根据下方幻灯片修改设置:
调整摄像机位置到 (-43, 42, -25),旋转调整到 (40, 60, 0),并设置为正交投影。
将相机组件中的 Clear Flags 选为 Solid Color,背景色改为 (80, 60, 50),并保存场景。
2 坦克创建和控制
创建坦克:
- 在 Models 中找到 Tank 并拖入 Hierarchy
- 将 Tank 的 Layer 设成 Player(方便后续做碰撞检测),且仅修改父物体。
- 为 Tank 添加刚体组件,为了防止坦克高度发生变化或者围绕Y轴以外的轴旋转,在刚体组件的 Constraints 中勾选 Freeze Position 的 Y 以及 Freeze Rotation 的 X 和 Z
为 Tank 添加碰撞体组件:
为 Tank 添加音频组件,用于循环播放发动机的声音:
添加另一个为之后的脚本准备的音频组件,并将 Tank 保存为预制体:
为 Hierarchy 中的 Tank 添加粒子系统,模拟行车时车轮扬起的尘土:
为 Tank 添加一个脚本 TankMovement.cs 用来控制其移动,代码如下:
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; // 原始音调
private void Awake()
{
m_Rigidbody = GetComponent<Rigidbody>();
}
private void OnEnable ()
{
// isKinematic 的作用简单来说是使其不受力的影响
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)
{
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)
{
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);
}
}
写完脚本之后,在编辑器中设置好 Tank 的三个音频变量。
保存后在 Inspector 中更新预制体。
可以开始测试了,根据默认的输入设定,通过 wasd 能控制坦克移动(当然摄像机跟随还没做好)。