一个简单的双人坦克游戏(3D)。



GitHub
https://github.com/SSGamble/TanksGame <https://github.com/SSGamble/TanksGame>



文章目录

* 总结 <https://blog.csdn.net/SGamble/article/details/89085566#_8>
* 创建场景 <https://blog.csdn.net/SGamble/article/details/89085566#_16>
* 创建坦克 <https://blog.csdn.net/SGamble/article/details/89085566#_20>
* 添加脚本控制坦克移动 <https://blog.csdn.net/SGamble/article/details/89085566#_24>
* 双人操作坦克 <https://blog.csdn.net/SGamble/article/details/89085566#_61>
* 控制坦克发射子弹 <https://blog.csdn.net/SGamble/article/details/89085566#_80>
* 设置坦克生命值并控制死亡 <https://blog.csdn.net/SGamble/article/details/89085566#_173>
* 设置相机跟随 <https://blog.csdn.net/SGamble/article/details/89085566#_218>
* 添加音效 <https://blog.csdn.net/SGamble/article/details/89085566#_264>
* BGM <https://blog.csdn.net/SGamble/article/details/89085566#BGM_266>
* 音效 <https://blog.csdn.net/SGamble/article/details/89085566#_270>
* 增加血条 - 游戏结束 <https://blog.csdn.net/SGamble/article/details/89085566#___295>


<>总结

* 双人操作
* 拆分 Horizontal 和 Vertical 轴,为坦克设置编号,区分控制
* 相机跟随两个物体
* 让相机跟随两个物体的正中心
* 添加音效
* 利用声音组件,设置音效,控制播放。
<>创建场景

拖入场景模型

<>创建坦克

拖入坦克模型,并为坦克添加 Box Collider 组件,设置碰撞区域。

<>添加脚本控制坦克移动

因为是 3 维场景,坦克应在水平面移动,所以应该锁定刚体组件的 y 方向,和 x,z 的转向。即,只能在 xoz 平面移动,只能绕 y 轴旋转。


