现在我们来探讨怪物的相关事宜:
首先我们给怪物加一个EnemyContrl脚本,用来储存怪物的各种属性以及寻路,各种动画。
怪物身上的组件以及脚本设置
话不多说,贴上代码先:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.UI;
public class EnemyContrl : MonoBehaviour
{
/// <summary>
/// 敌人的伤害值
/// </summary>
public float Destruction;
/// <summary>
/// 子弹的伤害
/// </summary>
private float Damage;
/// <summary>
/// 怪物血量
/// </summary>
public float Blood = 100f;
private float b ;
/// <summary>
/// 怪物要到达的终点
/// </summary>
public GameObject Pos;
/// <summary>
/// 自动寻路组件
/// </summary>
private NavMeshAgent agt;
/// <summary>
/// 定义动画控制器
/// </summary>
private Animator Ani;
/// <summary>
/// 死亡后销毁时间
/// </summary>
private float DestryTime = 3f;
/// <summary>
/// 计时器
/// </summary>
private float Timer = 0;
private Slider sd;
void Awake()
{
sd = transform.GetChild(3).GetChild(0).GetComponent<Slider>();
sd.value = sd.maxValue = 1;
b = Blood;
}
void Start()
{
//获取自动寻路组件
agt = this.GetComponent<NavMeshAgent>();
//获取动画控制组件
Ani = this.GetComponent<Animator>();
//将终点位置传递进去
agt.SetDestination(Pos.transform.position);
}
// Update is called once per framea
void Update()
{
transform.GetChild(3).transform.forward = Camera.main.transform.forward;
//监测生命值
EnemyDead(Blood);
//检测是否到达水晶
Attack();
}
public void EnemyHurt(float Damage)
{
Blood -= Damage;
sd.value = Blood /b;
}
public void EnemyDead(float Blood)
{
if (Blood <= 0)
{
this.gameObject.GetComponent<Collider>().enabled = false;
Destroy(this.gameObject.GetComponent<Rigidbody>());
//杀怪物获得金币
GameData.Instance.money += 10;
Ani.SetBool("Dead", true);
Ani.SetBool("Attack", false);
//agt.SetDestination(this.transform.position);
this.gameObject.GetComponent<NavMeshAgent>().enabled = false;
Timer += Time.deltaTime;
if (Timer >= DestryTime) {
Destroy(this.gameObject);
}
}
else
{
}
}
public void Attack()
{
if (Vector3.Distance(this.transform.position, Pos.transform.position) <= 3.5)
{
Ani.SetBool("Attack", true);
}
}
}
有了这些还不够,我们还需要创建一个怪物生成点 (一个空物体即可)
挂载EnemyCreatePos脚本,这里尚未使用对象池技术,想要使用该技术的请到我之前发的文章里找找灵感。
链接:http://www.jianshu.com/p/18950e18ea75
再编写生成脚本时,我们要提前想好自己需要几种不同种类的怪物,这里的不同种类不是指外形的不同,而是比如,地面怪物,空中怪物,甚至物理怪物或魔法怪物,我暂时只分出地面怪物,空中怪物两大类。
代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyCreatePos : MonoBehaviour
{
//public float CreateSpeed = 2;
/// <summary>
/// 波数
/// </summary>
public int boshu = 10;
/// <summary>
/// 每波间隔
/// </summary>
public float bowait = 5;
/// <summary>
/// 每波怪数量
/// </summary>
public int bonum = 10;
/// <summary>
/// 每个怪间隔
/// </summary>
public float numwait = 2;
/// <summary>
/// 第几波
/// </summary>
private int boNO;
/// <summary>
/// 每波第几个
/// </summary>
private int numNO;
private string str;
//void Start () {
// StartCoroutine("CreateEnemy");
//}
//public GameObject enemyPrefabHyp;
// Use this for initialization
void Start()
{
StartCoroutine(Test02(boshu));
}
// Update is called once per frame
void Update()
{
}
//num:一共产生多少波怪
IEnumerator Test02(int num)
{
boNO = 0;
while (boNO < num)
{
//Camera.main.transform.GetComponent<WeatherController>().weather = boNO % 3;
GameObject.Find("Weather").transform.GetComponent<WeatherController>().weather = boNO / 3;
GameObject.Find("Weather").transform.GetComponent<WeatherController>().Change();
boNO++;
yield return StartCoroutine(Test01(bonum));
Debug.Log("第" + boNO + "波怪产生结束");
//每波怪产生的时间差
yield return new WaitForSeconds(bowait);
Debug.Log("注意第" + (boNO + 1) + "波怪即将产生");
}
Debug.Log("GameOver");
}
//number:每波怪的数量
IEnumerator Test01(int number)
{
numNO = 0;
while (numNO < number)
{
numNO++;
//每个怪产生的时间差
if (boNO > 5)
yield return new WaitForSeconds(numwait / 2);
else
yield return new WaitForSeconds(numwait);
string a = ChooseEnemy(boNO,numNO);
//GameObject enemy = (GameObject)Resources.Load("Prefabs_Enemy/mon_goblinWizard");
GameObject enemy = (GameObject)Resources.Load("Prefabs_Enemy/"+a);
enemy.GetComponent<EnemyContrl>().Pos = GameObject.FindGameObjectWithTag("WayPos");
//print(enemy.GetComponent<EnemyContrl>().Pos.name);
GameObject o;
//如果在飞行怪,则拔高5
if (enemy.tag == "FlyEnemy")
{
o = Instantiate(enemy, transform.position + Vector3.up * 5, transform.rotation);
}
else
o = Instantiate(enemy,transform.position,transform.rotation);
o.transform.parent = transform;
}
}
/// <summary>
/// 选择怪物种类
/// </summary>
/// <param name="boNO"></param>波次
/// <param name="numNO"></param>怪次
/// <returns></returns>
string ChooseEnemy(int boNO, int numNO)
{
switch(boNO % 3)
{
case 1:
{
if (numNO < 8)
{
str = "AmurTiger_01";
}
else if (numNO < 10 && numNO >= 8)
{
str = "AmurTiger_02";
}
else
{
str = "AmurTiger_03";
}
break;
}
case 2:
{
if (numNO < 8)
{
str = "GiantBat";
}
else if (numNO < 10 && numNO >= 8)
{
str = "GiantBat_2";
}
else
{
str = "GiantBat_3";
}
break;
}
case 3:
{
if (numNO < 8)
{
print("3-1");
str = "Manticore_01";
}
else if (numNO < 10 && numNO >= 8)
{
print("3-2");
str = "Manticore_02";
}
else
{
str = "Manticore_03";
}
break;
}
case 0:
{
if (numNO < 4)
{
str = "GiantBat_2";
}
else if (numNO < 7 && numNO >= 4)
{
str = "AmurTiger_02";
}
else if (numNO <= 10 && numNO >= 7)
{
str = "Manticore_02";
}
break;
}
}
return str;
}
//IEnumerator CreateEnemy() {
// while (true) {
// yield return new WaitForSeconds(CreateSpeed);
// GameObject enemy = (GameObject)Resources.Load("Prefabs_Enemy/mon_goblinWizard");
// enemy.GetComponent<EnemyContrl>().Pos = GameObject.FindGameObjectWithTag("WayPos");
// Instantiate(enemy);
// }
//}
}
很明显,我设置了很多public,这是方便在外部调试。首先我的想法是将怪物分成n个波次,每波m个怪物,后期可以选择关卡难度时可以改变,甚至可以每波数量递增。其次我们需要将自己需要的怪物名字写成何种形式,或枚举,或分支,总之可以在生成怪时可以控制每次生成的怪物是哪一个。最后,我们对脚本进行微调,如:若是飞行怪则出生高度拔高x单位,或为每一波怪物来临之前加上一个提示等等,随你喜欢。
当然,我们要在怪物的攻击动画中添加时间,在怪物攻击“水晶”或者“萝卜”的时候,扣除水晶一定血量,本游戏采取积分制,但是目前所有怪物死亡后加的分数相同,不便于分出高下,所以我便加了一个判断,假如怪物是被防御塔打死则加10分,被水晶打死则不得分,甚至扣分。
怪物生成逻辑就先告一段落,日后若有优化会开新篇,下一篇我们来探讨防御塔对怪物的检测以及各种子弹的逻辑。
网友评论