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 ...
随机推荐
- mobilize扁平化的fullPage.js类工具使用心得
可以生成一个fullPage效果的主页,但是列表页面和内容页面呢? 主页中的block,可以选择多种组建生成.甚至连form都有: 应该改造其源代码,动态化和cms系统化,添加二三级页面模板: == ...
- centos安装epel源
用163的源,但是我发现这个源里面,根本没有libmcrypt libmcrypt-devel这二个包,装php扩展mcrypt时,又要用到这二个包,所以我手动装了libmcrypt包,但是给我的感觉 ...
- Python之路:Python 函数
一.函数式编程:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装 二. 函数的定义和使用 def 函数名(参数): ... 函数体 ... 函数的定义主要有 ...
- CSDN书籍下载
http://download.csdn.net/user/vanridin/uploads/38 (2016英文书下载) http://download.csdn.net/user/ramissue ...
- C的memset,memcpy,strcpy 的区别 及memset memcpy memmove源码
extern void *memcpy(void *dest,void *src,unsigned int count);#include <string.h> 功能:由src所指内存 ...
- ThinkPHP 3.1.2 控制器的模块和操作
本节课大纲: 一.空模块和空操作 1.空操作 function _empty($name){ $this->show("$name 不存在 <a href='__APP__/In ...
- BZOJ 3038: 上帝造题的七分钟2
3038: 上帝造题的七分钟2 Description XLk觉得<上帝造题的七分钟>不太过瘾,于是有了第二部. "第一分钟,X说,要有数列,于是便给定了一个正整数数列. 第二分 ...
- 《C++游戏开发》十八 角色在障碍物中智能行走的实现
本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/11621337 作者:七十一雾央 新浪微博:http: ...
- C程序设计语言之一
%d 按照十进制整形数打印: %o 按照八进制整形数打印: %x 按照十六进制整形数打印: %c 表示字符 %s 表示字符串 %% 表示%本身打印: %ld long型输出 ”幻数“: #define ...
- Flash中用AS3做的游戏,导出apk安装到手机上滤镜效果出不来为什么?
主要原因是,导出apk文件时渲染模式设置成了GPU.改掉就行了.