//敌人AI类更新至完整版--2022.4.30
//EnemyControl.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 敌人AI类
/// </summary>
//自动将脚本随此脚本挂载而挂载
[RequireComponent(typeof(EnemyMove))]
[RequireComponent(typeof(EnemyInfo))]
[RequireComponent(typeof(EnemyDH))]
public class EnemyControl : MonoBehaviour
{
//声明EnemyDH脚本组件字段
public EnemyDH EnemyDHVar;
//声明EnemyMove脚本组件字段
private EnemyMove EnemyMoveVar;
//声明死亡计数字段,测试
private int DeathCount;
//声明攻击计数字段,测试
private int AttackCount;
//声明一个攻击间隔时间
private float AttackTime;
//声明一个游戏主角GameObject类型
public GameObject PlayerObj;
//声明枪类的变量--英雄无敌项目武器模块--20220425
private Gun GunVar;
//private PlayerStauts playerstatusInfo;
//声明一个状态枚举
private enum Status
{
/// <summary>
/// 攻击状态
/// </summary>
Attack,
/// <summary>
/// 寻路状态
/// </summary>
WayFinding,
/// <summary>
/// 死亡状态
/// </summary>
Death,
/// <summary>
/// 闲置状态
/// </summary>
WaitTime
}
//声明状态枚举的引用,并默认一开始是寻路状态
private Status status = Status.WayFinding;
private void Start()
{
//找到本物体的EnemyDH脚本组件引用,并初始化
EnemyDHVar = this.GetComponent<EnemyDH>();
//找到本物体的EnemyMove脚本组件引用,并初始化
EnemyMoveVar = this.GetComponent<EnemyMove>();
//初始化攻击计数默认值为0,测试
AttackCount = 0;
//初始化攻击间隔时间默认值为0,测试
AttackTime = 0;
//初始化死亡计数默认值为0,测试
DeathCount = 0;
//获取标签为Player(主角)的GameObject类型引用
PlayerObj = GameObject.FindGameObjectWithTag("Player");
//获取枪的组件,实际开发项目中,枪类一般都在子物体上,此处子物体查找是包含本物体查找,本物体查找后即可返回组件信息给GunVar
GunVar = GetComponentInChildren<Gun>();
}
private void Update()
{
//根据枚举状态来使用switch判断各种状态需要执行什么功能
switch (status)
{
case Status.Attack: //攻击状态
EnemyAttack();
break;
case Status.WayFinding: //寻路状态
WayFinding();
break;
case Status.Death: //死亡状态
EnemyDeath();
break;
case Status.WaitTime: //闲置状态
WaitTimeFF();
break;
}
//增加功能,在敌人的视线10米外,正120度为敌人攻击范围,玩家经过此范围,将会触发敌人攻击--20210627
//因角度与英雄无敌最新的武器模块冲突,故直接使用距离判断是否攻击,此if 暂时注释
/*
if (Vector3.Distance(this.transform.position, PlayerObj.transform.position) < 10) //游戏角色与敌人之间小于10米
{
print("触发敌人视线范围");
//自身transform.position加上this.transform.forward(代表前方1米)获得一个向量EnemyForward
Vector3 EnemyForward = this.transform.position + this.transform.forward;
//Vector3.Dot点乘参数:敌人正前方向量和玩家位置向量,获得反余弦值
float ACOSNum = Vector3.Dot(EnemyForward.normalized, PlayerObj.transform.position.normalized);
//计算夹角,反余弦值乘以转换为角度即可求出两根向量的夹角角度
float DotNum = Mathf.Acos(ACOSNum) * Mathf.Rad2Deg;
if (DotNum < 60) //小于60度,进入敌人攻击范围
{
print("触发敌人攻击状态");
status = Status.Attack; //敌人进入攻击状态
}
else
{
print("敌人退出攻击状态");
status = Status.WaitTime; //敌人退出攻击状态
}
//print("DosNum: "+DotNum+" ACOSNum: "+ACOSNum);
}
*/
if (Vector3.Distance(this.transform.position, PlayerObj.transform.position) < 10) //游戏角色与敌人之间小于10米
{
//print("触发敌人攻击状态");
status = Status.Attack; //敌人进入攻击状态
}
else
{
status = Status.WayFinding; //敌人退出攻击状态
}
}
//敌人死亡方法
private void EnemyDeath()
{
print("进入死亡状态");
GetComponent<EnemyInfo>().IsDead(); //调用EnemyInfo类中,敌人死亡的方法
status = Status.WaitTime; //更改状态为闲置状态,测试语句,为了只执行一次,加上注释可以触发无限生成(利用update特性调用多次)
/*
//死亡动画只执行一次
for (; DeathCount < 2; DeathCount++)
{
EnemyDHVar.DHplayVar.DHPlayFF(EnemyDHVar.DeathDH);
}
*/
}
//敌人寻路方法
private void WayFinding()
{
//print("进入寻路状态");
if (EnemyMoveVar.WayFinding() == true) //判断寻路方法的值是否达到所有路线节点的最大值(true),是则更改状态为攻击状态
{
//寻路结束后更改状态为攻击状态
//status = Status.Attack;
//print("敌人找不到玩家呢");
}
else
{
EnemyDHVar.DHplayVar.DHPlayFF(EnemyDHVar.TiaoDH); //false为继续播放跳的动画
}
}
//敌人攻击方法,暂时注释,旧攻击方法无开火攻击,故注释禁用,注释于:20220425
/*
private void EnemyAttack()
{
print("进入攻击状态");
//加判断,如果攻击动画没有播放,则播放跳跃动画
if (!EnemyDHVar.DHplayVar.DHIsPlayering(EnemyDHVar.AttackDH))
//取反操作,等同于if (EnemyDHVar.DHplayVar.DHIsPlayering(EnemyDHVar.AttackDH)==false)
EnemyDHVar.DHplayVar.DHPlayFF(EnemyDHVar.TiaoDH);
if (AttackTime < Time.time) //攻击时间间隔判断,一开始肯定是true
{
EnemyDHVar.DHplayVar.DHPlayFF(EnemyDHVar.AttackDH); //播放攻击动画
AttackCount++; //攻击次数++
AttackTime = Time.time + 3; //攻击间隔时间,这里设定的是3
if (AttackCount >= 3) //攻击次数大于等于3的时候更改状态为死亡状态,测试语句
{
status = Status.Death;
}
}
}
*/
//敌人攻击方法,新方法为开火方法
private void EnemyAttack()
{
//敌人攻击时朝向玩家--20220426
EnemyMoveVar.EnemyRotateFF(PlayerStauts.PubPlayerStatus.PlayerTF.position);
if (AttackTime < Time.time) //攻击时间间隔判断,一开始肯定是true
{
//若敌人当前弹匣全部清空,则予以更换弹匣
if (GunVar.NowAmmoBullet==0)
{
GunVar.UpdateAmmo();
}
//if (GunVar.NowAmmoBullet==0)
//{
//GunVar.UpdateAmmo();
//}
//GunVar.Fireing(this.transform.position - PlayerObj.transform.position);
//延迟调用开火,因为正常项目会有动画需要播放从而抬起枪口,所以需要等待动画播放到枪口抬到平行线才能开枪,这里设置为0.5s后才能开枪
//以后使用动画事件替代
Invoke("EnemyFireDerly", 0.5f);
AttackTime = Time.time + 0.5f; //攻击间隔时间,这里设定的是0.5s
}
//print("敌人攻击方法执行测试");
}
//闲置状态方法,测试方法,为了让死亡状态只执行一次
private void WaitTimeFF()
{
return;
}
//敌人开枪方法,因为需要使用延迟调用,所以另起一个方法方便调用!
private void EnemyFireDerly()
{
//发起攻击(从枪口位置指向玩家受攻击点位置)
//在重申,注意,位置朝向公式是 朝向哪 - 从哪里开始朝向
GunVar.Fireing(PlayerStauts.PubPlayerStatus.PlayerTF.position - GunVar.GunFirePoint.position);
}
}
//联动枪类模块,访问帖子:https://www.swztdza.cn/dalt/foru ... 1&extra=#pid659
|