博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Unity3D开发游戏坦克大战
阅读量:96 次
发布时间:2019-02-26

本文共 17935 字,大约阅读时间需要 59 分钟。

文章目录

写在前面

参考学习视频是siki学院Trigger老师的课程《如何使用unity开发坦克大战》:

感谢Trigger老师的辛勤付出!
|•’-’•) ✧我在编写脚本时很多地方进行了修改和完善,和老师的教学视频稍有出入。
我使用的是Unity2019.4.0f1Rider,其实Unity2017以上版本都可以,脚本我个人更喜欢用Rider。

游戏效果图示

分别是游戏开始界面,正在游戏界面和游戏结束界面,玩家死亡3秒后返回主界面。

开始游戏游戏ing游戏结束

文件结构图

Scripts

Player.cs

using System;using System.Collections;using System.Collections.Generic;using UnityEngine;public class Player : MonoBehaviour{
public float moveSpeed = 3; // 移动速度 private Vector3 bulletEulerAngles; private float timeVal; // 子弹发射计时器 private bool isDenfended = true; // 被保护状态 private float denfenTimeVal = 3; // 被保护的计时器 // 引用 private SpriteRenderer sr; public Sprite[] tankSprite; // 坦克精灵组 上右下左 public GameObject bulletPrefab; public GameObject explosionPrefab; // 爆炸效果 public GameObject shieldPrefab; // 受保护的预制体 // 声音组建 public AudioSource moveAudio; public AudioClip[] tankAudio; private void Awake() {
sr = GetComponent
(); } void Start() {
} // Update is called once per frame void Update() {
// 是否处于无敌状态 if (isDenfended) {
shieldPrefab.SetActive(true); // 如果无敌则显示 // 受保护时间累减 denfenTimeVal -= Time.deltaTime; if (denfenTimeVal <= 0) {
isDenfended = false; shieldPrefab.SetActive(false); // 无敌消失 } } } // 固定物理帧 每一秒匀称的情况下 private void FixedUpdate() {
// 玩家不能再移动攻击 if (PlayerManager.Instance.isDefeat) return; Move(); // 子弹攻击CD if (timeVal >= 0.4f) {
Attack(); } else {
timeVal += Time.fixedDeltaTime; } } // 坦克移动方法 private void Move() {
// 通过监听h和v的输入来控制player在x和y轴位移的方向 float v = Input.GetAxisRaw("Vertical"); transform.Translate(Vector3.up * (v * moveSpeed * Time.fixedDeltaTime), Space.World); if (v < 0) {
sr.sprite = tankSprite[2]; bulletEulerAngles = new Vector3(0, 0, 180); // -180和正180 都是向下 } else if (v > 0) {
sr.sprite = tankSprite[0]; bulletEulerAngles = new Vector3(0, 0, 0); } if (Mathf.Abs(v) > 0.05f) {
// 坦克前进音效 moveAudio.clip = tankAudio[1]; if (!moveAudio.isPlaying) {
moveAudio.Play(); } } // 优先级 if (v != 0) {
return; } float h = Input.GetAxisRaw("Horizontal"); transform.Translate(Vector3.right * (h * moveSpeed * Time.fixedDeltaTime), Space.World); if (h < 0) {
sr.sprite = tankSprite[3]; bulletEulerAngles = new Vector3(0, 0, 90); } else if (h > 0) {
sr.sprite = tankSprite[1]; bulletEulerAngles = new Vector3(0, 0, -90); } if (Mathf.Abs(h) > 0.05f) {
// 坦克前进音效 moveAudio.clip = tankAudio[1]; if (!moveAudio.isPlaying) moveAudio.Play(); } else {
moveAudio.clip = tankAudio[0]; if (!moveAudio.isPlaying) moveAudio.Play(); } } // 坦克的攻击方法 private void Attack() {
if (Input.GetKeyDown(KeyCode.Space)) {
// 子弹产生的的角度等于当前坦克角度加子弹旋转角度 Instantiate(bulletPrefab, transform.position, Quaternion.Euler(transform.eulerAngles + bulletEulerAngles)); timeVal = 0; } } // 坦克死亡方法 private void Die() {
// 无敌状态不会爆炸 if (isDenfended) {
return; } PlayerManager.Instance.isDead = true; // 产生爆炸特效 Instantiate(explosionPrefab, transform.position, transform.rotation); // 死亡 Destroy(gameObject); }}

Explosion.cs

using System.Collections;using System.Collections.Generic;using UnityEngine;public class Explosion : MonoBehaviour{
// Start is called before the first frame update void Start() {
// 爆照0.167秒后自动销毁 Destroy(gameObject,0.167f); } // Update is called once per frame void Update() {
}}

