zoukankan      html  css  js  c++  java
  • cocos2d-x游戏开发系列教程-坦克大战游戏之敌方坦克AI的编写

    在上篇我们完成了子弹和地图碰撞的检测,在这篇我们将完成敌方坦克AI的编写。

    具体思路是屏幕中保持有四个敌方坦克,然后坦克随机方向运动,并且子弹消失后1秒发射一次

    1.我们新建一个敌方坦克的AI类来控制地方坦克AI行为:

    static const char* enemyTankType[] = 
    {
    	"normalU.png", "speedU.png", "armor1U.png"
    };
    
    class EnemyAI
    {
    public:
    	EnemyAI();
    	~EnemyAI();
    
    	static EnemyAI* createEnemyAIWithTank(Tank* tank);
    	void initEnemyAIWithTank(Tank* tank);
    	void update(float delta);
    
    private:
    	void addTank(float delta);
    	void tankAction(float delta);
    
    private:
    	CCArray* mEnemyTanks;
    	Tank* mTank;
    	TileMapInfo* mTileMapInfo;
    
    	//出现地点
    	CCPoint bornPoint[3];
    };
    上面目前只添加三种类型的敌方坦克,

    在成员变量中,mEnemyTanks存放了所有的坦克,

    mTank存放了玩家坦克,最后mTileMapInfo存放了地图信息。

    bornPoint存放了敌方坦克出身的三个位置。


    2.先实现void EnemyAI::initEnemyAIWithTank(Tank* tank)来初始化我们的EnemyAI类:

    void EnemyAI::initEnemyAIWithTank(Tank* tank)
    {
    	mTank = tank;
    	mTileMapInfo = tank->getTileMapInfo();
    	mEnemyTanks = CCArray::createWithCapacity(4);
    	mEnemyTanks->retain();
    
    	//初始化出现地点
    	CCSize mapSize = mTileMapInfo->getTileMap()->getContentSize();
    	CCSize tileSize = mTileMapInfo->getTileMap()->layerNamed("layer_0")->getMapTileSize();
    	bornPoint[0] = ccp(tileSize.width, mapSize.height - tileSize.height);
    	bornPoint[1] = ccp(mapSize.width / 2, mapSize.height - tileSize.height);
    	bornPoint[2] = ccp(mapSize.width - tileSize.width, mapSize.height - tileSize.height);
    }
    在上面我们初始化了敌方坦克出身的三个地点,然后创建了一个容量为4的数组mEnemyTanks来存放敌方坦克对象。

    3.再实现静态方法返回EnmeyAI类指针:

    EnemyAI* EnemyAI::createEnemyAIWithTank(Tank* tank)
    {
    	EnemyAI* enemyTank = new EnemyAI();
    	enemyTank->initEnemyAIWithTank(tank);
    
    	return enemyTank;
    }

    4.实现void EnemyAI::addTank(float delta):

    其中delta是每一帧调用之间的事件间隔

    void EnemyAI::addTank(float delta)
    {
    	static float deltaTimes = 0.0f;
    	deltaTimes += delta;
    	if (deltaTimes >= 2.0f)
    	{
    		deltaTimes = 0.0f;
    		int count = mEnemyTanks->count();
    		if (count < 3)	//先从固定位置添加三个坦克
    		{
    			Tank* enemyTank = Tank::createTankWithTankType(enemyTankType[count], mTileMapInfo);
    			enemyTank->setPosition(bornPoint[count]);
    			enemyTank->setRotation(180.0f);
    			mEnemyTanks->addObject(enemyTank);
    		}
    		else if (count == 3)	//第四个坦克随机添加
    		{
    			int tankTypeIndex = (int)(CCRANDOM_0_1() * 4) % 3;
    			Tank* enemyTank = Tank::createTankWithTankType(enemyTankType[tankTypeIndex], mTileMapInfo);
    			enemyTank->setPosition(bornPoint[tankTypeIndex]);
    			enemyTank->setRotation(180.0f);
    			mEnemyTanks->addObject(enemyTank);
    		}
    	}
    }

    可以看到deltaTimes累加时间,超过2秒就开始添加坦克,初始三个坦克从固定位置添加,

    然后第四个坦克随机位置添加。


    5.实现void EnemyAI::tankAction(float delta),来控制坦克行为:

    void EnemyAI::tankAction(float delta)
    {
    	CCObject* pObj;
    	CCARRAY_FOREACH(mEnemyTanks, pObj)
    	{
    		Tank* tank = (Tank*)pObj;
    
    		//坦克自动移动,碰到墙壁自动换方向
    		int Rotation = tank->getRotation();
    		if (!tank->command((enumOrder)(Rotation / 90 + 1)))
    		{
    			int n = (int)(CCRANDOM_0_1() * 5) % 5;
    			if (n != 0)
    				tank->command((enumOrder)n);
    		}
    
    		//每隔一秒开一次火
    		tank->setBulletDelta(tank->getBulletDelta() + delta);
    		if (tank->getBulletDelta() > 0.5)
    		{
    			//开火后,如果子弹在飞行中,归零计时
    			if (tank->command(cmdFire))
    			{
    				tank->setBulletDelta(0.0);
    			}
    		}
    	}
    }
    从mEnemyTanks中遍历坦克对象,然后向固定方向移动,遇到墙壁则随机换方向移动。

    在下面,子弹消失后,隔0.5秒再次发射子弹。


    6.最后实现我们的void EnemyAI::update(float delta),它会在每一帧切换的时候被调用。

    void EnemyAI::update(float delta)
    {
    	//坦克不足4个,补充坦克
    	addTank(delta);
    
    	//坦克行为控制
    	tankAction(delta);
    }

    可以看到,简单的调用添加坦克函数和控制坦克行为函数。


    7.下面我们把敌人的AI类整合到CityScene场景中:

    bool  CityScene::init()
    {
    	CCLayer::init();
    
    	//初始化地图信息
    	char szRound[260];
    	sprintf(szRound, "Round%d.tmx", mRound);
    	TileMapInfo* tileMapInfo = TileMapInfo::createMapInfoWithFile(szRound);
    	CCTMXTiledMap* tmxTileMap = tileMapInfo->getTileMap();
    	this->addChild(tmxTileMap);
    
    	//在已有的地图上,创建玩家坦克
    	mPlayerTank[0] = Tank::createTankWithTankType("player2U.png", tileMapInfo);
    
    	//放到地图中初始化位置
    	CCSize tileSize = tmxTileMap->getTileSize();
    	CCSize mapSize = tmxTileMap->getContentSize();
    	mPlayerTank[0]->setPosition(ccp(mapSize.width / 2 - tileSize.width * 3, tileSize.height));
    
    	//添加虚拟手柄的显示
    	mLayerPanel = Panel::create();
    	addChild(mLayerPanel, 3);
    
    	//创建敌人坦克的AI
    	mEnemyAI = EnemyAI::createEnemyAIWithTank(mPlayerTank[0]);
    
    	return true;
    }

    //创建敌人坦克的AI
    mEnemyAI = EnemyAI::createEnemyAIWithTank(mPlayerTank[0]);

    可以看到最后面创建了我们的AI。


    8.我们在场景的update中调用AI的update函数

    void CityScene::update(float delta)
    {
    	CCLayer::update(delta);
    	//将控制面板中的mLayerPanel获取的命令传给坦克
    	if (mPlayerTank[0] != NULL)
    		mPlayerTank[0]->command(mLayerPanel->getOrder());
    
    	//调用敌人AI的update
    	mEnemyAI->update(delta);
    }

    到这里基本的坦克AI构建完成,我们运行下看看效果:



    完整代码下载地址:

    http://download.csdn.net/detail/yincheng01/6764095

  • 相关阅读:
    kafka整理笔记笔记
    node(一)安装nodejs最新版到debian,ubuntu,mint系统
    ubuntu16.04安装visual-studio-code
    ubuntu16.04更新内核--使用4.6以上的内核会让用A卡的Dell电脑更快--及卸载多余内核
    linux查看主板型号及内存硬件信息,及硬盘测速
    git使用,在ubuntu中
    Ubuntu中文目录文件夹改为英文
    w3m 在ubuntu中的使用
    关于右键属性与du -sh显示的文件大小不一致的解决
    ubuntu16.04安装chrome
  • 原文地址:https://www.cnblogs.com/new0801/p/6177288.html
Copyright © 2011-2022 走看看