赞
踩
❥ Cheer Up ❥
❥游戏说明:
❥除了音效,游戏地图上的元素有:
❀草丛(玩家可以躲进去,敌人攻击不到)
❀河流(双方都过不去,但是子弹可以穿过)
❀铁墙(坦克和子弹都过不去)
❀砖墙(一发子弹摧毁后坦克可以过去)
❀空气墙(围在地图周围,防止出界)
❀敌方大坦克(打两下才死)
❀敌方小坦克(打一下就死)
❀有玩家1和玩家2,可以选择单人/双人模式
❥地图是随机生成的,每次打开都不一样,丰富了游戏的多样性和可玩性。敌方坦克(包括大小坦克)一次最多存在3个,被摧毁后间隔3s在地图的左上/右上/上面中间 随机生成相应数量的。
❥输赢的判断:
敌方坦克数目一定,每消灭一个获得1分,消灭满20个,也就就是得分20分获得胜利,玩家自己有3生命值(即3条生命),被击中一次损失1条生命并且在出生点复活,获得3s的无敌效果。生命耗尽或者老家被摧毁,就game over。
❥可以理解为有10个类:
目录
代码如下:
- // 产生随机位置的方法
- private Vector3 CreateRandomPosition() // 列表中没有这个位置,才能产生
- {
- while(true)
- {
- // 不生成x=-13,13(变为10)这两列,y=-8,8这两行的位置
- Vector3 createPosition = new Vector3( Random.Range(-9,10), Random.Range(-7,8), 0); // x y z,Random.Range(a,b)中b的实际值是b-1
- if(!HasThePosition(createPosition))
- {
- return createPosition; // 列表中没有的位置就返回
- }
- // false 则继续循环
- }
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- public class Audio : MonoBehaviour
- {
- public AudioClip hitAudio;
-
- public void PlayAudio()
- {
- AudioSource.PlayClipAtPoint(hitAudio, transform.position);
- }
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- public class Born : MonoBehaviour
- {
- public GameObject playerPrefab; // 先拿一下玩家的引用
- public GameObject[] enemyPrefabList; // 新建一个敌人的数组:敌人预制体的列表
- public bool createPlayer; // 为了判断子弹是谁产生的(初始默认为敌人的)
-
- // Start is called before the first frame update
- void Start()
- {
- Invoke("BornTank", 1.0f); // 让游戏一开始调用一下延时Born方法
- Destroy(gameObject, 1.0f); // 经过0.8f延时0.8f销毁出生特效
- }
-
- private void BornTank()
- {
- if(createPlayer) // ture则产生玩家
- {
- Instantiate(playerPrefab, transform.position, Quaternion.identity);
- }
- else // 敌人有两种,定义一个随机数
- {
- int num = Random.Range(0,2); // 0 1(整型情况包含前两个)
- Instantiate(enemyPrefabList[num], transform.position, Quaternion.identity);
- }
- }
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- public class bullet : MonoBehaviour
- {
- public float moveSpeed = 10;
- public bool isPlayerBullet; // 默认false,不是敌人的子弹
-
- void Update()
- {
- transform.Translate(transform.up * moveSpeed * Time.deltaTime, Space.World); //让子弹沿着自身所在Y轴移动
- }
-
- //子弹碰撞检测的方法
- private void OnTriggerEnter2D(Collider2D collision)
- {
- switch (collision.tag)
- {
- case "Tank":
- if (!isPlayerBullet) // 玩家碰到敌人的子弹
- {
- collision.SendMessage("Die"); // 玩家死亡一次
- Destroy(gameObject); // 玩家死亡,自身子弹销毁
- }
- break;
- case "Heart":
- collision.SendMessage("Die"); // 老家死亡
- Destroy(gameObject); // 子弹碰老家,子弹销毁
- break;
- case "Enemy":
- if(isPlayerBullet) // 敌人碰到玩家的子弹
- {
- collision.SendMessage("Die"); // 敌人死亡一次
- Destroy(gameObject); // 敌人死亡,自身子弹销毁
- }
- break;
- case "Wall":
- Destroy(collision.gameObject); // 子弹碰到,墙就销毁
- Destroy(gameObject); // 子弹碰墙,子弹也销毁
- break;
- case "Barrier":
- if(isPlayerBullet) // 玩家的子弹才有音效
- {
- collision.SendMessage("PlayAudio");
- }
- Destroy(gameObject); // 子弹碰到不可销毁的障碍(铁墙和空气墙),子弹自身销毁
- break;
- default:
- break;
- }
-
- }
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- public class Enemy : MonoBehaviour
- {
- //属性值
- public float moveSpeed = 3;
- private Vector3 bulletEulerAngles; // 子弹应该旋转的角度
- private float v = -1;
- private float h;
-
- //引用
- private SpriteRenderer sr;
- public Sprite[] tankSprite; // 表示(上 右 下 左)方向;因为要改变精灵的值,所以设一个精灵数组(也就是拿一个和精灵值同类型的属性)
- public GameObject bulletPrefab;
- public GameObject explosionPrefab;
-
- //计时器
- private float timeVal; // 攻击CD(计时器)
- private float timeValChangeDirection; // 改变方向的时间计时器(一开始若设为4是为了使其已出现就移动)
-
-
- private void Awake() // 一般的引用在awake中赋值比较好,因为所有属性的确定和引用都应该在游戏物体一开始的时候就拿到
- {
- sr = GetComponent<SpriteRenderer>(); // 拿到了精灵渲染的组件
-
- // 接下来去控制它的图片属性就可以了
- }
-
- void Update()
- {
- // 攻击的时间间隔
- if (timeVal >= 3f)
- {
-
- }
- else
- {
-
- }
- }
-
- void FixedUpdate() // 生命周期函数,也叫固定物理帧,是在每一秒都匀称的情况下执行的
- {
- Move();
- }
-
- //坦克的攻击方法
- public void Attack()
- {
- //子弹产生的角度:当前坦克的角度+子弹应该旋转的角度(rotation中的欧拉角要转为四元数的形式表示角度)
- //子弹预制体 坦克位置 旋转角
- timeVal = 0;
- }
-
- // 坦克的移动方法
- private void Move() // 把移动代码封装成 Move()函数
- {
-
- // 下面的敌人AI只是为了控制h和v的值,下面和player一样根据值选择图片
- if(timeValChangeDirection >= 4) // 攻击一次后改变方向
- {
- int num = Random.Range(0, 8); // 多定义4个,为了让朝下的概率变大
- if(num > 5) // 向下(确保概率较大)
- {
-
- }
- else if(num == 0) // 向上(确保概率较小)
- {
-
- }
- else if (num > 0 && num <=2) // 向左
- {
-
- }
- else if (num > 2 && num <= 4) // 向右
- {
-
- }
-
- timeValChangeDirection = 0; // 归零防止鬼畜运动
- }
- else
- {
- // 因为move()的方法是放在void FixedUpdate()里面的
- }
-
-
- //控制玩家的移动,Vector3.right 表示X轴方向的移动,Y轴是up,Z轴是forward
- if (v < 0)
- {
- sr.sprite = tankSprite[2];
- bulletEulerAngles = new Vector3(0, 0, -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); //Time.deltaTime:按每秒移动;逗号右边的第二个方向是以世界坐标轴的方向
- if (h < 0)
- {
-
- }
- else if (h > 0)
- {
-
- }
- }
-
- // 坦克的死亡方法
- private void Die()
- {
- // 敌人每次死亡,就让得分+1
- PlayerManager.Instance.playerScore++;
- // 产生爆炸特效
- Instantiate(explosionPrefab, transform.position, transform.rotation);
- //死亡
- Destroy(gameObject);
- }
-
- //优化Enemy的AI:若敌人相碰,顺时针旋转一个角度,这样能避免扎堆
- private void OnCollisionEnter2D(Collision2D collision) // 坦克是碰撞检测
- {
- if(collision.gameObject.tag=="Enemy")
- {
- // 时间瞬间达到4,即刻旋转
- }
- }
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- public class Explosion : MonoBehaviour
- {
- void Start()
- {
- Destroy(gameObject, 0.167f);
- }
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- public class Heart : MonoBehaviour
- {
- private SpriteRenderer sr;
- public Sprite BrokenSprite; // 为了获取老家(Heart)被破坏时的图片
- public GameObject explosionPrefab; // 拿一下爆炸效果的引用
- public AudioClip dieAudio;
-
- void Start()
- {
- sr = GetComponent<SpriteRenderer>(); // 开始的时候就获取一下精灵渲染器组件
- }
-
- public void Die()
- {
- // 更换图片:一旦触发老家死亡效果,就更换为老家被破坏时的图片
- // 产生爆炸特效
- PlayerManager.Instance.isDefeat = true; // 被击中
- // 在某个点调用一下dieAudio
- }
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- public class MapCreation : MonoBehaviour // 地图实例化
- {
- // 用来装饰初始化地图所需物体的数组
- // 0.老家 1.墙 2.障碍 3.出生效果 4.河流 5.草 6.空气墙
- public GameObject[] item;
-
- // 已经有东西的位置列表
- private List<Vector3> itemPositionList = new List<Vector3>();
-
- private void Awake()
- {
- InitMap();
- }
-
- private void InitMap()
- {
- // 实例化老家(CreateItem其实还是用的Instantiate的方法)
- CreateItem(item[0], new Vector3(0, -8, 0), Quaternion.identity); // Quaternion.identity:无旋转
-
- //用墙把老家围起来
- CreateItem(item[1], new Vector3(-1, -8, 0), Quaternion.identity);
- CreateItem(item[1], new Vector3(1, -8, 0), Quaternion.identity);
- for (int i = -1; i < 2; i++)
- {
- CreateItem(item[1], new Vector3(i, -7, 0), Quaternion.identity);
- }
-
- // 实例化外围墙 x=-14,14(变为11),y=-9,9
- for (int i = -11; i < 12; i++) //最上面一行
- {
- CreateItem(item[6], new Vector3(i, 9, 0), Quaternion.identity);
- }
- for (int i = -11; i < 12; i++) //最下面一行
- {
- CreateItem(item[6], new Vector3(i, -9, 0), Quaternion.identity);
- }
- for (int i = -8; i < 9; i++) //最左面一行
- {
- CreateItem(item[6], new Vector3(-11, i, 0), Quaternion.identity);
- }
- for (int i = -8; i < 9; i++) //最右面一行
- {
- CreateItem(item[6], new Vector3(11, i, 0), Quaternion.identity);
- }
-
- // 初始化玩家(通过实例化出生特效实例化玩家)
- GameObject go = Instantiate(item[3], new Vector3(-2, -8, 0), Quaternion.identity); // 产生出生特效
- go.GetComponent<Born>().createPlayer = true;// 特效上的bool值设置为true:产生玩家
-
- // 产生敌人(在固定的三个位置先产生,之后每隔一段时间在三个位置随机产生)
- CreateItem(item[3], new Vector3(-10, 8, 0), Quaternion.identity);
- CreateItem(item[3], new Vector3(0, 8, 0), Quaternion.identity);
- CreateItem(item[3], new Vector3(10, 8, 0), Quaternion.identity);
-
- InvokeRepeating("CreateEnemy", 4, 5);
-
- // 实例化地图
- for (int i = 0; i < 60; i++)
- {
- CreateItem(item[1], CreateRandomPosition(), Quaternion.identity);
- }
- for (int i = 0; i < 20; i++)
- {
- CreateItem(item[2], CreateRandomPosition(), Quaternion.identity);
- }
- for (int i = 0; i < 20; i++)
- {
- CreateItem(item[4], CreateRandomPosition(), Quaternion.identity);
- }
- for (int i = 0; i < 20; i++)
- {
- CreateItem(item[5], CreateRandomPosition(), Quaternion.identity);
- }
-
- }
-
-
- private void CreateItem(GameObject createGameObject,Vector3 createPosition,Quaternion createRotation) // 封装一个方法:使播放时Hierarchy菜单下的东西不散落
- {
- // 根据上面的参数实例化游戏物体
- // Parent是当前的游戏物体
- // 把所有出现过的物体位置存进位置列表
- }
-
-
- // 产生随机位置的方法
- private Vector3 CreateRandomPosition() // 列表中没有这个位置,才能产生
- {
- while(true)
- {
- // 不生成x=-13,13(变为10)这两列,y=-8,8这两行的位置
- Vector3 createPosition = new Vector3( Random.Range(-9,10), Random.Range(-7,8), 0); // x y z,Random.Range(a,b)中b的实际值是b-1
- if(!HasThePosition(createPosition))
- {
- return createPosition; // 列表中没有的位置就返回
- }
- // false 则继续循环
- }
- }
-
-
- // 用来判断位置列表中是否有这个位置
- private bool HasThePosition(Vector3 createPos)
- {
- for (int i = 0; i < itemPositionList.Count; i++) // 遍历当前的位置列表
- {
- if(createPos == itemPositionList[i]) // 如果随机产生位置的值等于当前列表某个位置的值
- {
- return true;
- }
- }
- return false;
- }
-
-
- // 产生敌人的方法
- private void CreateEnemy()
- {
- int num = Random.Range(0, 3); // 0 1 2
- Vector3 EnemyPos = new Vector3(); // 装随机产生的位置:向量/坐标
- if (num == 0)
- {
-
- }
- else if (num == 1)
- {
-
- }
- else
- {
-
- }
- CreateItem(item[3], EnemyPos, Quaternion.identity);
- }
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.SceneManagement;
-
- public class Option : MonoBehaviour
- {
- private int choice = 1;
- public Transform posOne;
- public Transform posTwo;
-
- // Update is called once per frame
- void Update()
- {
- // 监听开始界面上下移动的选项
- if (Input.GetKeyDown(KeyCode.W))
- {
- choice = 1;
- transform.position = posOne.position;
- }
- else if (Input.GetKeyDown(KeyCode.S))
- {
- choice = 2;
- transform.position = posTwo.position;
- }
- if (choice==1 && Input.GetKeyDown(KeyCode.Space))
- {
- SceneManager.LoadScene(1); // 加载 Main 场景
- }
- }
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- public class Player : MonoBehaviour {
-
- //属性值
- public float moveSpeed = 3;
- private Vector3 bulletEulerAngles; // 子弹应该旋转的角度
- private float timeVal; // 攻击CD(计时器)
- private float defendTimeVal = 3; // 无敌CD(计时器)
- private bool isDefended = true; // 无敌状态
-
- //引用
- // 拿到渲染器
- // 拿到需要用到的图片,(上 右 下 左)方向;因为要改变精灵的值,所以设一个精灵数组(也就是拿一个和精灵值同类型的属性)
- public GameObject bulletPrefab;
- public GameObject explosionPrefab;
- public GameObject defendEffectPrefab;
- // 控制音效的播放
- // 拿到音效播放的资源
-
- private void Awake() // 一般的引用在awake中赋值比较好,因为所有属性的确定和引用都应该在游戏物体一开始的时候就拿到
- {
- // 拿到了精灵渲染的组件
-
- // 接下来去控制它的图片属性就可以了
- }
-
- void Update()
- {
- // 无敌CD
- if(isDefended)
- {
- defendEffectPrefab.SetActive(true); // 控制无敌状态时护盾打开
- defendTimeVal -= Time.deltaTime;
- if(defendTimeVal <= 0)
- {
- isDefended = false;
- // 控制无敌状态时护盾关闭
- }
- }
- }
-
- private void FixedUpdate() {// 生命周期函数,也叫固定物理帧,是在每一秒都匀称的情况下执行的
-
- if(PlayerManager.Instance.isDefeat)
- {
- return; // true则return:游戏失败,禁止玩家所有操作
- }
- Move();
-
- // 攻击CD
- if (timeVal >= 0.4f)
- {
- Attack();
- }
- else
- {
- timeVal += Time.fixedDeltaTime;
- }
- }
-
-
- //坦克的攻击方法
- public void Attack()
- {
- if() //若检测到玩家输入为空格键
- {
- //子弹产生的角度:当前坦克的角度+子弹应该旋转的角度(rotation中的欧拉角要转为四元数的形式表示角度)
- //子弹预制体 坦克位置 旋转角
- timeVal = 0;
- }
- }
-
-
- // 坦克的移动方法
- private void Move() // 把移动代码封装成 Move()函数
- {
- // 监听玩家垂直轴值的输入
- transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);
-
- if (v < 0) {
-
- }
- else if (v > 0) {
-
- }
-
- // v和h不为0,播放...音效 (在判断v是否为0之前判断是考虑了它的优先级)
- if(Mathf.Abs(v)>0.05f)
- {
- // 若音效播放时又调用,声音会很杂,所以要判断...
- if(!moveAudio.isPlaying)
- {
- moveAudio.Play();
- }
- }
-
- if (v != 0) { // 确保按照上下移动的同时不能进行左右移动
- return;
- }
-
- //监听玩家水平轴值的输入h来控制在X轴上的位移的方向,按右方向为1,左为-1
-
- //控制玩家的移动,Vector3.right 表示X轴方向的移动,Y轴是up,Z轴是forward
- transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World); //Time.deltaTime:按每秒移动;逗号右边的第二个方向是以世界坐标轴的方向
- if (h < 0) {
-
- }
- else if (h > 0) {
-
- }
-
- 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 Die()
- {
- // 是否处于无敌状态
- if (isDefended)
- {
- return;
- }
- // 击中的话,就让玩家管理里面的属性变为true
- PlayerManager.Instance.isDead = true;
-
- // 产生爆炸特效
- Instantiate(explosionPrefab, transform.position, transform.rotation);
- //死亡
- Destroy(gameObject);
- }
-
- }
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.AI;
- using UnityEngine.UI; // 为了更新 UI,拿一下它的引用,使用 UI,就要拿一下Unity的运营空间
- using UnityEngine.SceneManagement;
-
- public class PlayerManager : MonoBehaviour
- {
- //属性值
- public int lifeValue = 3;
- public int playerScore = 0;
- public bool isDead;
- public bool isDefeat;
-
- //引用
- public GameObject born;
- public Text playerScoreText;
- public Text playerLifeValueText;
- public GameObject isDefeatUI; // 拿一下游戏物体的引用
-
- //单例
- private static PlayerManager instance;
- public static PlayerManager Instance { get => instance; set => instance = value; }
-
- private void Awake()
- {
- Instance = this;
- }
-
- // Update is called once per frame
- void Update() // 在其中实时监听一些状态
- {
- if(isDefeat) // 失败的话
- {
- isDefeatUI.SetActive(true); // 让失败的图片显示
- return;
- }
-
- if(isDead) // 如果死亡
- {
- Recover();
- }
-
- // 实时更新消灭敌人的显示和生命值
- playerScoreText.text = playerScore.ToString(); // .ToString():把int转化为字符串
- playerLifeValueText.text = lifeValue.ToString();
- }
-
- private void Recover()
- {
- if (lifeValue<=0)
- {
- // 游戏失败,返回主界面
- isDefeat = true;
- Invoke("ReturnToTheMainMenu", 3); // 延时3s调用这个方法
- }
- else
- {
- lifeValue --;
- GameObject go = Instantiate(born, new Vector3(-2, -7.9f, 0), Quaternion.identity); // 接收born的脚本
- go.GetComponent<Born>().createPlayer = true;
- isDead = false;
- }
- }
-
- private void ReturnToTheMainMenu()
- {
- SceneManager.LoadScene(0); // 返回开始界面
- }
-
- }
完结,撒花❀~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。