Bullet.cs

using System.Collections;using System.Collections.Generic;using UnityEngine;public class Bullet : MonoBehaviour{
public float moveSpeed = 10; public bool isPlayerBullet; // 是否敌人子弹 public AudioClip hitAudio; public void PlayAudio() {
AudioSource.PlayClipAtPoint(hitAudio,transform.position); } void Start() {
} // Update is called once per frame void Update() {
transform.Translate(transform.up * (moveSpeed * Time.deltaTime), Space.World); } // collision 子弹碰撞到的物体 private void OnTriggerEnter2D(Collider2D collision) {
switch (collision.tag) {
case "Tank": if (!isPlayerBullet) {
// 敌人子弹打到玩家die collision.SendMessage("Die"); Destroy(gameObject); } break; case "Base": collision.SendMessage("Die"); Destroy(gameObject); break; case "Enemy": if (isPlayerBullet) {
collision.SendMessage("Died"); Destroy(gameObject); } break; case "Wall": // 碰到墙销毁 Destroy(collision.gameObject); // 自身也要销毁 Destroy(gameObject); break; case "Barrier": if (isPlayerBullet) {
PlayAudio(); } // 碰到障碍 自身销毁 Destroy(gameObject); break; } }}

MapCreator.cs

using System;using System.Collections;using System.Collections.Generic;using Unity.Mathematics;using UnityEngine;using Random = UnityEngine.Random;public class MapCreator : MonoBehaviour{
// 用来装饰初始化地图所需物体的数组 // 0.base 1 wall 2.barrier 3.born 4.river 5.grass 6 airWall public GameObject[] item; // 装已经存物体的位置 private List
itemPositionList = new List
(); private void Awake() {
InitMap(); } private void CreatItem(GameObject creatGO, Vector3 cPosition, Quaternion cRotation) {
// 游戏物体,位置,旋转角度 GameObject itemGo = Instantiate(creatGO, cPosition, cRotation); // 父物体设置成装游戏物体的容器 set成当前的游戏物体 保证不会散落出来 itemGo.transform.SetParent(gameObject.transform); // 已产生的位置存放进列表 itemPositionList.Add(cPosition); } // 产生随机位置方法 private Vector3 CreatRandomPosition() {
// 不生成x=-10,10的两列,y=8,y = -8这两行的位置 while (true) {
// 声音v3接收随机生成的物体 Vector3 creatPosition = new Vector3(Random.Range(-9, 10), Random.Range(-7, 8), 0); // 在列表中有位置不返回,再次循环,无位置返回 if (!itemPositionList.Contains(creatPosition)) return creatPosition; } } // 判断位是否存在列表中 private bool IsPosition(Vector3 cP) {
for (int i = 0; i < itemPositionList.Count; i++) {
if (cP == itemPositionList[i]) {
return true; } } return false; } // 产生敌人的方法 private void CreateEnemy() {
// 随机三个位置 int num = Random.Range(0, 3); Vector3 EnemyPos; if (num == 0) {
EnemyPos = new Vector3(-10, 8, 0); } else if (num == 1) {
EnemyPos = new Vector3(0, 8, 0); } else {
EnemyPos = new Vector3(10, 8, 0); } CreatItem(item[3], EnemyPos, Quaternion.identity); } // 地图实例化的方法 private void InitMap() {
// 实例化基地 CreatItem(item[0], new Vector3(0, -8, 0), Quaternion.identity); // 用墙围基地 CreatItem(item[1], new Vector3(-1, -8, 0), Quaternion.identity); CreatItem(item[1], new Vector3(1, -8, 0), Quaternion.identity); CreatItem(item[1], new Vector3(-1, -7, 0), Quaternion.identity); CreatItem(item[1], new Vector3(0, -7, 0), Quaternion.identity); CreatItem(item[1], new Vector3(1, -7, 0), Quaternion.identity); // 格挡砖 CreatItem(item[2], new Vector3(10, -4, 0), Quaternion.identity); CreatItem(item[2], new Vector3(-10, -4, 0), Quaternion.identity); CreatItem(item[2], new Vector3(0, -5, 0), Quaternion.identity); // 实例化外围墙 最上,最下,最左,最右 for (int i = -11; i < 12; i++) {
CreatItem(item[6], new Vector3(i, 9, 0), Quaternion.identity); CreatItem(item[6], new Vector3(i, -9, 0), Quaternion.identity); } for (int i = -8; i < 9; i++) {
CreatItem(item[6], new Vector3(-11, i, 0), Quaternion.identity); CreatItem(item[6], new Vector3(11, i, 0), Quaternion.identity); } // 实例化地图 墙 障碍 河流 草 不能写在同一个for 保证均匀 for (int i = 0; i < 60; i++) {
CreatItem(item[1], CreatRandomPosition(), Quaternion.identity); } for (int i = 0; i < 17; i++) {
CreatItem(item[2], CreatRandomPosition(), Quaternion.identity); } for (int i = 0; i < 20; i++) {
CreatItem(item[4], CreatRandomPosition(), Quaternion.identity); } for (int i = 0; i < 20; i++) {
CreatItem(item[5], CreatRandomPosition(), Quaternion.identity); } // 实例化玩家和敌人 // 产生出生的特效 GameObject go = Instantiate(item[3], new Vector3(-2, -8, 0), Quaternion.identity); go.GetComponent
().createPlayer = true; // 产生敌人 随机顶部三个位置 游戏开始先产生三个敌人 CreatItem(item[3], new Vector3(-8, 8, 0), Quaternion.identity); CreatItem(item[3], new Vector3(8, 8, 0), Quaternion.identity); CreatItem(item[3], new Vector3(0, 8, 0), Quaternion.identity); // 每隔一断时间产生敌人 每隔一段时间重复调用 InvokeRepeating("CreateEnemy", 4, 5); }}

