2D坦克大战 像素版
游戏规则:
玩家通过上、下、左、右移动坦克,空格键发射子弹
敌人AI出身时朝向己方大本营(未防止游戏快速结束,心脏上方三个单位障碍物设为刚体)
当玩家被击杀次数>=3 或 心脏被子弹击穿 重新加载游戏场景
控制游戏每4秒发射一颗子弹(可自己做修改)
游戏项目已托管到Github上 传送门
(文章最下边有游戏脚本)
场景搭建
设置Main Camera摄像头参数
游戏中制作预制体与动画
创建一个Cube作为参照,Cube长宽高都为1m
创建一个Player1_0作为玩家
将Player1_0制作成预制体
制作游戏砖块、钢铁、草丛、基地预制体
创建游戏物体出生动画Animation
快速创建动画:点击第一张图片->按住Shift->点击最后一张图片
保存好后场景出现Born_0动画,修改scale大小为3 3 3
制作坦克出生无敌、坦克爆炸、河流特效
动画大小与预制体适配
控制玩家的移动
添加Player.cs脚本,绑定到Player玩家坦克上
默认移动速度
public float moveSpeed = 3;
监听玩家水平轴输入
float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right*h*moveSpeed*Time.deltaTime,Space.World);
监听玩家垂直轴输入
float v = Input.GetAxisRaw("Vertical");transform.Translate(Vector3.up * v * moveSpeed * Time.deltaTime, Space.World);
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Player : MonoBehaviour {public float moveSpeed = 3;// Use this for initializationvoid Start () {}// Update is called once per framevoid Update () {//监听玩家水平轴输入float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1transform.Translate(Vector3.right*h*moveSpeed*Time.deltaTime,Space.World);//监听玩家垂直轴输入float v = Input.GetAxisRaw("Vertical");transform.Translate(Vector3.up * v * moveSpeed * Time.deltaTime, Space.World);} }
控制图片的移动和切换
制作坦克渲染
添加精灵数组的引用
private SpriteRenderer sr;public Sprite[] tankSprite;
(上 右 下 左)
玩家按上下左右控制坦克方向的移动
//监听玩家水平轴输入float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1transform.Translate(Vector3.right*h*moveSpeed*Time.deltaTime,Space.World);if (h < 0){sr.sprite = tankSprite[3];}else if (h>0){sr.sprite = tankSprite[1];}//监听玩家垂直轴输入float v = Input.GetAxisRaw("Vertical");transform.Translate(Vector3.up * v * moveSpeed * Time.deltaTime, Space.World);if (v < 0){sr.sprite = tankSprite[2];}else if (v > 0){sr.sprite = tankSprite[0];}
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Player : MonoBehaviour {public float moveSpeed = 3;private SpriteRenderer sr;public Sprite[] tankSprite; //上 右 下 左// Use this for initializationvoid Start () {sr = GetComponent<SpriteRenderer>();}// Update is called once per framevoid Update () {//监听玩家水平轴输入float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1transform.Translate(Vector3.right*h*moveSpeed*Time.deltaTime,Space.World);if (h < 0){sr.sprite = tankSprite[3];}else if (h>0){sr.sprite = tankSprite[1];}//监听玩家垂直轴输入float v = Input.GetAxisRaw("Vertical");transform.Translate(Vector3.up * v * moveSpeed * Time.deltaTime, Space.World);if (v < 0){sr.sprite = tankSprite[2];}else if (v > 0){sr.sprite = tankSprite[0];}} }
碰撞器的添加
碰撞检测
两个物体都有碰撞器
一个物体上挂载刚体组件
给玩家Player添加2D刚体和2D碰撞器
刚体的Gravity Scale设置为0,取消重力因素的影响
给Barriar、Wall、River、Heart添加Box Collider 2D碰撞器
发现坦克方向坐标轴会改变,在Rigidbody 2D中Constraints下的Freeze Rotation Z 进行绑定,当它碰撞到物体时坐标不发生偏移
解决抖动问题
使用private void FixedUpdate()
FixedUpdate () 和 Update () 同:当MonoBehaviour启用时,其在每一帧被调用。都是用来更新的异:Update()每一帧的时间不固定,即第一帧与第二帧的时间t1和第三帧与第四帧的时间t2不一定相同。FixedUpdate()每帧与每帧之间相差的时间是固定的.Update受当前渲染的物体影响,这与当前场景中正在被渲染的物体有关(比如人物的面数,个数等),有时快有时慢,帧率会变化,Update被调用的时间间隔就会发生变化。但是FixedUpdate则不受帧率的变化影响,它是以固定的时间间隔来被调用。所以一些物理属性的更新操作应该放在FxiedUpdate中操作,比如Force,Collider,Rigidbody等。外设的操作也是,比如说键盘或者鼠标的输入输出Input,因为这样GameObject的物理表现的更平滑,更接近现实。FixedUpdate的时间间隔可以在项目设置中更改,Edit->Project Setting->time 找到Fixed timestep。就可以修改了
//监听玩家水平轴输入float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1transform.Translate(Vector3.right*h*moveSpeed*Time.fixedDeltaTime,Space.World);//监听玩家垂直轴输入float v = Input.GetAxisRaw("Vertical");transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);
FixedUpdate()方法留空就行
private void FixedUpdate(){}
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Player : MonoBehaviour {public float moveSpeed = 3;private SpriteRenderer sr;public Sprite[] tankSprite; //上 右 下 左// Use this for initializationvoid Start () {sr = GetComponent<SpriteRenderer>();}// Update is called once per framevoid Update () {//监听玩家水平轴输入float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1transform.Translate(Vector3.right*h*moveSpeed*Time.fixedDeltaTime,Space.World);if (h < 0){sr.sprite = tankSprite[3];}else if (h>0){sr.sprite = tankSprite[1];}//监听玩家垂直轴输入float v = Input.GetAxisRaw("Vertical");transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);if (v < 0){sr.sprite = tankSprite[2];}else if (v > 0){sr.sprite = tankSprite[0];}}// private void FixedUpdate(){} }
解决玩家按方向键左右的同时按上下
在监听玩家垂直轴输入后对v方向按键进行判断,如果为0则在Update()中直接返回
float v = Input.GetAxisRaw("Vertical");transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);if (v < 0){sr.sprite = tankSprite[2];}else if (v > 0){sr.sprite = tankSprite[0];}if(v!=0){return;}//监听玩家水平轴输入float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1transform.Translate(Vector3.right*h*moveSpeed*Time.fixedDeltaTime,Space.World);if (h < 0){sr.sprite = tankSprite[3];}else if (h>0){sr.sprite = tankSprite[1];}
整理一下Player.cs脚本
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Player : MonoBehaviour {//属性值public float moveSpeed = 3;//引用private SpriteRenderer sr;public Sprite[] tankSprite; //上 右 下 左// Use this for initializationvoid Start () {sr = GetComponent<SpriteRenderer>();}// Update is called once per framevoid Update () {}private void FixedUpdate(){Move();}//坦克的移动方法private void Move(){//监听玩家垂直轴输入float v = Input.GetAxisRaw("Vertical");transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);if (v < 0){sr.sprite = tankSprite[2];}else if (v > 0){sr.sprite = tankSprite[0];}if (v != 0){return;}//监听玩家水平轴输入float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World);if (h < 0){sr.sprite = tankSprite[3];}else if (h > 0){sr.sprite = tankSprite[1];}} }
2D渲染层级
设置游戏物体的层级
坦克的攻击
坦克的攻击方法
private void Attack(){if(Input.GetKeyDown(KeyCode.Space)){Instantiate(bullectPrefab,transform.position,transform.rotation);}}
private void FixedUpdate(){Move();Attack();}
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Player : MonoBehaviour {//属性值public float moveSpeed = 3;//引用private SpriteRenderer sr;public Sprite[] tankSprite; //上 右 下 左public GameObject bullectPrefab;// Use this for initializationvoid Start () {sr = GetComponent<SpriteRenderer>();}// Update is called once per framevoid Update () {}private void FixedUpdate(){Move();Attack();}//坦克的攻击方法private void Attack(){if(Input.GetKeyDown(KeyCode.Space)){Instantiate(bullectPrefab,transform.position,transform.rotation);}}//坦克的移动方法private void Move(){//监听玩家垂直轴输入float v = Input.GetAxisRaw("Vertical");transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);if (v < 0){sr.sprite = tankSprite[2];}else if (v > 0){sr.sprite = tankSprite[0];}if (v != 0){return;}//监听玩家水平轴输入float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World);if (h < 0){sr.sprite = tankSprite[3];}else if (h > 0){sr.sprite = tankSprite[1];}} }
子弹的朝向和移动
通过按键V和H来判断子弹旋转的角度
定义子弹旋转的角度
private Vector3 bullectEulerAugles;
子弹参数的角度:当前坦克的角度+子弹应该旋转的角度
Instantiate(bullectPrefab,transform.position,Quaternion.Euler(transform.eulerAngles+bullectEulerAugles));
---恢复内容结束---
未完~
完成时会有完整项目展示
场景搭建
设置Main Camera摄像头参数
游戏中制作预制体与动画
创建一个Cube作为参照,Cube长宽高都为1m
创建一个Player1_0作为玩家
将Player1_0制作成预制体
制作游戏砖块、钢铁、草丛、基地预制体
创建游戏物体出生动画Animation
快速创建动画:点击第一张图片->按住Shift->点击最后一张图片
保存好后场景出现Born_0动画,修改scale大小为3 3 3
制作坦克出生无敌、坦克爆炸、河流特效
动画大小与预制体适配
控制玩家的移动
添加Player.cs脚本,绑定到Player玩家坦克上
默认移动速度
public float moveSpeed = 3;
监听玩家水平轴输入
float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.Translate(Vector3.right*h*moveSpeed*Time.deltaTime,Space.World);
监听玩家垂直轴输入
float v = Input.GetAxisRaw("Vertical");transform.Translate(Vector3.up * v * moveSpeed * Time.deltaTime, Space.World);
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Player : MonoBehaviour {public float moveSpeed = 3;// Use this for initializationvoid Start () {}// Update is called once per framevoid Update () {//监听玩家水平轴输入float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1transform.Translate(Vector3.right*h*moveSpeed*Time.deltaTime,Space.World);//监听玩家垂直轴输入float v = Input.GetAxisRaw("Vertical");transform.Translate(Vector3.up * v * moveSpeed * Time.deltaTime, Space.World);} }
控制图片的移动和切换
制作坦克渲染
添加精灵数组的引用
private SpriteRenderer sr;public Sprite[] tankSprite;
(上 右 下 左)
玩家按上下左右控制坦克方向的移动
//监听玩家水平轴输入float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1transform.Translate(Vector3.right*h*moveSpeed*Time.deltaTime,Space.World);if (h < 0){sr.sprite = tankSprite[3];}else if (h>0){sr.sprite = tankSprite[1];}//监听玩家垂直轴输入float v = Input.GetAxisRaw("Vertical");transform.Translate(Vector3.up * v * moveSpeed * Time.deltaTime, Space.World);if (v < 0){sr.sprite = tankSprite[2];}else if (v > 0){sr.sprite = tankSprite[0];}
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Player : MonoBehaviour {public float moveSpeed = 3;private SpriteRenderer sr;public Sprite[] tankSprite; //上 右 下 左// Use this for initializationvoid Start () {sr = GetComponent<SpriteRenderer>();}// Update is called once per framevoid Update () {//监听玩家水平轴输入float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1transform.Translate(Vector3.right*h*moveSpeed*Time.deltaTime,Space.World);if (h < 0){sr.sprite = tankSprite[3];}else if (h>0){sr.sprite = tankSprite[1];}//监听玩家垂直轴输入float v = Input.GetAxisRaw("Vertical");transform.Translate(Vector3.up * v * moveSpeed * Time.deltaTime, Space.World);if (v < 0){sr.sprite = tankSprite[2];}else if (v > 0){sr.sprite = tankSprite[0];}} }
碰撞器的添加
碰撞检测
两个物体都有碰撞器
一个物体上挂载刚体组件
给玩家Player添加2D刚体和2D碰撞器
刚体的Gravity Scale设置为0,取消重力因素的影响
给Barriar、Wall、River、Heart添加Box Collider 2D碰撞器
发现坦克方向坐标轴会改变,在Rigidbody 2D中Constraints下的Freeze Rotation Z 进行绑定,当它碰撞到物体时坐标不发生偏移
解决抖动问题
使用private void FixedUpdate()
FixedUpdate () 和 Update () 同:当MonoBehaviour启用时,其在每一帧被调用。都是用来更新的异:Update()每一帧的时间不固定,即第一帧与第二帧的时间t1和第三帧与第四帧的时间t2不一定相同。FixedUpdate()每帧与每帧之间相差的时间是固定的.Update受当前渲染的物体影响,这与当前场景中正在被渲染的物体有关(比如人物的面数,个数等),有时快有时慢,帧率会变化,Update被调用的时间间隔就会发生变化。但是FixedUpdate则不受帧率的变化影响,它是以固定的时间间隔来被调用。所以一些物理属性的更新操作应该放在FxiedUpdate中操作,比如Force,Collider,Rigidbody等。外设的操作也是,比如说键盘或者鼠标的输入输出Input,因为这样GameObject的物理表现的更平滑,更接近现实。FixedUpdate的时间间隔可以在项目设置中更改,Edit->Project Setting->time 找到Fixed timestep。就可以修改了
//监听玩家水平轴输入float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1transform.Translate(Vector3.right*h*moveSpeed*Time.fixedDeltaTime,Space.World);//监听玩家垂直轴输入float v = Input.GetAxisRaw("Vertical");transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);
FixedUpdate()方法留空就行
private void FixedUpdate(){}
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Player : MonoBehaviour {public float moveSpeed = 3;private SpriteRenderer sr;public Sprite[] tankSprite; //上 右 下 左// Use this for initializationvoid Start () {sr = GetComponent<SpriteRenderer>();}// Update is called once per framevoid Update () {//监听玩家水平轴输入float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1transform.Translate(Vector3.right*h*moveSpeed*Time.fixedDeltaTime,Space.World);if (h < 0){sr.sprite = tankSprite[3];}else if (h>0){sr.sprite = tankSprite[1];}//监听玩家垂直轴输入float v = Input.GetAxisRaw("Vertical");transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);if (v < 0){sr.sprite = tankSprite[2];}else if (v > 0){sr.sprite = tankSprite[0];}}// private void FixedUpdate(){} }
解决玩家按方向键左右的同时按上下
在监听玩家垂直轴输入后对v方向按键进行判断,如果为0则在Update()中直接返回
float v = Input.GetAxisRaw("Vertical");transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);if (v < 0){sr.sprite = tankSprite[2];}else if (v > 0){sr.sprite = tankSprite[0];}if(v!=0){return;}//监听玩家水平轴输入float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1transform.Translate(Vector3.right*h*moveSpeed*Time.fixedDeltaTime,Space.World);if (h < 0){sr.sprite = tankSprite[3];}else if (h>0){sr.sprite = tankSprite[1];}
整理一下Player.cs脚本
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Player : MonoBehaviour {//属性值public float moveSpeed = 3;//引用private SpriteRenderer sr;public Sprite[] tankSprite; //上 右 下 左// Use this for initializationvoid Start () {sr = GetComponent<SpriteRenderer>();}// Update is called once per framevoid Update () {}private void FixedUpdate(){Move();}//坦克的移动方法private void Move(){//监听玩家垂直轴输入float v = Input.GetAxisRaw("Vertical");transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);if (v < 0){sr.sprite = tankSprite[2];}else if (v > 0){sr.sprite = tankSprite[0];}if (v != 0){return;}//监听玩家水平轴输入float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World);if (h < 0){sr.sprite = tankSprite[3];}else if (h > 0){sr.sprite = tankSprite[1];}} }
2D渲染层级
设置游戏物体的层级
坦克的攻击
坦克的攻击方法
private void Attack(){if(Input.GetKeyDown(KeyCode.Space)){Instantiate(bullectPrefab,transform.position,transform.rotation);}}
private void FixedUpdate(){Move();Attack();}
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Player : MonoBehaviour {//属性值public float moveSpeed = 3;//引用private SpriteRenderer sr;public Sprite[] tankSprite; //上 右 下 左public GameObject bullectPrefab;// Use this for initializationvoid Start () {sr = GetComponent<SpriteRenderer>();}// Update is called once per framevoid Update () {}private void FixedUpdate(){Move();Attack();}//坦克的攻击方法private void Attack(){if(Input.GetKeyDown(KeyCode.Space)){Instantiate(bullectPrefab,transform.position,transform.rotation);}}//坦克的移动方法private void Move(){//监听玩家垂直轴输入float v = Input.GetAxisRaw("Vertical");transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);if (v < 0){sr.sprite = tankSprite[2];}else if (v > 0){sr.sprite = tankSprite[0];}if (v != 0){return;}//监听玩家水平轴输入float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World);if (h < 0){sr.sprite = tankSprite[3];}else if (h > 0){sr.sprite = tankSprite[1];}} }
子弹的朝向和移动
通过按键V和H来判断子弹旋转的角度
定义子弹旋转的角度
private Vector3 bullectEulerAugles;
子弹参数的角度:当前坦克的角度+子弹应该旋转的角度
Instantiate(bullectPrefab,transform.position,Quaternion.Euler(transform.eulerAngles+bullectEulerAugles));
private void Attack(){if(Input.GetKeyDown(KeyCode.Space)){//子弹参数的角度:当前坦克的角度+子弹应该旋转的角度Instantiate(bullectPrefab,transform.position,Quaternion.Euler(transform.eulerAngles+bullectEulerAugles));timeVal = 0;}}
给子弹添加方向速度
public float moveSpeed = 10;
给子弹添加判断是否是友军
public bool isPlayerBullect;
void Update () {transform.Translate(transform.up*moveSpeed*Time.deltaTime,Space.World);}
添加子弹攻击CD间隔
if (timeVal>=0.4f){//间隔大于0.4的时候才有攻击效果 Attack();}else{timeVal += Time.deltaTime;}
给组件添加标签
给子弹添加碰撞体和触发器
添加Heart.cs脚本,当Heart心脏被子弹攻击时,切换死亡图片
private SpriteRenderer sr;public Sprite BrokenSprite; // Use this for initializationvoid Start () {sr = GetComponent<SpriteRenderer>();}
添加Heart.cs心脏死亡时方法
private void Die(){sr.sprite = BrokenSprite; }
添加Explosion.cs脚本
当坦克销毁时触发脚本
public class Explosion : MonoBehaviour {// Use this for initializationvoid Start () {//坦克销毁后0.167秒销毁爆炸特效Destroy(gameObject,0.167f);}// Update is called once per framevoid Update () {} }
子弹触发碰撞检测
当子弹碰撞到物体时触发OnTriggerEnter2D(Collider2D collision)方法
子弹碰到“Tank”判断是否是友军,不是的话击毁自己
子弹碰到"Wall"时,销毁子弹自身
子弹碰到"Heart"时,触发基地死亡方法
子弹碰到"Barrier"刚体时,销毁子弹
private void OnTriggerEnter2D(Collider2D collision){switch(collision.tag){case "Tank":if(!isPlayerBullect){collision.SendMessage("Die");}break;case "Heart":collision.SendMessage("Die");Destroy(gameObject);break;case "Enemy":break;case "Wall"://销毁自身和墙 Destroy(collision.gameObject);Destroy(gameObject);break;case "Barrier":Destroy(gameObject);break;default:break;}}
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Player : MonoBehaviour {//属性值public float moveSpeed = 3;private Vector3 bullectEulerAugles;public float timeVal;private float defendTimeVal=1;private bool isDefended=true;//引用private SpriteRenderer sr;public Sprite[] tankSprite; //上 右 下 左public GameObject bullectPrefab;public GameObject explosionPrefab;public GameObject defendEffectPrefab;// Use this for initializationvoid Start () {sr = GetComponent<SpriteRenderer>();}// Update is called once per framevoid Update () {//保护是否处于无敌状态if(isDefended){defendEffectPrefab.SetActive(true);defendTimeVal -= Time.deltaTime;if (defendTimeVal<=0){isDefended = false;defendEffectPrefab.SetActive(false);}}//攻击的CDif (timeVal>=0.4f){//间隔大于0.4的时候才有攻击效果 Attack();}else{timeVal += Time.deltaTime;}}private void FixedUpdate(){Move();}//坦克的攻击方法private void Attack(){if(Input.GetKeyDown(KeyCode.Space)){//子弹参数的角度:当前坦克的角度+子弹应该旋转的角度Instantiate(bullectPrefab,transform.position,Quaternion.Euler(transform.eulerAngles+bullectEulerAugles));timeVal = 0;}}//坦克的移动方法private void Move(){//监听玩家垂直轴输入float v = Input.GetAxisRaw("Vertical");transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);if (v < 0){sr.sprite = tankSprite[2];bullectEulerAugles = new Vector3(0, 0, -180);}else if (v > 0){sr.sprite = tankSprite[0];bullectEulerAugles = new Vector3(0, 0, 0);}if (v != 0){return;}//监听玩家水平轴输入float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World);if (h < 0){sr.sprite = tankSprite[3];bullectEulerAugles = new Vector3(0, 0, 90);}else if (h > 0){sr.sprite = tankSprite[1];bullectEulerAugles = new Vector3(0, 0, -90);}}//坦克的死亡方法private void Die(){if(isDefended){return;}//产生爆炸特效 Instantiate(explosionPrefab, transform.position, transform.rotation);//死亡 Destroy(gameObject);} }
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Explosion : MonoBehaviour {// Use this for initializationvoid Start () {//坦克销毁后0.167秒销毁爆炸特效Destroy(gameObject,0.167f);}// Update is called once per framevoid Update () {} }
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Heart : MonoBehaviour {private SpriteRenderer sr;public Sprite BrokenSprite; // Use this for initializationvoid Start () {sr = GetComponent<SpriteRenderer>();}private void Die(){sr.sprite = BrokenSprite; } }
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Bullect : MonoBehaviour {public float moveSpeed = 10;public bool isPlayerBullect;// Use this for initializationvoid Start () {}// Update is called once per framevoid Update () {transform.Translate(transform.up*moveSpeed*Time.deltaTime,Space.World);}//子弹触发碰撞检测private void OnTriggerEnter2D(Collider2D collision){switch(collision.tag){case "Tank":if(!isPlayerBullect){collision.SendMessage("Die");}break;case "Heart":collision.SendMessage("Die");Destroy(gameObject);break;case "Enemy":break;case "Wall"://销毁自身和墙 Destroy(collision.gameObject);Destroy(gameObject);break;case "Barrier":Destroy(gameObject);break;default:break;}}}
敌人的制作
Ctrl+D一份玩家,修改图片渲染,制作敌人
添加敌人脚本Enemy.cs
玩家的移动和敌人的移动差不多,把Player.cs脚本中内容复制到Enemy.cs当中
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Enemy : MonoBehaviour {//属性值public float moveSpeed = 3;private Vector3 bullectEulerAugles;public float timeVal;private float defendTimeVal = 1;private bool isDefended = true;//引用private SpriteRenderer sr;public Sprite[] tankSprite; //上 右 下 左public GameObject bullectPrefab;public GameObject explosionPrefab;public GameObject defendEffectPrefab;// Use this for initializationvoid Start(){sr = GetComponent<SpriteRenderer>();}// Update is called once per framevoid Update(){//保护是否处于无敌状态if (isDefended){defendEffectPrefab.SetActive(true);defendTimeVal -= Time.deltaTime;if (defendTimeVal <= 0){isDefended = false;defendEffectPrefab.SetActive(false);}}//攻击的CDif (timeVal >= 0.4f){//间隔大于0.4的时候才有攻击效果 Attack();}else{timeVal += Time.deltaTime;}}private void FixedUpdate(){Move();}//坦克的攻击方法private void Attack(){if (Input.GetKeyDown(KeyCode.Space)){//子弹参数的角度:当前坦克的角度+子弹应该旋转的角度Instantiate(bullectPrefab, transform.position, Quaternion.Euler(transform.eulerAngles + bullectEulerAugles));timeVal = 0;}}//坦克的移动方法private void Move(){//监听玩家垂直轴输入float v = Input.GetAxisRaw("Vertical");transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);if (v < 0){sr.sprite = tankSprite[2];bullectEulerAugles = new Vector3(0, 0, -180);}else if (v > 0){sr.sprite = tankSprite[0];bullectEulerAugles = new Vector3(0, 0, 0);}if (v != 0){return;}//监听玩家水平轴输入float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World);if (h < 0){sr.sprite = tankSprite[3];bullectEulerAugles = new Vector3(0, 0, 90);}else if (h > 0){sr.sprite = tankSprite[1];bullectEulerAugles = new Vector3(0, 0, -90);}}//坦克的死亡方法private void Die(){if (isDefended){return;}//产生爆炸特效 Instantiate(explosionPrefab, transform.position, transform.rotation);//死亡 Destroy(gameObject);} }
(因为敌人没有出生无敌3s,运行时无敌预制体defendEffectPrefab会出现报空)
添加基地死亡时动画
public GameObject explosionPrefab;
private void Die(){sr.sprite = BrokenSprite;Instantiate(explosionPrefab,transform.position,transform.rotation);}
(关闭项目后爆炸脚本失活了,最后的时候再做一个补上)
添加一个玩家出生时脚本Born.cs
延时玩家出生和死亡动画
public GameObject playerPrefab;// Use this for initializationvoid Start () {Invoke("BornTank",1f);Destroy(gameObject,1f);}private void BornTank(){Instantiate(playerPrefab,transform.position,Quaternion.identity);}
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Born : MonoBehaviour {public GameObject playerPrefab;// Use this for initializationvoid Start () {Invoke("BornTank",0.8f);Destroy(gameObject,0.8f);}// Update is called once per framevoid Update () {}private void BornTank(){Instantiate(playerPrefab,transform.position,Quaternion.identity);} }
制作大坦克和小坦克,添加坦克方向变化时改变坦克方向图片
坦克改变方向顺序按上、右、下、左进行添加
小敌人同打敌人设置当坦克方向改变时切换自身图片
将大敌人和小敌人设置成预制体
小敌人速度调大一些,改为5
编写Born.cs脚本判断是否产生敌人
public bool createPlay;
private void BornTank(){if (createPlay){Instantiate(playerPrefab, transform.position, Quaternion.identity);}else{int num = Random.Range(0, 2);Instantiate(enemyPrefabList[num], transform.position, Quaternion.identity);}}
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Born : MonoBehaviour {public GameObject playerPrefab;public GameObject[] enemyPrefabList;//判断是否产生敌人public bool createPlay;// Use this for initializationvoid Start () {Invoke("BornTank",1f);Destroy(gameObject,1f);}private void Update(){}private void BornTank(){if (createPlay){Instantiate(playerPrefab, transform.position, Quaternion.identity);}else{int num = Random.Range(0, 2);Instantiate(enemyPrefabList[num], transform.position, Quaternion.identity);}} }
编写敌人AI
子弹间3s攻击一次
void Update(){//攻击的时间间隔if (timeVal >= 0.3f){//间隔大于0.4的时候才有攻击效果 Attack();}else{timeVal += Time.deltaTime;}}
//坦克的攻击方法private void Attack(){//子弹参数的角度:当前坦克的角度+子弹应该旋转的角度Instantiate(bullectPrefab, transform.position, Quaternion.Euler(transform.eulerAngles + bullectEulerAugles));timeVal = 0;}
坦克的移动不需要按下上下左右键盘,只需要管理V和H的值对敌人AI进行方向的控制
定义两个计时器
public float timeVal;public float timeValChangeDirection;
修改敌人移动的方法
private void Move(){if(timeValChangeDirection>=4){int num = Random.Range(0,8);if(num>5){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;}timeValChangeDirection = 0;}else{timeValChangeDirection += Time.fixedDeltaTime;}//监听玩家垂直轴输入 transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);if (v < 0){sr.sprite = tankSprite[2];bullectEulerAugles = new Vector3(0, 0, -180);}else if (v > 0){sr.sprite = tankSprite[0];bullectEulerAugles = 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];bullectEulerAugles = new Vector3(0, 0, 90);}else if (h > 0){sr.sprite = tankSprite[1];bullectEulerAugles = new Vector3(0, 0, -90);}}
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Enemy : MonoBehaviour {//属性值public float moveSpeed = 3;private Vector3 bullectEulerAugles;private float v;private float h;//引用private SpriteRenderer sr;public Sprite[] tankSprite; //上 右 下 左public GameObject bullectPrefab;public GameObject explosionPrefab;//计时器public float timeVal;public float timeValChangeDirection=4;// Use this for initializationvoid Start(){sr = GetComponent<SpriteRenderer>();}// Update is called once per framevoid Update(){//攻击的时间间隔if (timeVal >= 0.3f){//间隔大于0.4的时候才有攻击效果 Attack();}else{timeVal += Time.deltaTime;}}private void FixedUpdate(){Move();}//坦克的攻击方法private void Attack(){//子弹参数的角度:当前坦克的角度+子弹应该旋转的角度Instantiate(bullectPrefab, transform.position, Quaternion.Euler(transform.eulerAngles + bullectEulerAugles));timeVal = 0;}//坦克的移动方法private void Move(){if(timeValChangeDirection>=4){int num = Random.Range(0,8);if(num>5){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;}timeValChangeDirection = 0;}else{timeValChangeDirection += Time.fixedDeltaTime;}//监听玩家垂直轴输入 transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);if (v < 0){sr.sprite = tankSprite[2];bullectEulerAugles = new Vector3(0, 0, -180);}else if (v > 0){sr.sprite = tankSprite[0];bullectEulerAugles = 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];bullectEulerAugles = new Vector3(0, 0, 90);}else if (h > 0){sr.sprite = tankSprite[1];bullectEulerAugles = new Vector3(0, 0, -90);}}//坦克的死亡方法private void Die(){//产生爆炸特效 Instantiate(explosionPrefab, transform.position, transform.rotation);//死亡 Destroy(gameObject);} }
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Bullect : MonoBehaviour {public float moveSpeed = 10;public bool isPlayerBullect;// Use this for initializationvoid Start () {}// Update is called once per framevoid Update () {transform.Translate(transform.up*moveSpeed*Time.deltaTime,Space.World);}//子弹触发碰撞检测private void OnTriggerEnter2D(Collider2D collision){switch(collision.tag){case "Tank":if(!isPlayerBullect){collision.SendMessage("Die");}Destroy(gameObject);break;case "Heart":collision.SendMessage("Die");Destroy(gameObject);break;case "Enemy":if(isPlayerBullect){collision.SendMessage("Die");}Destroy(gameObject);break;case "Wall"://销毁自身和墙 Destroy(collision.gameObject);Destroy(gameObject);break;case "Barrier":Destroy(gameObject);break;default:break;}}}
初始化地图工具
判断地图长度
地图大小:长20 宽16
添加MapCreation.cs地图管理器来控制草和地图等建筑物
public class MapCreation : MonoBehaviour {//用来装饰初始化地图所需物体的数组//0.老家 1.墙 2.障碍 3.出生效果 4.河流 5.草 6.空气墙public GameObject[] item;}
制作老家心脏和心脏周围的围墙
private void Awake(){//实例化老家Instantiate(item[0], new Vector3(0, -8, -0), Quaternion.identity);//用墙把老家围起来Instantiate(item[1], new Vector3(-1, -8, -0), Quaternion.identity);Instantiate(item[1], new Vector3(1, -8, -0), Quaternion.identity);for(int i=-1;i<2;i++){Instantiate(item[1],new Vector3(i,-7,0),Quaternion.identity);}}
对同一个位置上进行判断,判断是否有障碍物在上面,如果在上面那不再额外生成其它建筑物
已经有东西位置的列表
private List<Vector3> itemPositionList = new List<Vector3>();
private void CreateItem(GameObject createGameObject,Vector3 createPosition,Quaternion createRotate){GameObject itemGo = Instantiate(createGameObject, createPosition, createRotate);itemGo.transform.SetParent(gameObject.transform);itemPositionList.Add(createPosition);}
制作外围墙,也就是游戏边界
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);}
产生随机位置的方法
private Vector3 CreateRamdomPosition(){//不生成x=-10,10的两列,y=-8和8这两行的位置while(true){Vector3 createPosition = new Vector3(Random.Range(-9, 10), Random.Range(-7, 8),0);if(!HasThePosition(createPosition)){return createPosition;}}}
用来判断位置列表中是否有这个位置
private bool HasThePosition(Vector3 createPos){for(int i=0;i<itemPositionList.Count;i++){if(createPos==itemPositionList[i]){return true;}}return false;}
修复子弹触发碰撞检测
private void OnTriggerEnter2D(Collider2D collision){switch(collision.tag){case "Tank":if(!isPlayerBullect){collision.SendMessage("Die");Destroy(gameObject);}break;case "Heart":collision.SendMessage("Die");Destroy(gameObject);break;case "Enemy":if(isPlayerBullect){collision.SendMessage("Die");Destroy(gameObject);}break;case "Wall"://销毁自身和墙 Destroy(collision.gameObject);Destroy(gameObject);break;case "Barrier":Destroy(gameObject);break;default:break;}}
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Bullect : MonoBehaviour {public float moveSpeed = 10;public bool isPlayerBullect;// Use this for initializationvoid Start () {}// Update is called once per framevoid Update () {transform.Translate(transform.up*moveSpeed*Time.deltaTime,Space.World);}//子弹触发碰撞检测private void OnTriggerEnter2D(Collider2D collision){switch(collision.tag){case "Tank":if(!isPlayerBullect){collision.SendMessage("Die");Destroy(gameObject);}break;case "Heart":collision.SendMessage("Die");Destroy(gameObject);break;case "Enemy":if(isPlayerBullect){collision.SendMessage("Die");Destroy(gameObject);}break;case "Wall"://销毁自身和墙 Destroy(collision.gameObject);Destroy(gameObject);break;case "Barrier":Destroy(gameObject);break;default:break;}}}
实例化地图
for(int i=0;i<20;i++){CreateItem(item[1], CreateRamdomPosition(), Quaternion.identity);}for(int i=0;i<20;i++){CreateItem(item[2], CreateRamdomPosition(), Quaternion.identity);}for (int i = 0; i < 20; i++){CreateItem(item[4], CreateRamdomPosition(), Quaternion.identity);}for (int i = 0; i < 20; i++){CreateItem(item[5], CreateRamdomPosition(), Quaternion.identity);}
初始化玩家
GameObject go = Instantiate(item[3], new Vector3(-2, -8, 0), Quaternion.identity); go.GetComponent<Born>().createPlay = 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);
实例化地图并且让围墙的数量尽可能的多
for (int i=0;i<60;i++){CreateItem(item[1], CreateRamdomPosition(), Quaternion.identity);}for(int i=0;i<20;i++){CreateItem(item[2], CreateRamdomPosition(), Quaternion.identity);}for (int i = 0; i < 20; i++){CreateItem(item[4], CreateRamdomPosition(), Quaternion.identity);}for (int i = 0; i < 20; i++){CreateItem(item[5], CreateRamdomPosition(), Quaternion.identity);}
产生敌人的方法
private void CreateEnemy(){int num = Random.Range(0, 3);Vector3 EnemyPos = new Vector3();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);}CreateItem(item[3],EnemyPos,Quaternion.identity);}
每隔5s产生一波敌人
InvokeRepeating("CreateEnemy",4,5);
优化一下敌人AI
敌人AI碰到一起时切换一次方向
private void OnCollisionEnter2D(Collision2D collision){if(collision.gameObject.tag=="Enemy"){timeValChangeDirection = 4;}}
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Player : MonoBehaviour {//属性值public float moveSpeed = 3;private Vector3 bullectEulerAugles;public float timeVal;private float defendTimeVal=3;private bool isDefended=true;//引用private SpriteRenderer sr;public Sprite[] tankSprite; //上 右 下 左public GameObject bullectPrefab;public GameObject explosionPrefab;public GameObject defendEffectPrefab;// Use this for initializationvoid Start () {sr = GetComponent<SpriteRenderer>();}// Update is called once per framevoid Update () {//保护是否处于无敌状态if(isDefended){defendEffectPrefab.SetActive(true);defendTimeVal -= Time.deltaTime;if (defendTimeVal<=0){isDefended = false;defendEffectPrefab.SetActive(false);}}//攻击的CDif (timeVal>=0.4f){//间隔大于0.4的时候才有攻击效果 Attack();}else{timeVal += Time.deltaTime;}}private void FixedUpdate(){Move();}//坦克的攻击方法private void Attack(){if(Input.GetKeyDown(KeyCode.Space)){//子弹参数的角度:当前坦克的角度+子弹应该旋转的角度Instantiate(bullectPrefab,transform.position,Quaternion.Euler(transform.eulerAngles+bullectEulerAugles));timeVal = 0;}}//坦克的移动方法private void Move(){//监听玩家垂直轴输入float v = Input.GetAxisRaw("Vertical");transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);if (v < 0){sr.sprite = tankSprite[2];bullectEulerAugles = new Vector3(0, 0, -180);}else if (v > 0){sr.sprite = tankSprite[0];bullectEulerAugles = new Vector3(0, 0, 0);}if (v != 0){return;}//监听玩家水平轴输入float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World);if (h < 0){sr.sprite = tankSprite[3];bullectEulerAugles = new Vector3(0, 0, 90);}else if (h > 0){sr.sprite = tankSprite[1];bullectEulerAugles = new Vector3(0, 0, -90);}}//坦克的死亡方法private void Die(){if(isDefended){return;}//产生爆炸特效 Instantiate(explosionPrefab, transform.position, transform.rotation);//死亡 Destroy(gameObject);} }
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(){//实例化老家CreateItem(item[0], new Vector3(0, -8, -0), 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++){Instantiate(item[1],new Vector3(i,-7,0),Quaternion.identity);}//实例化外围墙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>().createPlay = 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);//第一次调用CreateEnemy用4s,每隔5s开调用InvokeRepeating("CreateEnemy",4,5);//实例化地图for (int i=0;i<60;i++){CreateItem(item[1], CreateRamdomPosition(), Quaternion.identity);}for(int i=0;i<20;i++){CreateItem(item[2], CreateRamdomPosition(), Quaternion.identity);}for (int i = 0; i < 20; i++){CreateItem(item[4], CreateRamdomPosition(), Quaternion.identity);}for (int i = 0; i < 20; i++){CreateItem(item[5], CreateRamdomPosition(), Quaternion.identity);}}private void CreateItem(GameObject createGameObject,Vector3 createPosition,Quaternion createRotate){GameObject itemGo = Instantiate(createGameObject, createPosition, createRotate);itemGo.transform.SetParent(gameObject.transform);itemPositionList.Add(createPosition);}//产生随机位置的方法private Vector3 CreateRamdomPosition(){//不生成x=-10,10的两列,y=-8和8这两行的位置while(true){Vector3 createPosition = new Vector3(Random.Range(-9, 10), Random.Range(-7, 8),0);if(!HasThePosition(createPosition)){return createPosition;}}}//用来判断位置列表中是否有这个位置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);Vector3 EnemyPos = new Vector3();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);}CreateItem(item[3],EnemyPos,Quaternion.identity);}}
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Born : MonoBehaviour {public GameObject playerPrefab;public GameObject[] enemyPrefabList;//判断是否产生敌人public bool createPlay;// Use this for initializationvoid Start () {Invoke("BornTank",1f);Destroy(gameObject,1f);}private void Update(){}private void BornTank(){if (createPlay){Instantiate(playerPrefab, transform.position, Quaternion.identity);}else{int num = Random.Range(0, 2);Instantiate(enemyPrefabList[num], transform.position, Quaternion.identity);}} }
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Enemy : MonoBehaviour {//属性值public float moveSpeed = 3;private Vector3 bullectEulerAugles;private float v;private float h;//引用private SpriteRenderer sr;public Sprite[] tankSprite; //上 右 下 左public GameObject bullectPrefab;public GameObject explosionPrefab;//计时器public float timeVal;public float timeValChangeDirection=4;// Use this for initializationvoid Start(){sr = GetComponent<SpriteRenderer>();}// Update is called once per framevoid Update(){//攻击的时间间隔if (timeVal >= 0.3f){//间隔大于0.4的时候才有攻击效果 Attack();}else{timeVal += Time.deltaTime;}}private void FixedUpdate(){Move();}//坦克的攻击方法private void Attack(){//子弹参数的角度:当前坦克的角度+子弹应该旋转的角度Instantiate(bullectPrefab, transform.position, Quaternion.Euler(transform.eulerAngles + bullectEulerAugles));timeVal = 0;}//坦克的移动方法private void Move(){if(timeValChangeDirection>=4){int num = Random.Range(0,8);if(num>5){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;}timeValChangeDirection = 0;}else{timeValChangeDirection += Time.fixedDeltaTime;}//监听玩家垂直轴输入 transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);if (v < 0){sr.sprite = tankSprite[2];bullectEulerAugles = new Vector3(0, 0, -180);}else if (v > 0){sr.sprite = tankSprite[0];bullectEulerAugles = 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];bullectEulerAugles = new Vector3(0, 0, 90);}else if (h > 0){sr.sprite = tankSprite[1];bullectEulerAugles = new Vector3(0, 0, -90);}}//坦克的死亡方法private void Die(){//产生爆炸特效 Instantiate(explosionPrefab, transform.position, transform.rotation);//死亡 Destroy(gameObject);}//优化敌人AIprivate void OnCollisionEnter2D(Collision2D collision){if(collision.gameObject.tag=="Enemy"){timeValChangeDirection = 4;}}}
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Explosion : MonoBehaviour {// Use this for initializationvoid Start () {//坦克销毁后0.167秒销毁爆炸特效Destroy(gameObject,0.167f);}// Update is called once per framevoid Update () {} }
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Heart : MonoBehaviour {private SpriteRenderer sr;public GameObject explosionPrefab;public Sprite BrokenSprite; // Use this for initializationvoid Start () {sr = GetComponent<SpriteRenderer>();}private void Die(){sr.sprite = BrokenSprite;Instantiate(explosionPrefab,transform.position,transform.rotation);} }
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Bullect : MonoBehaviour {public float moveSpeed = 10;public bool isPlayerBullect;// Use this for initializationvoid Start () {}// Update is called once per framevoid Update () {transform.Translate(transform.up*moveSpeed*Time.deltaTime,Space.World);}//子弹触发碰撞检测private void OnTriggerEnter2D(Collider2D collision){switch(collision.tag){case "Tank":if(!isPlayerBullect){collision.SendMessage("Die");Destroy(gameObject);}break;case "Heart":collision.SendMessage("Die");Destroy(gameObject);break;case "Enemy":if(isPlayerBullect){collision.SendMessage("Die");Destroy(gameObject);}break;case "Wall"://销毁自身和墙 Destroy(collision.gameObject);Destroy(gameObject);break;case "Barrier":Destroy(gameObject);break;default:break;}}}
玩家状态管理
游戏中添加空物体PlayerManager对象
添加游戏的属性值
public int lifeVale = 3;public int playerScore = 0;public bool isDead;
坦克的死亡方法
private void Die(){if(isDefended){return;}PlayerManager.Instance.isDead = true;//产生爆炸特效 Instantiate(explosionPrefab, transform.position, transform.rotation);//死亡 Destroy(gameObject);}
玩家状态管理类监听玩家状态,当玩家被子弹击中时,生命值开始降低
void Update () {if(isDead){Recover();}}private void Recover(){if (lifeVale < 0){//游戏失败,返回主界面 SceneManager.LoadScene("Game");}else{lifeVale--;GameObject go = Instantiate(born,new Vector3(-2,-8,0),Quaternion.identity);go.GetComponent<Born>().createPlay = true;isDead = false;}}
游戏源代码
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Player : MonoBehaviour {//属性值public float moveSpeed = 3;private Vector3 bullectEulerAugles;public float timeVal;private float defendTimeVal=3;private bool isDefended=true;//引用private SpriteRenderer sr;public Sprite[] tankSprite; //上 右 下 左public GameObject bullectPrefab;public GameObject explosionPrefab;public GameObject defendEffectPrefab;// Use this for initializationvoid Start () {sr = GetComponent<SpriteRenderer>();}// Update is called once per framevoid Update () {//保护是否处于无敌状态if(isDefended){defendEffectPrefab.SetActive(true);defendTimeVal -= Time.deltaTime;if (defendTimeVal<=0){isDefended = false;defendEffectPrefab.SetActive(false);}}}private void FixedUpdate(){if(PlayerManager.Instance.isDefeat){return;}Move();//攻击的CDif (timeVal >= 0.4f){//间隔大于0.4的时候才有攻击效果 Attack();}else{timeVal += Time.fixedDeltaTime;}}//坦克的攻击方法private void Attack(){if(Input.GetKeyDown(KeyCode.Space)){//子弹参数的角度:当前坦克的角度+子弹应该旋转的角度Instantiate(bullectPrefab,transform.position,Quaternion.Euler(transform.eulerAngles+bullectEulerAugles));timeVal = 0;}}//坦克的移动方法private void Move(){//监听玩家垂直轴输入float v = Input.GetAxisRaw("Vertical");transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);if (v < 0){sr.sprite = tankSprite[2];bullectEulerAugles = new Vector3(0, 0, -180);}else if (v > 0){sr.sprite = tankSprite[0];bullectEulerAugles = new Vector3(0, 0, 0);}if (v != 0){return;}//监听玩家水平轴输入float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1transform.Translate(Vector3.right * h * moveSpeed * Time.fixedDeltaTime, Space.World);if (h < 0){sr.sprite = tankSprite[3];bullectEulerAugles = new Vector3(0, 0, 90);}else if (h > 0){sr.sprite = tankSprite[1];bullectEulerAugles = new Vector3(0, 0, -90);}}//坦克的死亡方法private void Die(){if(isDefended){return;}PlayerManager.Instance.isDead = true;//产生爆炸特效 Instantiate(explosionPrefab, transform.position, transform.rotation);//死亡 Destroy(gameObject);} }
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement;public class PlayerManager : MonoBehaviour {//属性值public int lifeVale = 3;public int playerScore = 0;public bool isDead=false;public bool isDefeat;//引用public GameObject born;//单例private static PlayerManager instance;public static PlayerManager Instance{get{return instance;}set{instance = value;}}public void Awake(){Instance = this;}// Use this for initializationvoid Start () {}// Update is called once per framevoid Update () {if(isDead){Recover();}}private void Recover(){if (lifeVale < 0){//游戏失败,返回主界面 SceneManager.LoadScene("Game");}else{lifeVale--;GameObject go = Instantiate(born,new Vector3(-2,-8,0),Quaternion.identity);go.GetComponent<Born>().createPlay = true;isDead = false;}} }
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(){//实例化老家CreateItem(item[0], new Vector3(0, -8, -0), 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++){Instantiate(item[1],new Vector3(i,-7,0),Quaternion.identity);}//坦克一开始就向下太难了,就直接给老家前面加了一顶墙CreateItem(item[2], new Vector3(0, -4, -0), Quaternion.identity);//实例化外围墙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>().createPlay = 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);//第一次调用CreateEnemy用4s,每隔5s开调用InvokeRepeating("CreateEnemy",4,5);//实例化地图for (int i=0;i<60;i++){CreateItem(item[1], CreateRamdomPosition(), Quaternion.identity);}for(int i=0;i<20;i++){CreateItem(item[2], CreateRamdomPosition(), Quaternion.identity);}for (int i = 0; i < 20; i++){CreateItem(item[4], CreateRamdomPosition(), Quaternion.identity);}for (int i = 0; i < 20; i++){CreateItem(item[5], CreateRamdomPosition(), Quaternion.identity);}}private void CreateItem(GameObject createGameObject,Vector3 createPosition,Quaternion createRotate){GameObject itemGo = Instantiate(createGameObject, createPosition, createRotate);itemGo.transform.SetParent(gameObject.transform);itemPositionList.Add(createPosition);}//产生随机位置的方法private Vector3 CreateRamdomPosition(){//不生成x=-10,10的两列,y=-8和8这两行的位置while(true){Vector3 createPosition = new Vector3(Random.Range(-9, 10), Random.Range(-7, 8),0);if(!HasThePosition(createPosition)){return createPosition;}}}//用来判断位置列表中是否有这个位置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);Vector3 EnemyPos = new Vector3();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);}CreateItem(item[3],EnemyPos,Quaternion.identity);}}
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Born : MonoBehaviour {public GameObject playerPrefab;public GameObject[] enemyPrefabList;//判断是否产生敌人public bool createPlay;// Use this for initializationvoid Start () {Invoke("BornTank",1f);Destroy(gameObject,1f);}private void Update(){}private void BornTank(){if (createPlay){Instantiate(playerPrefab, transform.position, Quaternion.identity);}else{int num = Random.Range(0, 2);Instantiate(enemyPrefabList[num], transform.position, Quaternion.identity);}} }
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Enemy : MonoBehaviour {//属性值public float moveSpeed = 3;private Vector3 bullectEulerAugles;private float v=-1;private float h;//引用private SpriteRenderer sr;public Sprite[] tankSprite; //上 右 下 左public GameObject bullectPrefab;public GameObject explosionPrefab;//计时器public float timeVal;public float timeValChangeDirection=0;// Use this for initializationvoid Start(){sr = GetComponent<SpriteRenderer>();}// Update is called once per framevoid Update(){//攻击的时间间隔if (timeVal >= 0.3f){//间隔大于0.4的时候才有攻击效果 Attack();}else{timeVal += Time.deltaTime;}}private void FixedUpdate(){Move();}//坦克的攻击方法private void Attack(){//子弹参数的角度:当前坦克的角度+子弹应该旋转的角度Instantiate(bullectPrefab, transform.position, Quaternion.Euler(transform.eulerAngles + bullectEulerAugles));timeVal = 0;}//坦克的移动方法private void Move(){if(timeValChangeDirection>=4){int num = Random.Range(0,8);if(num>5){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;}timeValChangeDirection = 0;}else{timeValChangeDirection += Time.fixedDeltaTime;}//监听玩家垂直轴输入 transform.Translate(Vector3.up * v * moveSpeed * Time.fixedDeltaTime, Space.World);if (v < 0){sr.sprite = tankSprite[2];bullectEulerAugles = new Vector3(0, 0, -180);}else if (v > 0){sr.sprite = tankSprite[0];bullectEulerAugles = 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];bullectEulerAugles = new Vector3(0, 0, 90);}else if (h > 0){sr.sprite = tankSprite[1];bullectEulerAugles = new Vector3(0, 0, -90);}}//坦克的死亡方法private void Die(){PlayerManager.Instance.playerScore++;//产生爆炸特效 Instantiate(explosionPrefab, transform.position, transform.rotation);//死亡 Destroy(gameObject);}//优化敌人AIprivate void OnCollisionEnter2D(Collision2D collision){if(collision.gameObject.tag=="Enemy"){timeValChangeDirection = 4;}}}
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Explosion : MonoBehaviour {// Use this for initializationvoid Start () {//坦克销毁后0.167秒销毁爆炸特效Destroy(gameObject,0.167f);}// Update is called once per framevoid Update () {} }
using System.Collections; using System.Collections.Generic; using UnityEngine;public class Heart : MonoBehaviour {private SpriteRenderer sr;public GameObject explosionPrefab;public Sprite BrokenSprite; // Use this for initializationvoid Start () {sr = GetComponent<SpriteRenderer>();}private void Die(){sr.sprite = BrokenSprite;Instantiate(explosionPrefab,transform.position,transform.rotation);PlayerManager.Instance.isDefeat = true;} }
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement;public class Bullect : MonoBehaviour {public float moveSpeed = 10;public bool isPlayerBullect;// Use this for initializationvoid Start () {}// Update is called once per framevoid Update () {transform.Translate(transform.up*moveSpeed*Time.deltaTime,Space.World);}//子弹触发碰撞检测private void OnTriggerEnter2D(Collider2D collision){switch(collision.tag){case "Tank":if(!isPlayerBullect){collision.SendMessage("Die");Destroy(gameObject);}break;case "Heart":collision.SendMessage("Die");Destroy(gameObject);SceneManager.LoadScene("Game");break;case "Enemy":if(isPlayerBullect){collision.SendMessage("Die");Destroy(gameObject);}break;case "Wall"://销毁自身和墙 Destroy(collision.gameObject);Destroy(gameObject);break;case "Barrier":Destroy(gameObject);break;default:break;}}}