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 ...
随机推荐
- 关于left join 和 inner join
今天遇到一个逻辑很复杂的SQL,虽然写出来了,但是并没有完全体会,找了找资料,算是摸清楚了left join和inner join 的实际意义. 感谢PCJIM的文章,写的非常明白,原文地址:http ...
- 由命名空间函数而引发思考--js中的对象赋值问题
最近没有编码任务,作为一个才毕业的小辣鸡,给的任务就是看一下公司的新系统,熟悉怎么用哪些地方是干什么的. 下午喝了两杯水,感觉有点浪.然后就开始看了下代码.发现有一个函数是这样子的. var TX = ...
- 如何通过java反射将数据库表生成实体类?
首先有几点声明: 1.代码是在别人的基础进行改写的: 2.大家有什么改进的意见可以告诉我,也可以自己改好共享给其他人: 3.刚刚毕业,水平有限,肯定有许多不足之处: 4.希望刚刚学习java的同学能有 ...
- python成长之路15
一:JavaScript: JavaScript是一门编程语言,浏览器内置了JavaScript语言的解释器,所以在浏览器上按照JavaScript语言的规则编写相应代码之,浏览器可以解释并做出相应的 ...
- ajax是怎么发请求的和浏览器发的请求一样吗?cookie
下午设置cookie时出现了个问题 用ajax发的post请求php,在php的方法里设置了cookie,然后在浏览器请求的php里打印cookie值但是一直获取不到cookie的值 分析: 1.aj ...
- NSString 用法大全。
一.NSString 创建字符串. NSString *astring = @"This is a String!"; 创建空字符串,给予赋值. NSString *astri ...
- Ubuntu下配置修改IP地址
一.使用命令设置Ubuntu IP地址 1.修改配置文件blacklist.conf禁用IPV6:sudo vi /etc/modprobe.d/blacklist.conf 2.在文档最后添加 bl ...
- linux下检测端口是否连通
检测tcp端口使用telnet命令 telnet 例:telnet 192.168.0.1 80 检测udp端口使用uc命令 uc -zu 例:uc -zu 192.169.0.1 80 以上命令 ...
- 在 Windows Azure 网站 (WAWS) 上对 Orchard CMS 使用 Azure 缓存
编辑人员注释: 本文章由 Windows Azure 网站团队的项目经理 Sunitha Muthukrishna 撰写. 如果您当前的 OrchardCMS 网站在 Windows Azure 网站 ...
- java面板设计
写面板真的是写到吐血,深深感受到什么叫又臭又长,可能是自己用的太烂吧. 关于布局管理器不写一下还是不懂,另外加面板的思想跟html中div的感觉差不多. 发现的一个小彩蛋:用JScrollPane的时 ...