PlayerManager.cs

using System;using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.UI;using UnityEngine.SceneManagement;public class PlayerManager : MonoBehaviour{
// 玩家生命值 public int playerHP = 3; public int score = 0; public bool isDead; public bool isDefeat; // 游戏失败 public GameObject born; public Text playerHpText; public Text playerScoreText; public GameObject isDefeatUI; // 单例 private static PlayerManager instance; public static PlayerManager Instance {
get {
return instance; } set {
instance = value; } } private void Awake() {
instance = this; } void Start() {
} // Update is called once per frame void Update() {
// 如果失败,播放失败图片 if (isDefeat) {
isDefeatUI.SetActive(true); Invoke("ReturnMenu", 3); return; // 所有方法不再执行 } // 如果死亡 玩家复活 if (isDead) {
Recover(); } // 实时更新 playerScoreText.text = score.ToString(); playerHpText.text = playerHP.ToString(); } // 复活的方法 private void Recover() {
if (playerHP <= 0) {
// 游戏失败,返回主界面 isDefeat = true; // 延时3秒回到主页 Invoke("ReturnMenu", 3); } else {
playerHP--; // 并且在出生地born一次 GameObject go = Instantiate(born, new Vector3(-2, -8, 0), Quaternion.identity); go.GetComponent
().createPlayer = true; isDead = false; } } private void ReturnMenu() {
SceneManager.LoadScene("Main"); }}

Enemy.cs

using System;using System.Collections;using System.Collections.Generic;using UnityEngine;using Random = UnityEngine.Random;public class Enemy : MonoBehaviour{
public float moveSpeed = 3; // 移动速度 private Vector3 bulletEulerAngles; private float timeVal; // 子弹发射计时器 private float turnTimeVal; // 控制转向的计时器 默认为4 一产生就转向 private float v = -1; // 出生往下走 private float h; // 引用 private SpriteRenderer sr; public Sprite[] tankSprite; // 坦克精灵组 上右下左 public GameObject bulletPrefab; public GameObject explosionPrefab; // 爆炸效果 private void Awake() {
sr = GetComponent
(); } void Start() {
} // Update is called once per frame void Update() {
// 子弹攻击的时间间隔,敌人每隔一段时间射出子弹 if (timeVal >= 2) {
Attack(); } else {
timeVal += Time.deltaTime; } } // 固定物理帧 每一秒匀称的情况下 private void FixedUpdate() {
Move(); } // 坦克移动方法 private void Move() {
// 敌人一直往Base走 往Base几率更大 if (turnTimeVal >= 4) {
int num = Random.Range(0, 8); if (num > 4) {
v = -1; h = 0; } else if (num == 0) {
v = 1; h = 0; } else if (num > 0 && num <= 2) {
h = -1; v = 0; } else if (num > 2 && num <= 4) {
h = -1; v = 0; } // 归0, 否则一直旋转 turnTimeVal = 0; } else {
turnTimeVal += Time.fixedDeltaTime; } transform.Translate(Vector3.up * (v * moveSpeed * Time.fixedDeltaTime), Space.World); if (v < 0) {
sr.sprite = tankSprite[2]; bulletEulerAngles = new Vector3(0, 0, 180); // -180和正180 都是向下 } else if (v > 0) {
sr.sprite = tankSprite[0]; bulletEulerAngles = new Vector3(0, 0, 0); } if (v != 0) {
return; } transform.Translate(Vector3.right * (h * moveSpeed * Time.fixedDeltaTime), Space.World); if (h < 0) {
sr.sprite = tankSprite[3]; bulletEulerAngles = new Vector3(0, 0, 90); } else if (h > 0) {
sr.sprite = tankSprite[1]; bulletEulerAngles = new Vector3(0, 0, -90); } } // 坦克的攻击方法 自动射击 private void Attack() {
// 子弹产生的的角度等于当前坦克角度加子弹旋转角度 Instantiate(bulletPrefab, transform.position, Quaternion.Euler(transform.eulerAngles + bulletEulerAngles)); timeVal = 0; } // 坦克死亡方法 private void Died() {
// 产生爆炸特效并且玩家得分加1 PlayerManager.Instance.score++; Instantiate(explosionPrefab, transform.position, transform.rotation); // 死亡 Destroy(gameObject); } // 转换方向 如果两个坦克有触碰,顺势转换方向 private void OnCollisionEnter2D(Collision2D collision) {
if (collision.gameObject.tag == "Enemy") {
v *= -1; h *= -1; } }}

