本文共 17935 字,大约阅读时间需要 59 分钟。
参考学习视频是siki学院Trigger老师的课程《如何使用unity开发坦克大战》:
感谢Trigger老师的辛勤付出! |•’-’•) ✧我在编写脚本时很多地方进行了修改和完善,和老师的教学视频稍有出入。 我使用的是Unity2019.4.0f1和Rider,其实Unity2017以上版本都可以,脚本我个人更喜欢用Rider。分别是游戏开始界面,正在游戏界面和游戏结束界面,玩家死亡3秒后返回主界面。
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); }}
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() { }}
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; } }}
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 ListitemPositionList = 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); }}
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"); }}
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; } }}
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"); } }}
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); }}
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); } }}
GitHub:
|•’-’•) ✧上面是开发完成的工程项目,如果从0开始搭建需要资源包的话,可以私信我哟。补充:如何加载GitHub上下载的Unity工程
需要在本地新建
一个Unity工程项目,然后将下载的资源包里的Assets
文件夹进行替换,重新打开新建工程就可以了。此外,浏览完整工程还需要根据项目的具体情况在File->Build Settings
下对场景按照顺序进行关联
。 本文的坦克大战小游戏项目需要将Main场景和Game场景进行关联。
感谢Trigger老师的辛勤付出!
如果代码中有我写错或者没有理解的部分,恳请指正,一起学习讨论,共同进步。 最后,祝自己早日咸鱼翻身,斩获心仪的Offer,冲呀!转载地址:http://dhvk.baihongyu.com/