目录
23、子弹导入及其初始化
24、子弹逻辑完善
测试
23、子弹导入及其初始化
导入子弹素材
在Bullet游戏对象上添加相关组件
既然子弹具有碰撞体,那么僵尸也得有碰撞体
新建Zombie的Tag(以便确认碰撞对象是否是僵尸群体,这里用的Tag,其实图层也可以),然后将触发器勾上,以便实现碰撞的一些逻辑,而不是真实的碰撞
添加子弹击中效果
在Bullet.cs中添加代码
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
private Rigidbody2D rigidbody;
private SpriteRenderer spriteRenderer;
// 是否击中
private bool isHit = false;
void Start()
{
rigidbody = GetComponent();
spriteRenderer = GetComponent();
// 施加一个向右的力,匀速运动
rigidbody.AddForce(Vector2.right*300);
}
void Update()
{
if (isHit) return;
// 朝Z轴旋转
transform.Rotate(new Vector3(0,0,-15f));
}
private void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Zombie")
{
isHit = true;
// 击中后修改成击中图片
spriteRenderer.sprite = GameManager.instance.GameConf.BulletHit;
// 暂停自己的运动
rigidbody.velocity = Vector2.zero;
// 恢复重力下落
rigidbody.gravityScale = 1;
// 最后销毁(延迟调用)
Invoke("Destroy",0.5f);
}
}
private void Destroy()
{
Destroy(gameObject);
}
}
测试
24、子弹逻辑完善
首先将子弹保存成预制体,并放在GameConf中
新建ZombieManager.cs脚本来管理僵尸
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ZombieManager : MonoBehaviour
{
public static ZombieManager Instance;
private void Awake()
{
Instance = this;
}
private List zombies = new List();
public void AddZombie(Zombie zombie)
{
zombies.Add(zombie);
}
///
/// 获取一个距离最近的僵尸
///
/// 植物当前的行
/// 植物当前的坐标
///
public Zombie GetZombieBylineMinDistance(int lineNum, Vector3 pos)
{
Zombie zombie = null;
float dis = 10000;
for (int i = 0; i < zombies.Count; ++i)
{
// 遍历所有僵尸中等于传进来的lineNum(植物当前的行),并且返回最小距离的僵尸
if ((int)zombies[i].CurrGrid.Point.y == lineNum && Vector2.Distance(pos, zombies[i].transform.position) < dis)
{
dis = Vector2.Distance(pos, zombies[i].transform.position);
zombie = zombies[i];
}
}
return zombie;
}
}
并在Zombie.cs中添加代码
最后在PeaShooter.cs中添加代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
///
/// 植物的基类
///
public class PeaShooter : PlantBase
{
public override float MaxHp
{
get { return 300; }
}
// 是否可以攻击
private bool canAttack = true;
// 攻击间隔
private float attackCD = 1.4f;
// 实例化子弹相对于豌豆射手的偏移量
private Vector3 createBulletOffestPos = new Vector2(0.562f, 0.396f);
protected override void OnInitForPlace()
{
// 每0.2s攻击
InvokeRepeating("Attack",0,0.2f);
}
///
/// 攻击方法-循环检测
///
private void Attack()
{
if (canAttack == false) return;
// 从僵尸管理器获取一个离我最近的僵尸
Zombie zombie = ZombieManager.Instance.GetZombieBylineMinDistance((int) currGrid.Point.y, transform.position);
// 前方没有僵尸则跳出
if (zombie == null) return;
// 僵尸必须在草坪上
if ((int)zombie.CurrGrid.Point.x == 8 &&
Vector2.Distance(zombie.transform.position, zombie.CurrGrid.Position) > 1.5f) return;
// 此使开始发射,实例化一个子弹
Bullet bullet = GameObject.Instantiate(GameManager.instance.GameConf.Bullet1,
transform.position + createBulletOffestPos, Quaternion.identity, transform).GetComponent();
CDEnter();
canAttack = false;
}
private void CDEnter()
{
// 开始计算冷却
StartCoroutine(CalCD());
}
// 计算冷却时间
IEnumerator CalCD()
{
yield return new WaitForSeconds(attackCD);
// 冷却时间结束
canAttack = true;
}
}
测试
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ZombieManager : MonoBehaviour
{
public static ZombieManager Instance;
private void Awake()
{
Instance = this;
}
private List zombies = new List();
public void AddZombie(Zombie zombie)
{
zombies.Add(zombie);
}
///
/// 获取一个距离最近的僵尸
///
/// 植物当前的行
/// 植物当前的坐标
///
public Zombie GetZombieBylineMinDistance(int lineNum, Vector3 pos)
{
Zombie zombie = null;
float dis = 10000;
for (int i = 0; i < zombies.Count; ++i)
{
// 遍历所有僵尸中等于传进来的lineNum(植物当前的行),并且返回最小距离的僵尸
if ((int)zombies[i].CurrGrid.Point.y == lineNum && Vector2.Distance(pos, zombies[i].transform.position) < dis)
{
dis = Vector2.Distance(pos, zombies[i].transform.position);
zombie = zombies[i];
}
}
return zombie;
}
}
并在Zombie.cs中添加代码
最后在PeaShooter.cs中添加代码
using System.Collections; using System.Collections.Generic; using UnityEngine; ////// 植物的基类 /// public class PeaShooter : PlantBase { public override float MaxHp { get { return 300; } } // 是否可以攻击 private bool canAttack = true; // 攻击间隔 private float attackCD = 1.4f; // 实例化子弹相对于豌豆射手的偏移量 private Vector3 createBulletOffestPos = new Vector2(0.562f, 0.396f); protected override void OnInitForPlace() { // 每0.2s攻击 InvokeRepeating("Attack",0,0.2f); } ////// 攻击方法-循环检测 /// private void Attack() { if (canAttack == false) return; // 从僵尸管理器获取一个离我最近的僵尸 Zombie zombie = ZombieManager.Instance.GetZombieBylineMinDistance((int) currGrid.Point.y, transform.position); // 前方没有僵尸则跳出 if (zombie == null) return; // 僵尸必须在草坪上 if ((int)zombie.CurrGrid.Point.x == 8 && Vector2.Distance(zombie.transform.position, zombie.CurrGrid.Position) > 1.5f) return; // 此使开始发射,实例化一个子弹 Bullet bullet = GameObject.Instantiate(GameManager.instance.GameConf.Bullet1, transform.position + createBulletOffestPos, Quaternion.identity, transform).GetComponent (); CDEnter(); canAttack = false; } private void CDEnter() { // 开始计算冷却 StartCoroutine(CalCD()); } // 计算冷却时间 IEnumerator CalCD() { yield return new WaitForSeconds(attackCD); // 冷却时间结束 canAttack = true; } }



