最近在做一个小的ARPG游戏。刚写了一点关于怪物的AI控制的代码,前后还出现了很多问题的。现在拿出来分享一下。
首先我们先导入一个骷髅模型作例子学习。
1、先增加一个animator状态机。
2、然后我们把Skeleton_Pack文件夹里面的其中一个prefab拖到场景。我们在prefab给他添加好Controller,组件和脚本。(差点忘了说,我们把prefab拖出来后,在skeleton_archer_blue设置一个空的gameobject,命名为head,这个head的坐标是skeleton_archer_blue的头顶,用来显示血条的。)
3.using UnityEngine;
using System.Collections;
////// 功能:人物血条的隐藏与显示,怪物的转向(当player与怪物小于一定距离,则设置两者面对面),怪物的自动攻击。
///public class MonsterAI : MonoBehaviour {
public GameObject uiPrefab; //血条的prefab
//角色头顶的点,最好让美术把这个点直接做在fbx模型里面
public Transform head;
public enum State {
IDLE, WALK, ATTACK, DANGER
}
public State state;
private Animator animator;//获取Animator组件
private CharacterController control;
private GameObject ui;
//默认血条与摄像机的距离
private float fomat;
//人物位置坐标
private Vector3 playerPosition;
void Awake() {
ui = (GameObject)Instantiate(uiPrefab);
animator = GetComponent();
control = GetComponent();
}
void Start () {
state = State.IDLE;
fomat = Vector3.Distance(head.position, Camera.main.transform.position);
}
void Update () {
//人物Position
playerPosition=PlayerControl.instance.transform.position;
Debug.DrawLine(playerPosition, transform.position, Color.red);
setBloodBar();
//人物与怪物的距离
float dis = Vector3.Distance(transform.position, playerPosition);
/** * 下面是这样的,当两者距离小于3时,则怪物攻击,设置怪物状态为ATTACK
* 当两者距离大于3小于15时候 ,怪物走向player
* 当大于15时, 怪物处于IDLE状态)
**/
if(dis < 3){
state = State.Attack;
}if( dis <15){
print("进入攻击状态");
Quatertion rotation =Quatertion.Slerp( tranform.rotation , Quatertion.LookRotation( playerPosition - transform.position),5 * Time.deltatime); (LookRotation 创建由怪物正方向转向玩家正方向的旋转)
if(dis > 3){
state = State.WALK;
transform.position += transform.forwrd * 5 * Time.deltatime;
}
}
else {
print("退出小怪攻击范围");
state = State.IDLE;
}
MonsterStateControl(); }
////// 怪物的各种状态处理,设置了animator的状态机的变量
///void MonsterStateControl() {
switch (state) {
case State.IDLE:
animator.SetBool("isAttack00", false);
animator.SetBool("isRun", false);
break;
case State.WALK:
animator.SetBool("isRun", true);
animator.SetBool("isAttack00", false);
break;
case State.ATTACK:
animator.SetBool("isAttack00", true);
animator.SetBool("isRun", false);
break;
case State.DANGER:
state = State.ATTACK;
break;
}
}
////// 设置怪物血条,当怪物在人物前方时显示血条,否则隐藏
///void setBloodBar() {
/** * 此处判断怪物是否在player的前方。 * 获得player的forward,和两者的距离,再通过Vector3.Angle取得player正前方方向与distance方向的角度 * 计算,magnitude表示两者距离,angle当角度小于45,证明怪物在player的正前方视野。 * */
Vector3 Playerforward = PlayerControl.instance.transform.TransformDirection(Vector3.forward); (从自身坐标到世界坐标的变换)
//人物与怪物的距离
Vector3 distance = transform.position - playerPosition;
float angle = Vector3.Angle(Playerforward, distance);
if(angle<45 && distance.magnitude<15) {
ui.SetActive(true);
} else {
ui.SetActive(false);
}
//这里可以判定一下,如果位置没有变化就不要再赋值了
float newFomat = fomat / Vector3.Distance(head.position, Camera.main.transform.position);
ui.transform.position = WorldToUI(head.position);
ui.transform.localScale = Vector3.one * newFomat;
}
//核心代码在这里把3D点换算成NGUI屏幕上的2D点。
public static Vector3 WorldToUI(Vector3 point) {
Vector3 pt = Camera.main.WorldToScreenPoint(point);
Vector3 ff = UICamera.currentCamera.ScreenToWorldPoint(pt);
//UI的话z轴等于0
ff.z = 0;
return ff;
}
}