Unity3D_(游戏)2D坦克大战 像素版
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 initialization void Start () { } // Update is called once per frame void Update () { //监听玩家水平轴输入 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); } }
控制图片的移动和切换
制作坦克渲染
添加精灵数组的引用
private SpriteRenderer sr; public Sprite[] tankSprite;
(上 右 下 左)
玩家按上下左右控制坦克方向的移动
//监听玩家水平轴输入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.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 initialization void Start () { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void Update () { //监听玩家水平轴输入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.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 1 transform.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 initialization void Start () { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void Update () { //监听玩家水平轴输入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.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 1 transform.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 initialization void Start () { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void 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 1 transform.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 initialization void Start () { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void 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 1 transform.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 initialization void Start () { } // Update is called once per frame void Update () { //监听玩家水平轴输入 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); } }
控制图片的移动和切换
制作坦克渲染
添加精灵数组的引用
private SpriteRenderer sr; public Sprite[] tankSprite;
(上 右 下 左)
玩家按上下左右控制坦克方向的移动
//监听玩家水平轴输入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.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 initialization void Start () { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void Update () { //监听玩家水平轴输入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.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 1 transform.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 initialization void Start () { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void Update () { //监听玩家水平轴输入 float h = Input.GetAxisRaw("Horizontal"); //返回-1 0 1 transform.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 1 transform.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 initialization void Start () { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void 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 1 transform.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 initialization void Start () { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void 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 1 transform.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 initialization void Start () { sr = GetComponent<SpriteRenderer>(); }
添加Heart.cs心脏死亡时方法
private void Die() { sr.sprite = BrokenSprite; }
添加Explosion.cs脚本
当坦克销毁时触发脚本
public class Explosion : MonoBehaviour { // Use this for initialization void Start () { //坦克销毁后0.167秒销毁爆炸特效 Destroy(gameObject,0.167f); } // Update is called once per frame void 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 initialization void Start () { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void Update () { //保护是否处于无敌状态 if(isDefended) { defendEffectPrefab.SetActive(true); defendTimeVal -= Time.deltaTime; if (defendTimeVal<=0) { isDefended = false; defendEffectPrefab.SetActive(false); } } //攻击的CD if (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 1 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() { 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 initialization 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 Heart : MonoBehaviour { private SpriteRenderer sr; public Sprite BrokenSprite; // Use this for initialization void 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 initialization void Start () { } // Update is called once per frame void 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 initialization void Start() { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void Update() { //保护是否处于无敌状态 if (isDefended) { defendEffectPrefab.SetActive(true); defendTimeVal -= Time.deltaTime; if (defendTimeVal <= 0) { isDefended = false; defendEffectPrefab.SetActive(false); } } //攻击的CD if (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 1 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() { 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 initialization void 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 initialization void Start () { Invoke("BornTank",0.8f); Destroy(gameObject,0.8f); } // Update is called once per frame void 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 initialization void 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 initialization void Start() { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void 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 initialization void Start () { } // Update is called once per frame void 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 initialization void Start () { } // Update is called once per frame void 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 initialization void Start () { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void Update () { //保护是否处于无敌状态 if(isDefended) { defendEffectPrefab.SetActive(true); defendTimeVal -= Time.deltaTime; if (defendTimeVal<=0) { isDefended = false; defendEffectPrefab.SetActive(false); } } //攻击的CD if (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 1 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() { 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 initialization void 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 initialization void Start() { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void 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); } //优化敌人AI private 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 initialization 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 Heart : MonoBehaviour { private SpriteRenderer sr; public GameObject explosionPrefab; public Sprite BrokenSprite; // Use this for initialization void 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 initialization void Start () { } // Update is called once per frame void 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 initialization void Start () { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void 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(); //攻击的CD if (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 1 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() { 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 initialization void Start () { } // Update is called once per frame 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 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 initialization void 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 initialization void Start() { sr = GetComponent<SpriteRenderer>(); } // Update is called once per frame void 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); } //优化敌人AI private 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 initialization 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 Heart : MonoBehaviour { private SpriteRenderer sr; public GameObject explosionPrefab; public Sprite BrokenSprite; // Use this for initialization void 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 initialization void Start () { } // Update is called once per frame void 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; } } }