using System.Collections; using System.Collections.Generic; using UnityEngine;
public class TankMovement : MonoBehaviour { private Rigidbody rigidbody; public
float speed = 15; // 坦克的移动速度 public float angularSpeed = 10; // 坦克的旋转速度 void
Start () { rigidbody = this.GetComponent<Rigidbody>(); } //
MonoBehaviour.FixedUpdate():在每个固定帧帧数被调用,在处理 Rigidbody 时,应该使用 FixedUpdate 而不是
Update private void FixedUpdate() { // 控制坦克前后移动 float v =
Input.GetAxis("Vertical"); rigidbody.velocity = transform.forward * v * speed;
// 修改刚体的速度,这种方式并不符合物理规律 // 控制坦克左右旋转 float h = Input.GetAxis("Horizontal"); //
angularVelocity 刚体角速度矢量,单位为弧度/秒。 rigidbody.angularVelocity = transform.up * h *
angularSpeed; // 绕 Y 轴旋转 } }
<>双人操作坦克

edit -> project settings -> input,拆分 Horizontal 和 Vertical 轴,为坦克设置编号,区分控制。



坦克 ID



拆分控制轴
public float tankID = 1; // 坦克的编号,用于控制两种不同的键盘操作 // 通过坦克编号区分控制 float v =
Input.GetAxis("VerticalPlayer" + tankID); float h =
Input.GetAxis("HorizontalPlayer" + tankID);
<>控制坦克发射子弹

拖入子弹模型,为子弹添加碰撞体和刚体,设为触发器,并将其设为预制体。

创建空物体,设置位置到坦克发射口,此为坦克的开火位置。



坦克的开火位置

找到开火位置,实例化子弹,并为子弹设置速度,实现发射效果,为子弹添加触发检测,实现爆炸效果,最后要记得在适合的时候销毁子弹和爆炸效果。

控制坦克开火
using System.Collections; using System.Collections.Generic; using UnityEngine;
/// <summary> /// 坦克 /// 控制坦克开火 /// </summary> public class TankAttack :
MonoBehaviour { private Transform firePosition; // 开火位置 public GameObject
shell; // 子弹,需要赋值 public KeyCode fireKey = KeyCode.Space; // 开火按键 public float
shellSpeed = 15; // 子弹发射速度 // Use this for initialization void Start () { //
Transform.Find,public Transform Find(string name); 按名称查找子元素并返回它。 firePosition =
transform.Find("FirePosition"); // 查找开火位置 } // Update is called once per frame
void Update () { if (Input.GetKeyDown(fireKey)) { GameObject obj =
GameObject.Instantiate(shell, firePosition.position, firePosition.rotation) as
GameObject; // 实例化子弹 obj.GetComponent<Rigidbody>().velocity =
obj.transform.forward * shellSpeed; } } }
子弹的触发检测,产生爆炸效果
using System.Collections; using System.Collections.Generic; using UnityEngine;
/// <summary> /// 子弹 /// 子弹的触发检测,产生爆炸效果 /// </summary> public class Shell :
MonoBehaviour { public GameObject shellExplosion; // 爆炸效果,需勾选爆炸效果的 Play On
Awake,即生成就开始 // 触发检测 private void OnTriggerEnter(Collider collider) {
GameObject.Instantiate(shellExplosion, transform.position, transform.rotation);
// 实例化爆炸效果,位置就是当前子弹的位置 GameObject.Destroy(this.gameObject); // 把自身销毁 } }
爆炸效果的销毁
using System.Collections; using System.Collections.Generic; using UnityEngine;
/// <summary> /// 爆炸效果 /// 爆炸效果的销毁 /// </summary> public class DestroyFotTime :
MonoBehaviour { public float delayTime; // 爆炸效果延迟销毁时间 void Start () {
Destroy(this.gameObject, delayTime); // 爆炸效果,延迟销毁 } }
<>设置坦克生命值并控制死亡

当子弹碰到坦克时,发送一条信息,坦克收到消息,做出相应的处理。

在子弹的触发检测里设置
// 如果子弹碰撞到了 Tank,给 Tank 发送一条消息,Tank 里会创建一个 TankDamage 方法来处理消息 if (collider.tag
== "Tank") { collider.SendMessage("TankDamage"); }
坦克生命处理
using System.Collections; using System.Collections.Generic; using UnityEngine;
/// <summary> /// 坦克,坦克的生命处理 /// </summary> public class TankHealth :
MonoBehaviour { public int hp = 100; // 坦克的生命值 public GameObject tankExplosion;
// 坦克死亡的爆炸效果 /// <summary> /// 收到消息,坦克受到伤害 /// </summary> void TankDamage() {
if (hp <= 0) return; hp = hp - Random.Range(20, 30); // 随机减少生命值 if (hp <= 0) //
收到伤害后,如果死亡 { GameObject.Instantiate(tankExplosion, transform.position,
transform.rotation); // 生成爆炸效果 GameObject.Destroy(this.gameObject); // 销毁坦克 } }
}
<>设置相机跟随

让相机跟随两个坦克的正中心。首先获得两个坦克的距离,让相机处在一个合适的位置,此时相机的视野距离应该和两个坦克的距离成一个倍数,比如:

视野 = 18,坦克1 = 0.44,坦克2 = 9.57,此时倍数应该是 2 左右。


让相机一直保持在这个距离即可。这样一来,两个坦克走近的时候,视野会变小,走远的时候,视野会变大。应设置一个最小视野,否则坦克距离很近的时候,视野会变得非常小,可能只看得见两个坦克了,这是很不科学的。
using System.Collections; using System.Collections.Generic; using UnityEngine;
/// <summary> /// 相机:让相机跟随两个坦克的正中心 /// </summary> public class Follow :
MonoBehaviour { public Transform player1; // 坦克 1 public Transform player2;
//坦克 2 private Camera mainCamera; // 主相机 private Vector3 offect; //
偏移,相机和两个坦克正中心 private float size; void Start () { offect = transform.position -
(player1.position + player2.position) / 2; // 两个坦克的正中心 mainCamera =
this.GetComponent<Camera>(); // 获取相机 mainCamera.orthographic = true; //
将相机设置为正交法 } void Update () { if (player1 == null || player2 == null) return; //
如果任何一个坦克消失,游戏结束,取消相机跟随 transform.position = offect + (player1.position +
player2.position) / 2; // 两个坦克的中心位置 float distance =
Vector3.Distance(player1.position, player2.position); // 两个坦克的距离 if (distance <
9) // 即使两个坦克的距离很近,相机的最小视野也应是一个最佳倍数 size = 9f; // 相机视野的距离 = 初始倍数 else //
两个坦克距离很远 size = distance * 1; // 相机视野的距离 = 两个坦克的距离 * 一个合适的倍数
mainCamera.orthographicSize = size; // 设置相机视野 } }
<>添加音效

<>BGM



<>音效
private AudioSource audioSource; // 声音组件 public AudioClip idleAudio; //
坦克空闲时的音效 public AudioClip drivingAudio; // 坦克移动时的音效 // 获取 AudioSource 的组件
audioSource = this.GetComponent<AudioSource>(); // 在适合的时候播放音效 if (Mathf.Abs(h)
> 0.1 || Mathf.Abs(v) > 0.1) // 坦克移动时 { audioSource.clip = drivingAudio; //
设置音效 if (audioSource.isPlaying == false) // 如果没有播放,播放 audioSource.Play(); }
else // 坦克空闲时 { audioSource.clip = idleAudio; if (audioSource.isPlaying ==
false) audioSource.Play(); }
<>增加血条 - 游戏结束

添加 UI Slider,设置背景和填充图片,设置 Image Type 为 Filled
public Slider hpSlider; // 血条 private int hpTotal; // 血量 private void Start(){
hpTotal = hp; } // 坦克受到伤害时 hpSlider.value = 1 - ((float)hp / hpTotal); // 设置
Slider 血条 的值

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信