对于AI,我的初始想法很简单,首先他要能动,并且是在地图里面动, 懂得撞墙后转弯,然后懂得射击,其他的没有了,基于这个想法,我首先创建了一个MyTank类,用于管理玩家的坦克的活动,然后创建AITank类,AITank类继承MyTank类,这样的话,在AITank类上,只需要增加AI就可以了,具体的状态机实现,就放到MyTank类上即可。
首先来分析一下MyTank这个类,就从有限状态机开始吧。
一辆坦克的状态有下面几个:
protected enum State
{
Idle,
LeftWalk,
RightWalk,
UpWalk,
DownWalk,
Fire
};然后就是分别实现每个状态,首先是转向:
protected void UpdateRotate(State state)
{
switch (state)
{
case State.LeftWalk:
this.transform.rotation = Quaternion.identity;
this.transform.Rotate(Vector3.forward * m_fAngle);
m_curAngle = Vector3.left;
break;
case State.RightWalk:
this.transform.rotation = Quaternion.identity;
this.transform.Rotate(Vector3.forward * -m_fAngle);
m_curAngle = Vector3.right;
break;
case State.UpWalk:
this.transform.rotation = Quaternion.identity;
m_curAngle = Vector3.up;
break;
case State.DownWalk:
this.transform.rotation = Quaternion.identity;
this.transform.Rotate(Vector3.forward * m_fAngle * 2);
m_curAngle = Vector3.down;
break;
}
} public virtual void UpdateState()
{
Debug.Log(m_sName + ":UpdateState()");
switch (m_curState)
{
case State.Idle:
break;
case State.LeftWalk:
this.transform.position += Vector3.left * Time.deltaTime * m_fMoveSpeed;
break;
case State.UpWalk:
this.transform.position += Vector3.up * Time.deltaTime * m_fMoveSpeed;
break;
case State.DownWalk:
this.transform.position += Vector3.down * Time.deltaTime * m_fMoveSpeed;
break;
case State.RightWalk:
this.transform.position += Vector3.right * Time.deltaTime * m_fMoveSpeed;
break;
case State.Fire:
doFire();
break;
}
} 其中,doFire的函数实现如下:
protected virtual void doFire()
{
GameObject bullet = Instantiate(m_gBullet) as GameObject;
bullet.name = m_sName + "Bullet";
bullet.GetComponent<CBullet>().m_vDirection = m_curAngle;
bullet.GetComponent<CBullet>().m_fMoveSpeed = m_fMoveSpeed + 1.0f;
bullet.transform.position = new Vector3(this.transform.position.x, this.transform.position.y,0);
Destroy(bullet, 5.0f);
} void Update()
{
SetCurState(State.Idle);
//转向
if (Input.GetKey(KeyCode.A))
{
UpdateRotate(State.LeftWalk);
SetCurState(State.LeftWalk);
}
if (Input.GetKey(KeyCode.W))
{
UpdateRotate(State.UpWalk);
SetCurState(State.UpWalk);
}
if (Input.GetKey(KeyCode.S))
{
UpdateRotate(State.DownWalk);
SetCurState(State.DownWalk);
}
if (Input.GetKey(KeyCode.D))
{
UpdateRotate(State.RightWalk);
SetCurState(State.RightWalk);
}
if (Input.GetKeyDown(KeyCode.K))
{
SetCurState(State.Fire);
}
UpdateState();
} protected void SetCurState(State curState)
{
if (curState != m_curState)
m_lastState = m_curState;
m_curState = curState;
} void OnTriggerEnter2D(Collider2D other)
{
Debug.Log(m_sName + " OnTriggerEnter : " + other.gameObject.name);
//被打中了
if (other.gameObject.name == "AIBullet")
{
Destroy(other.gameObject);
if (Camera.main.GetComponent<CCamera>().ReduceMyLeft() > 0)
{
GameObject temp = Instantiate(m_BoomAnimation, this.gameObject.transform.position, Quaternion.identity) as GameObject;
Destroy(temp, 0.5f);
string name = this.gameObject.name;
GameObject temp_tank = Instantiate(this.gameObject, m_initPosition, Quaternion.identity) as GameObject;
temp_tank.name = name;
}
else
{
//你输了
Camera.main.GetComponent<CCamera>().m_bIsLose = true;
}
Destroy(this.gameObject);
}
}----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面到了AITank的实现,AITank主要是添加一些触发器,例如检测到碰撞就转弯,每隔两秒就发射子弹等等,作为一个非常简单的AI,就不需要考虑那么多。首先是碰撞检测:
void OnCollisionEnter2D(Collision2D coll)
{
Debug.Log(m_sName + " OnCollisionEnter2D : " + coll.gameObject.name);
ChangeStateFromWall();
} 遇到碰撞就转向,然后ChangeStateFromWall的具体实现如下:
void ChangeStateFromWall()
{
switch (m_curState)
{
case State.Idle:
SetCurState(State.DownWalk);
break;
case State.LeftWalk:
SetCurState(State.UpWalk);
break;
case State.UpWalk:
SetCurState(State.RightWalk);
break;
case State.DownWalk:
SetCurState(State.LeftWalk);
break;
case State.RightWalk:
SetCurState(State.DownWalk);
break;
case State.Fire:
SetCurState(m_lastState);
break;
}
this.UpdateRotate(m_curState);
}
}然后到开火,开火的设定非常简单,调用到一个函数:InvokeRepeating,这个是一个重复定时器,函数原型为:
void InvokeRepeating (string methodName,float time,float repeatRate)
我们需要的是在AI坦克生成后一秒发射子弹 然后周期是每隔两秒发射一次,所以在Start函数中应该这么写:
//每隔2秒开一次火
InvokeRepeating("doFire", 1, 2); 然后,我们需要重写doFire这个函数:
protected override void doFire()
{
base.doFire();
}
上面就是AI的基本功能了,以后可以慢慢优化它,使它成为一个强大的AI。
【跟我一起学Unity3D】做一个2D的90坦克大战之AI系统
原文地址:http://blog.csdn.net/nxshow/article/details/40677851