博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【跟我一起学Unity3D】做一个2D的90坦克大战之AI系统
阅读量:6501 次
发布时间:2019-06-24

本文共 6271 字,大约阅读时间需要 20 分钟。

对于AI,我的初始想法非常easy,首先他要能动,而且是在地图里面动。 懂得撞墙后转弯,然后懂得射击,其它的没有了,基于这个想法,我首先创建了一个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
().m_vDirection = m_curAngle; bullet.GetComponent
().m_fMoveSpeed = m_fMoveSpeed + 1.0f; bullet.transform.position = new Vector3(this.transform.position.x, this.transform.position.y,0); Destroy(bullet, 5.0f); }
设计为虚函数的原因是。AITank须要重写这个函数。
然后就须要监听各个按键,我设定为,按下A,W,S,D为方向键。松开就停止移动。然后按下K则开火,所以在Update函数里面应该这么实现:

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();    }
当中SetCurState这个函数是用来设置当前状态的,而且把上一次的状态也存储起来,方便使用。

protected void SetCurState(State curState)    {        if (curState != m_curState)            m_lastState = m_curState;        m_curState = curState;    }
最后就到了一些碰撞检測的函数了,比如,碰到敌人的子弹就生命值减一,生命值为0了就宣布游戏结束。

void OnTriggerEnter2D(Collider2D other)    {        Debug.Log(m_sName + " OnTriggerEnter : " + other.gameObject.name);        //被打中了        if (other.gameObject.name == "AIBullet")        {            Destroy(other.gameObject);            if (Camera.main.GetComponent
().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
().m_bIsLose = true; } Destroy(this.gameObject); } }
上面就是整个MyTank的实现过程了

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

以下到了AITank的实现,AITank主要是加入一些触发器,比如检測到碰撞就转弯,每隔两秒就发射子弹等等,作为一个很easy的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);    }}
这是一个循环转向的函数,假设当前方向是左边,就往上走,假设当前方向是上边。就往右走....;假设在开火状态的话。就返回上一状态。最后更新AI的角度。

然后到开火,开火的设定很easy,调用到一个函数: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。

项目源代码:

转载地址:http://zztyo.baihongyu.com/

你可能感兴趣的文章
iOS 音乐播放器之锁屏效果+歌词解析
查看>>
android O 蓝牙设备默认名称更改
查看>>
阳台的青椒苗
查看>>
swapper进程【转】
查看>>
跨链技术与通证经济
查看>>
爬虫学习之-xpath
查看>>
js jQuery 右键菜单 清屏
查看>>
dotConnect for Oracle
查看>>
Eclipse下C/C++开发环境搭建
查看>>
Eclipse中设置在创建新类时自动生成注释
查看>>
我的友情链接
查看>>
CoreOS 手动更新
查看>>
golang 分页
查看>>
再论机械式针对接口编程
查看>>
25 个 Linux 性能监控工具
查看>>
C#程序员整理的Unity 3D笔记(十三):Unity 3D基于组件的思想
查看>>
Tengine-2.1.1 ngx_http_concat_module 400问题
查看>>
Windows中挂载安装ISO文件
查看>>
Wayland 1.0发布
查看>>
golang的goroutine是如何实现的?
查看>>