Option.cs

using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.SceneManagement; // 场景管理public class Option : MonoBehaviour{
// 选择的选项 为0 空格加载场景 为1 时指针向下移动到pos2 private int choose = 1; public Transform posOne; public Transform posTwo; void Start() {
} // Update is called once per frame void Update() {
// 监听ws 根据键盘按下的位置选择值 if (Input.GetKeyDown(KeyCode.W)||Input.GetKeyDown(KeyCode.UpArrow)) {
choose = 1; transform.position = posOne.position; } else if (Input.GetKeyDown(KeyCode.S)||Input.GetKeyDown(KeyCode.DownArrow)) {
choose = 2; transform.position = posTwo.position; } if (choose == 1 && (Input.GetKeyDown(KeyCode.Space) || Input.GetKeyDown(KeyCode.Return))) {
SceneManager.LoadScene("Game"); } }}

Base.cs

using System.Collections;using System.Collections.Generic;using UnityEngine;public class Base : MonoBehaviour{
private SpriteRenderer sr; // 控制渲染 如果被子弹碰到,消失,游戏结束 public Sprite BrokenSprite; // 爆炸效果的引用 public GameObject explosionPrefab; // base死时的音效 public AudioClip dieAudio; private void Awake() {
sr = GetComponent
(); } void Start() {
} public void Die() {
// 一调用死亡方法,切换游戏死亡图片 sr.sprite = BrokenSprite; // 图片切换后产生一个爆炸特效 Instantiate(explosionPrefab, transform.position, transform.rotation); PlayerManager.Instance.isDefeat = true; // 当前位置播放 AudioSource.PlayClipAtPoint(dieAudio,transform.position); }}

Born.cs

using System.Collections;using System.Collections.Generic;using UnityEngine;public class Born : MonoBehaviour{
// 让特效播放一度半时间消失 public GameObject playerPrefab; // 敌人数组 随机产生 public GameObject[] enemyPrefabList; public bool createPlayer; // 初始产生敌人 void Start() {
// 延时调用 Invoke("BornTank", 1); // 延时销毁 Destroy(gameObject, 1); } // Update is called once per frame void Update() {
} private void BornTank() {
if (createPlayer) {
// 出生当前位置 无旋转 Instantiate(playerPrefab, transform.position, Quaternion.identity); } else {
int num = Random.Range(0, 2); Instantiate(enemyPrefabList[num], transform.position, Quaternion.identity); } }}

Unity工程源码

GitHub:

|•’-’•) ✧上面是开发完成的工程项目,如果从0开始搭建需要资源包的话,可以私信我哟。

补充:如何加载GitHub上下载的Unity工程

需要在本地新建一个Unity工程项目,然后将下载的资源包里的Assets文件夹进行替换,重新打开新建工程就可以了。此外,浏览完整工程还需要根据项目的具体情况在File->Build Settings下对场景按照顺序进行关联

本文的坦克大战小游戏项目需要将Main场景和Game场景进行关联。

在这里插入图片描述


写在最后

感谢Trigger老师的辛勤付出!

如果代码中有我写错或者没有理解的部分,恳请指正,一起学习讨论,共同进步。
最后,祝自己早日咸鱼翻身,斩获心仪的Offer,冲呀!

转载地址:http://dhvk.baihongyu.com/

你可能感兴趣的文章