cocos2d-x游戏开发系列教程-坦克大战游戏之子弹和地图碰撞
上篇文章实现了坦克与地图碰撞的检测,
这篇我们继续完成子弹和地图的碰撞检测。
1.先设计一个子弹类Bullet,如下所示:
class Bullet : public CCSprite
{
public:
Bullet();
~Bullet(); static Bullet* createBulletWithTank(Tank* tank);
void initBulletWithTank(Tank* tank);
bool fire();
virtual void update(float delta);
void bulletBoom(); private:
bool isFlying;
Tank* mTank;
TileMapInfo* mTileMapInfo;
float stepX, stepY;
};
在上面
static Bullet* createBulletWithTank(Tank* tank);
void initBulletWithTank(Tank* tank);
分别是创建子弹的静态方法和初始化子弹的方法,他们都有一个共同参数tank,
用来表示他们所属的坦克。
fire()方法用来被坦克开火的时候调用,
然后在update方法中控制子弹移动以及碰撞检测。
在撞击后通过调用bulletBoom来引爆子弹,炸毁周围的砖块等。
2.在构造函数中初始化
Bullet::Bullet() :isFlying(false)
{
}
isFlying指示子弹是否在飞行中,初始为false表示没有飞行。
3.void Bullet::initBulletWithTank(Tank* tank)函数的实现:
void Bullet::initBulletWithTank(Tank* tank)
{
mTank = tank;
mTileMapInfo = mTank->getTileMapInfo(); initWithSpriteFrameName("bullet.png");
mTileMapInfo->getTileMap()->addChild(this);
setVisible(false);
}
在Bullet类中我们用mTank成员变量存储了他所属的坦克,
用mTIleMapInfo存储了他所属的地图。
用bullet.png精灵帧初始化了精灵。
然后把子弹加入了地图层中
然后把子弹设置为不可见。
4.继续实现静态方法Bullet* Bullet::createBulletWithTank(Tank* tank)
Bullet* Bullet::createBulletWithTank(Tank* tank)
{
Bullet* bullet = new Bullet();
bullet->initBulletWithTank(tank);
bullet->autorelease(); return bullet;
}
可以看到实现非常简单,创建一个Bullet类实例,然后用tank参数初始化,
最后加入自动释放列表,然后返回子弹类指针。
5.是先fire()函数,控制子弹运动方向等:
bool Bullet::fire()
{
if (!isFlying)
{
isFlying = true;
setVisible(true);
setPosition(mTank->getPosition());
//设置子弹运行方向
int Rotation = mTank->getRotation();
switch (Rotation)
{
case 0:
stepX = 0.0f, stepY = 2.0f;
break;
case 90:
stepX = 2.0f, stepY = 0.0f;
break;
case 180:
stepX = 0.0f, stepY = -2.0f;
break;
case 270:
stepX = -2.0f, stepY = 0.0f;
break;
default:
break;
}
scheduleUpdate();
} return isFlying;
}
可以看到,先判断子弹是否在飞行中,如果不在飞行中被调用了,
则先设置飞行状态isFlying为飞行中。
然后设置子弹初始位置为坦克所在的位置,
然后根据坦克旋转的方向,来设置子弹的运行方向分量——stepX和stepY。
最后调用scheduleUpdate()启动update定时器。这样显示每一帧动画的时候,
就会调用我们的update()函数。
6.下面看看怎么实现update()函数:
void Bullet::update(float delta)
{
CCSprite::update(delta);
//设置移动后的位置
setPosition(ccp(getPositionX() + stepX, getPositionY() + stepY)); //检测是否有碰撞
CCRect rect = boundingBox();
if (mTileMapInfo->collisionTest(rect))
{
unscheduleUpdate();
setVisible(false);
isFlying = false;
//引爆子弹
bulletBoom();
}
}
上面先设置了子弹根据分量stepX和stepY移动后的位置。
然后获取自己在地图上的CCRect,然后传入地图信息类中的碰撞检测函数。
如果碰撞了,就调用unscheduleUpdate()来取消update()定时器,
然后设置子弹为不可见,飞行状态设置为false,调用bulletBoom()来引爆子弹。
7.下面实现Bullet类中最后一个成员函数bulletBoom(),来看看它怎么引爆子弹的:
void Bullet::bulletBoom()
{
CCRect rect = boundingBox();
CCSize mapSize = mTileMapInfo->getTileMap()->getContentSize(); if (rect.getMinX() < 0 || rect.getMaxX() >= mapSize.width ||
rect.getMinY() < 0 || rect.getMaxY() >= mapSize.height)
return ; CCTMXLayer* tmxLayer = mTileMapInfo->getTileMap()->layerNamed("layer_0");
CCSize tileSize = tmxLayer->getMapTileSize(); //调整Y轴位tmx地图中的Y轴
float MinY = mapSize.height - rect.getMinY();
float MaxY = mapSize.height - rect.getMaxY(); //将与子弹碰撞的墙壁tileWall图块删除
CCPoint pt = ccp((int)rect.getMinX() / tileSize.width,(int)(MinY / tileSize.height));
if (gidToTileType[tmxLayer->tileGIDAt(pt)] == tileWall)
tmxLayer->setTileGID(gidToTileType[tileNone], pt); pt = ccp((int)rect.getMinX() / tileSize.width,(int)(MaxY / tileSize.height));
if (gidToTileType[tmxLayer->tileGIDAt(pt)] == tileWall)
tmxLayer->setTileGID(gidToTileType[tileNone], pt); pt = ccp((int)rect.getMaxX() / tileSize.width,(int)(MinY / tileSize.height));
if (gidToTileType[tmxLayer->tileGIDAt(pt)] == tileWall)
tmxLayer->setTileGID(gidToTileType[tileNone], pt); pt = ccp((int)rect.getMaxX() / tileSize.width,(int)(MaxY / tileSize.height));
if (gidToTileType[tmxLayer->tileGIDAt(pt)] == tileWall)
tmxLayer->setTileGID(gidToTileType[tileNone], pt);
}
先获取了自己的位置rect和地图的尺寸mapSIze。
首先判断了自己是否跑到了地图外边。如果在地图外边就直接返回。
然后获取了layer_0层的地图信息,将屏幕中的Y轴转换成tmx地图中的Y轴,
然后判断子弹四个角所接触的图块,如果图块是墙壁,那么获取墙壁的GID都设置成tileNone,这样就相当于炸毁墙壁图块。
8.最后我们需要在Tank类型初始化我们的子弹才能看到子弹运行效果,在坦克类中:
void Tank::initTankWithTankType(const char* tankTypeName, TileMapInfo* tileMapInfo)
{
initWithSpriteFrameName(tankTypeName);
mTileMapInfo = tileMapInfo; //将坦克放入地图层中
mTileMapInfo->getTileMap()->addChild(this); //缩放到合适大小
CCTMXTiledMap* tmxTileMap = mTileMapInfo->getTileMap();
CCSize tileSize = tmxTileMap->getTileSize();
CCSize tankSize = getContentSize();
//比地图上砖块小一点
setScale((tileSize.height * 2-4) / (tankSize.height)); //初始化坦克的子弹
mBullet = Bullet::createBulletWithTank(this);
}
可以看到很简单在最下面一行,给mBullet成员函数调用Bullet::createBulletWithTank(this)初始化了子弹。
然后我们还要在Tank类的命中响应函数中调用开火命令:
void Tank::command(enumOrder order)
{
float stepX = 0.0f;
float stepY = 0.0f;
static float fRotation = 0.0f; switch (order)
{
case cmdNothing:
break;
case cmdGoUP:
stepY = 1.0f;
fRotation = 0.0f;
break;
case cmdGoDown:
stepY = -1.0f;
fRotation = 180.0f;
break;
case cmdGoLeft:
stepX = -1.0f;
fRotation = 270.0f;
break;
case cmdGoRight:
stepX = 1.0f;
fRotation = 90.0f;
break;
case cmdFire:
//调用子弹开火
mBullet->fire();
break;
default:
break;
} //检测地图上的碰撞
CCRect rect = this->boundingBox();
if (!mTileMapInfo->collisionTest(CCRectMake(rect.getMinX() + stepX,
rect.getMinY() + stepY, rect.size.width, rect.size.height)))
{
setPositionX(getPositionX() + stepX);
setPositionY(getPositionY() + stepY);
} //根据运行方向旋转坦克
setRotation(fRotation);
}
case cmdFire:
//调用子弹开火
mBullet->fire();
break;
容易看到,只加上这一句就能实现开火效果了。
下面我们编译运行程序,看看效果:
完整实现的代码下载地址如下:
http://download.csdn.net/detail/yincheng01/6760931
cocos2d-x游戏开发系列教程-坦克大战游戏之子弹和地图碰撞的更多相关文章
- cocos2d-x游戏开发系列教程-坦克大战游戏启动界面的编写
用前面介绍的方法,创建一个cocos2d-x项目,可以看到新项目内容如下图:
- cocos2d-x游戏开发系列教程-坦克大战游戏之敌方坦克AI的编写
在上篇我们完成了子弹和地图碰撞的检测,在这篇我们将完成敌方坦克AI的编写. 具体思路是屏幕中保持有四个敌方坦克,然后坦克随机方向运动,并且子弹消失后1秒发射一次 1.我们新建一个敌方坦克的AI类来控制 ...
- cocos2d-x游戏开发系列教程-坦克大战游戏之子弹的碰撞检测处理
在上篇我们加上了简单的坦克之间的碰撞检测,这篇我们继续加上子弹之间, 子弹与坦克之间的碰撞检测,对于上一篇碰撞处理不太完美的地方我们继续改进. 1.子弹之间的碰撞 //玩家子弹和敌方子弹之间的碰撞 C ...
- cocos2d-x游戏开发系列教程-坦克大战游戏之所有坦克之间的碰撞检测
上篇我们完成了简单的AI编写,但是各个坦克移动时之间是可以重合的, 这节课我们来完成坦克之间的碰撞检测,还是在上篇的EnemyAI中完成. 1.我先现在坦克类Tank中添加两个成员变量: CC_SYN ...
- cocos2d-x游戏开发系列教程-坦克大战游戏之虚拟手柄控制坦克移动
上篇显示了控制手柄,但是还不能用来控制坦克, 这篇将会讲手柄和坦克的移动结合起来. 1.先在CityScene场景中实现场景的虚函数virtual void onEnter(); onEnter在进入 ...
- cocos2d-x游戏开发系列教程-坦克大战游戏之坦克和地图碰撞的检测下
上篇我们完成了地图的信息获取和碰撞检测,这篇我们整合到程序中. 在这之前我们改造一下Tank类,使它更加模块化,共容易理解: 1.改造后的Tank类声明如下: class Tank : public ...
- cocos2d-x游戏开发系列教程-坦克大战游戏之虚拟手柄的显示
上篇文章我们有了坦克,但是没有手柄,无法控制坦克. 1.这篇我们编写虚拟手柄来控制坦克.头文件大致内容如下: #define RES_PADDLE_LEFT "paddle/left.png ...
- cocos2d-x游戏开发系列教程-坦克大战游戏之坦克的显示
1.先定义坦克的一些属性 class Tank : public CCSprite { public : Tank(); ~Tank(); static Tank* createTankWithTan ...
- cocos2d-x游戏开发系列教程-坦克大战游戏加载地图的编写
上节课写了关卡选择场景,那么接下来写关卡内容,先写最基本的地图的加载 我们新建一个场景类,如下所示: class CityScene : public cocos2d::CCLayer { publi ...
随机推荐
- ;(function($,window,undefined){})(jQuery,window)详细解析————借助B5教程解析自己整理了一下
在jquery插件中我们经常看到以下这段代码 ;(function ( $, window, document, undefined ){ //函数体内具体代码 })(jQuery, window,d ...
- A.归并排序
归并排序 (求逆序数) 归并排序:递归+合并+排序 时间复杂度:O(n logn) 空间复杂度:O(n) 用途:1.排序 2.求逆序对数 Description In this problem ...
- 进度记录 和 安装imagick时Cannot locate header file MagickWand.h错误的解决
修改php.ini文件,已使php支持扩展的功能 [root@localhost imagick-2.2.2]# ./configure --with-php-config=/usr/local/ph ...
- 多线程下载工具-Axel
1.安装: apt-get install axel 2.用法: axel 参数 文件下载地址 3.常用参数: -n 指定线程数 -o 指定文件存储位置(如不指定,默认存在当前位置(pwd)) -q ...
- Subsets 【dfs】
Given a set of distinct integers, nums, return all possible subsets. Note: Elements in a subset must ...
- AnsiString 在 Delphi 中虽然不可用,但是,在 C++ 中可以用
[C++] C++ Builder 中 Ansi 编码的字符串在Android/iOS程序中显示的问题 呃,这个问题说起来,其实也不麻烦,C++ Builder 本身在 TEncoding 做了处理, ...
- F#实现的单链表(函数式的思想)
// 在 http://fsharp.net 上了解有关 F# 的更多信息 // 请参阅“F# 教程”项目以获取更多帮助. type list = | Nil | Cons of int * list ...
- 【Cavali风格/优质羊毛混纺面料/高密抗静电里衬/撞色拼皮/立领/绿色/便装单西】玛萨玛索男装网购商城
[Cavali风格/优质羊毛混纺面料/高密抗静电里衬/撞色拼皮/立领/绿色/便装单西]玛萨玛索男装网购商城 Cavali风格/优质羊毛混纺面料/高密抗静电里衬/撞色拼皮/立领/绿色/便装单西
- Linux下的定时器
以下摘自linux下的man文件:(man getitimer) #include <sys/time.h> int getitimer(int which, struct iti ...
- 如何去掉IE控件的垂直滚动条(使用QAxWidget加载IE控件)
如果使用MFC的CHtmlView或Qt的QAxWidget加载IE控件,载入html文件后都会自动带一个垂直滚动条,我们不想要这个滚动条,改怎么办呢?搜索了一下“隐藏IE控件滚动条”,发现在 htt ...