对于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<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);}

设计为虚函数的原因是。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<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);}}

上面就是整个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。

项目源代码:【跟我一起学Unity3D】做一个2D的90坦克大战之各种各样的墙<<附上项目源代码>>

【跟我一起学Unity3D】做一个2D的90坦克大战之AI系统相关推荐

  1. 【跟我一起学Unity3D】做一个2D的90坦克大战之地图编辑器

    从10月20号到现在,Unity3D也学了10天了,对于Unity3D也有了一个大致的了解,有必要做一个小游戏来检测一下自己的学习成果了.经过两天的努力,终于总算是做出来了一个可以玩的坦克大战了.首先 ...

  2. 用JAVA 做一个简易版的坦克大战(只实现基本功能)

    不太会写文章,只是为了记录自己做过的东西 文章目录 前言 一.大概思路 二.主要代码 1.Tank.java 2.Shot.java 3. Mypanel.java 4.Hero.java 5.Ene ...

  3. dx绘制2d图像_【教程】使用DX9做一个2D游戏(1)

    本文最先发表在贴吧,现在整理到此处,之后所有更新将在这里进行. by Chu @ XDU 2012/11/25 版权所有,禁止用于商业用途. 转载请注明出处. 用DX9做一个2D游戏显然不是一件容易的 ...

  4. opencv交通标志识别_教你从零开始做一个基于深度学习的交通标志识别系统

    教你从零开始做一个基于深度学习的交通标志识别系统 基于Yolo v3的交通标志识别系统及源码 自动驾驶之--交通标志识别 在本文章你可以学习到如何训练自己采集的数据集,生成模型,并用yolo v3算法 ...

  5. Unity3D开发一个2D横版射击游戏

    教程基于http://pixelnest.io/tutorials/2d-game-unity/ , 这个例子感觉还是比较经典的, 网上转载的也比较多. 刚好最近也在学习U3D, 做的过程中自己又修改 ...

  6. 如何做一个基于JAVA房产中介预约看房系统毕业设计毕设作品(springboot框架)

    分析架构 我们开发系统,常规有两个架构,一个BS架构(浏览器/服务器模式),一个CS(客户端/服务器端模式):基于JAVA的网站开发属于B/S架构(即浏览器和服务器架构模式),架构如图 分析系统功能 ...

  7. 如何做一个基于python校园教室图书馆座位预约系统毕业设计毕设作品(Django框架)

    分析架构 我们开发系统,常规有两个架构,一个BS架构(浏览器/服务器模式),一个CS(客户端/服务器端模式):基于Python(Django框架)的网站开发属于B/S架构(即浏览器和服务器架构模式), ...

  8. 从零开始做一个SLG游戏(七):游戏系统以及配置表

    本文主要是来梳理下游戏内的基本系统(虽然只是照搬polytopia的,但是还是要总结一下),并预先做一些配置表,并实现读取. 一.经济系统 1.总述 经济系统可以是整个游戏的核心.在本游戏中只有一种资 ...

  9. vbs做一个会动的进度条_重装系统前后都需要做哪些工作?这几点需注意!

    对于重装系统,这是一个老生常谈的话题了,相信大家并不陌生.不过对于小白而言,往往不太清楚在重装系统前需要做些什么准备,重装系统后又该做哪些优化等这类的问题.今天这篇文章,就是系统的讲解一下重装系统前后 ...

最新文章

  1. 人脸识别引爆下一代生物支付四军之战
  2. 【微软公有云系列】Hyper-v(WinSer 2012 R2)网络虚拟化(三)租户隔离
  3. Aix oracle 自动启动,AIX如何自动启动和关闭软件的运行
  4. LeetCode-有效的字母异位词
  5. 使用SpringBoot AOP 记录操作日志、异常日志
  6. 【LeetCode】查找只出现一次的数字算法
  7. 完了!Oracle 被虐!MySQL 登顶 Top1!原来这么多人都在用
  8. 怎么根据输入的n来输入n组数组_【题解一维数组】1106:年龄与疾病
  9. ElasticSearch Client详解
  10. ie下使用frameset布局导致跨域cookie丢失问题解决
  11. In App Purchases(IAP 应用程序內购买): 完全攻略
  12. 基于Python分析实现酒店评论的中文情感
  13. PAT 甲级 1048 Find Coins
  14. 学校固定资产计算机台账,(一)固定资产台账.doc
  15. 由于找不到msvcp140.dll,无法继续执行代码。重新安装可能会解决此问题
  16. insertSelective和insert的区别?
  17. 新的篇章:来自鲍尔默和艾洛普的公开信
  18. 管理计算机硬件设备并使用应用软件,计算机硬件管理的基本原则
  19. 2022最新淘宝创建子账号教程
  20. python证明冰雹猜想_关于冰雹猜想的证明

热门文章

  1. 转载-SQL Server各种导入导出数据方式的比较
  2. 读懂ConnectString 中 enlist 设置的含义
  3. Flex实现页面多态--state对象
  4. 将Byte数组转化为String
  5. DataGrid在分页状态下删除纪录的问题
  6. Python3中装饰器@typing.overload的使用
  7. 支持向量机(SVM)简介
  8. VC++ 隐藏控制台程序窗口
  9. linux哪个版本支持多线程,关于Linux操作系统的叙述错误的是()A、Linux是多用户、多任务、支持多线程的操作系统B、Linux的源...
  10. java振动数据压缩_【数据结构-Java】最佳实践-数据压缩(使用赫夫曼树)