【三】仿微信飞机大战cocos2d-x3.0rc1
上一篇:【二】仿微信飞机大战cocos2d-x3.0rc1
今天的任务是:
1.我机子弹无限量发射
2.三种类型敌机的出现
3.敌机自己碰墙死掉
一、效果界面展示
暂时没有实现子弹打中敌机
二、工程解决方案
子弹层:BulletLayer文件
敌机层:EnemyLayer文件
敌机精灵数据:Enemy文件
三、子弹无限量供应
BulletLayer.h文件:
#ifndef __BULLET_LAYER_H__
#define __BULLET_LAYER_H__
#pragma once
#include "cocos2d.h"
#include "PlaneLayer.h"USING_NS_CC;class BulletLayer : public Layer
{
public:BulletLayer();~BulletLayer();virtual bool init();CREATE_FUNC(BulletLayer);public:void BeginBulletShoot(float dt=0.0f); // 开启子弹射击void StopBulletShoot(); // 停止子弹射击void addBullet(float dt); // 添加子弹void removeBullet(Node* pNode); // 移除子弹
};#endif //__BULLET_LAYER_H__
结构和之前的layer一样,无非加了一些自己的方法。
流程:
1.想打飞机,则开启子弹开关
2.发射子弹
3.某些情况移除子弹
4.不想打飞机,就停止射击
我们可以在创建子弹层的时候,开启射击开关:
bool BulletLayer::init()
{if (!Layer::init()){return false;}BeginBulletShoot();return true;
}
射击开关实现如下:
void BulletLayer::BeginBulletShoot( float dt )
{this->schedule(schedule_selector(BulletLayer::addBullet), 0.2f, kRepeatForever, dt);
}
每隔0.2秒,就发射一颗子弹(调用addBullet),kRepeatForever.
子弹发射过程:
void BulletLayer::addBullet( float dt )
{// 子弹auto bullet = Sprite::createWithSpriteFrameName("bullet1.png");if (NULL == bullet){return;}this->addChild(bullet);// 获得飞机的位置Point planePos = PlaneLayer::sharedPlane->getChildByTag(AIRPLANE)->getPosition();Point bulletPos = Point(planePos.x + 2, planePos.y + PlaneLayer::sharedPlane->getChildByTag(AIRPLANE)->getContentSize().height/2);bullet->setPosition(bulletPos);// 飞行长度 飞行就是超出窗体float flyLen = Director::getInstance()->getWinSize().height + bullet->getContentSize().height/2 - bulletPos.y;float flyVelocity = 320/1; //飞行速度float realFlyDuration = flyLen/flyVelocity; // 飞行时间auto actionMove=MoveTo::create(realFlyDuration,Point(bulletPos.x,Director::getInstance()->getWinSize().height+bullet->getContentSize().height/2));auto actionDone=CallFuncN::create(CC_CALLBACK_1(BulletLayer::removeBullet, this));Sequence* sequence=Sequence::create(actionMove,actionDone,NULL);bullet->runAction(sequence);
}
这里有个地方需要注意:PlaneLayer::sharedPlane->getChildByTag(AIRPLANE)->getPosition(); 这个地方,和我之前写的有点出入,因为那时候,我没考虑到飞机会被其他的模块调用。(飞机是在飞机头出现的,飞机又是可以移动的,所以子弹的位置需要根据飞机来定),这里我可以顺便给大家讲解下CREATE_FUNC宏。回到飞机层,下面展现下休整后的飞机层PlaneLayer.h头文件:
#pragma once
#include "cocos2d.h"
USING_NS_CC;enum Enum_Plane
{AIRPLANE = 1,
};class PlaneLayer : public Layer
{
public:PlaneLayer();~PlaneLayer();static PlaneLayer* create(); // 实现创建virtual bool init(); public:void checkBorder(float dt); // 边界检测public:static PlaneLayer* sharedPlane; // 提供全局的指针 类似单例bool isAlive; // 飞机是否活着
};
少侠们,发现什么不同吗?yes,我提供出了一个static PlaneLayer* sharedPlane;全局的指针,这样的话,就可以被其他模块直接调用了。还有什么不同!没错~CREATE_FUNC(PlaneLayer)定义不见了。其实static PlaneLayer* create()和CREATE_FUNC(PlaneLayer)是一样的,只是之前被宏代替了,我们为什么不用CREATE_FUNC了呢?先给你们看下static PlaneLayer* create()的实现:
PlaneLayer* PlaneLayer::create()
{// 不需要手动释放create出来的对象PlaneLayer *pRet = new PlaneLayer();if (pRet && pRet->init()){pRet->autorelease(); //将它交由内存管理器进行内存释放管理sharedPlane = pRet; // 赋给指针return pRet;}else{CC_SAFE_DELETE(pRet); // 使用delete操作符删除一个C++对象pRet,如果pRet为NULL,则不进行操作return NULL;}
}
CREATE_FUNC转换过来,其实也是这样的,不信?那就对比一下,CREATE_FUNC宏:
#define CREATE_FUNC(__TYPE__) \
static __TYPE__* create() \
{ \__TYPE__ *pRet = new __TYPE__(); \if (pRet && pRet->init()) \{ \pRet->autorelease(); \return pRet; \} \else \{ \delete pRet; \pRet = NULL; \return NULL; \} \
}
是不是咯。其实他们很像,只是我们多了sharedPlane = pRet; 把我们生成的layer层提供出来给静态成员,方便外界模块的调用,所以我们才重新编写函数实现。把上面的代码替换之后,别忘了PlaneLayer.cpp在里写下PlaneLayer* PlaneLayer::sharedPlane = NULL;我们根据飞机当前的位置,很容易就算出了子弹此刻应该出现的位置,设置它:
Point planePos = PlaneLayer::sharedPlane->getChildByTag(AIRPLANE)->getPosition();Point bulletPos = Point(planePos.x + 2, planePos.y + PlaneLayer::sharedPlane->getChildByTag(AIRPLANE)->getContentSize().height/2);bullet->setPosition(bulletPos);
接着让子弹按X坐标不变,再定一个Y的终点坐标,这样飞机就会按固定直线,飞离你的飞机到指定位置,然后调用子弹消亡函数removeBullet()。
解释一下MoveTo::create(5,Point(100,100)):用5秒的时间移动到Point(100,100)处。
移除子弹:
子弹射的太远,有时候也不太好(你不销毁的话,会占用内存的,不用的,就释放掉)。
void BulletLayer::removeBullet( Node* pNode )
{if (NULL == pNode){return;}Sprite* bullet=(Sprite*)pNode;this->removeChild(bullet,true);
}
在飞行到指定目的地,触发回调后,我们用本layer层直接removeChild。true是停止被移除精灵的所有动作。
停止射击:
void BulletLayer::StopBulletShoot()
{this->unschedule(schedule_selector(BulletLayer::addBullet));
}
是时候给让飞机打起来了!回到主场景GameScene下的GameLayer::init()。加入以下这段:
// 开启子弹bulletLayer = BulletLayer::create();this->addChild(bulletLayer);
当然别忘记在GameScene.h中加头文件:
#ifndef __GAME_SCENE_H__
#define __GAME_SCENE_H__
#include "cocos2d.h"
#include "PlaneLayer.h"
#include "BulletLayer.h"
#include "EnemyLayer.h"USING_NS_CC;
好吧,不小心把敌机的头文件也包含进来了。只好也把敌机也给实现了。
四、群魔乱舞的敌机
老规矩撒~继续摆出头文件EnemyLayer.h:
#pragma once
#include "cocos2d.h"
#include "EnemyDefine.h"
#include "Enemy.h"USING_NS_CC;class EnemyLayer : public Layer
{
public:EnemyLayer();~EnemyLayer();virtual bool init();CREATE_FUNC(EnemyLayer);public:void addEnemy1(float dt); // 添加敌机1void addEnemy2(float dt); // 添加敌机2void addEnemy3(float dt); // 添加敌机3void removeEnemy(Node *pNode, EnemyType eType);// 移除敌机pNode, eType是敌机类型,本来想用来加相应特效的,不过算了
public:};
我们赶快来看看init()的实现!!
bool EnemyLayer::init()
{if (!Layer::init()){return false;}// 敌机1被打爆动作帧cocos2d::Vector<SpriteFrame*> vecTemp;vecTemp.clear();vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy1_down1.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy1_down2.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy1_down3.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy1_down4.png"));Animation *pAnimation1 = Animation::createWithSpriteFrames(vecTemp);pAnimation1->setDelayPerUnit(0.1f);// 添加到AnimationCache,并且命名为Enemy1BlowupAnimationCache::getInstance()->addAnimation(pAnimation1, "Enemy1Blowup");this->schedule(schedule_selector(EnemyLayer::addEnemy1), 1.0f); // 每1秒出现一架敌机1// 敌机2被打爆动作帧vecTemp.clear();vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy2_down1.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy2_down2.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy2_down3.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy2_down4.png"));Animation *pAnimation2 = Animation::createWithSpriteFrames(vecTemp);pAnimation2->setDelayPerUnit(0.1f);AnimationCache::getInstance()->addAnimation(pAnimation1, "Enemy2Blowup");this->schedule(schedule_selector(EnemyLayer::addEnemy2), 5.0f);// 敌机3被打爆动作帧vecTemp.clear();vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy3_down1.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy3_down2.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy3_down3.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy3_down4.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy3_down5.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy3_down6.png"));Animation *pAnimation3 = Animation::createWithSpriteFrames(vecTemp);pAnimation3->setDelayPerUnit(0.1f);AnimationCache::getInstance()->addAnimation(pAnimation1, "Enemy3Blowup");this->schedule(schedule_selector(EnemyLayer::addEnemy3), 10.0f);return true;
}
我们就拿出敌机1来解释吧。其他其实都一样:
创建一个容器Vector:cocos2d::Vector<SpriteFrame*> vecTemp。这个Vector存储的只能是继承了Ref的对象,Node,Sprite等都继承了Ref。这个vecTemp.clear()。每次清理一下,我才放心。
然后就是把爆炸后的四个状态对象加入到Vector中去:
vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy1_down1.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy1_down2.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy1_down3.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy1_down4.png"));
接着就是让Animation把这些图像缓存起来,并且设置成0.1秒的间隔显示时间。
Animation *pAnimation1 = Animation::createWithSpriteFrames(vecTemp);pAnimation1->setDelayPerUnit(0.1f);
我们缓存起来之后,怎么取出来用呢?就用到了下面的这种形式:
// 添加到AnimationCache,并且命名为Enemy1BlowupAnimationCache::getInstance()->addAnimation(pAnimation1, "Enemy1Blowup");
好了让我们回归到如何出现敌机上来:
把第一架飞机设置成一秒一架的速率出现(有人说会不会太快了,你子弹0.2秒一个,还不许人家敌机1秒一次吗?):
this->schedule(schedule_selector(EnemyLayer::addEnemy1), 1.0f); // 每1秒出现一架敌机1
添加敌机void EnemyLayer::addEnemy1( float dt ):
void EnemyLayer::addEnemy1( float dt )
{EnemySprite *pEnemySprite = EnemySprite::create();pEnemySprite->setEnemyByType(Enemy1);this->addChild(pEnemySprite);// 设置运动轨迹 以及到终点时调用的函数auto actionMove=MoveTo::create(3.0f,Point(pEnemySprite->getPositionX(), 0 - pEnemySprite->getSprite()->getContentSize().height/2));auto actionDone = CallFuncN::create(CC_CALLBACK_1(EnemyLayer::removeEnemy, this, Enemy1));Sequence* sequence=Sequence::create(actionMove, actionDone, NULL); // 按顺序执行 敌机飞到边缘,敌机移动结束pEnemySprite->runAction(sequence);
}
EnemySprite是等下我们要讲的,就先不管这个家伙,我们只要知道EnemySprite它继承了Node。这样我们就可以让EnemySprite加入到EnemyLayer中去。记住我们是让EnemyLayer层里面加入多个以及多种肆无忌惮的敌机,然后射死它们。另外pEnemySprite->getPositionX()与0 - pEnemySprite->getSprite()->getContentSize().height/2这两个是说敌机的X位置不变,Y的位置移动到负的敌机高度的一半。
addEnemy2,addEnemy3都一样,只是把枚举改一下就可以了。
加入敌机1后,我们设置敌机的飞行轨迹actionMove,以及飞行完以后,需要擦屁股的函数EnemyLayer::removeEnemy。因为CC_CALLBACK_1可以额外带一个参数,所以我就带了个Enemy1,this是必带的。这里就实现了,敌机出现,以及敌机消亡的过程。那么敌机是怎么产生的呢?因为有我机,必需拿敌机来衬托我机的强大以及持久呗。好了,不废话,让我们看下敌机真正产生的过程:
/***********************************************因为敌方飞机具有生命值等特性,需要附加属性************************************************/
#include "cocos2d.h"
#include "EnemyDefine.h"USING_NS_CC;class EnemySprite : public Node
{
public:EnemySprite();~EnemySprite();virtual bool init();CREATE_FUNC(EnemySprite);public:void setEnemyByType(EnemyType enType);Sprite* getSprite();private:Sprite *pEnemySprite;int nLife;
};
我们这里的飞机有3种,每种的生命值都不一样,所以我们多了个nLife表示敌机生命值。而且我们还需要生成敌机,所以多了个Sprite。再让EnemySprite 继承 Node,这样就可以让敌机层加入这个Node,Node它自己也会addchild(Sprite)的。Layer中加入了Node,Node里面又加入了Sprite。这个你们应该能懂吧。
让我们看下init()的实现:
bool EnemySprite::init()
{bool pRet = true;if (!Node::init()){pRet = false;}return pRet;
}
我擦。居然什么都没有,创建敌机的方法跑哪里去了!!
看下之前被我们抛弃的那三行:
EnemySprite *pEnemySprite = EnemySprite::create();pEnemySprite->setEnemyByType(Enemy2);this->addChild(pEnemySprite);
用到了setEnemyByType函数,原来是通过敌机类型来产生不同类型的敌机的。
void EnemySprite::setEnemyByType( EnemyType enType )
{switch (enType){case Enemy1:pEnemySprite = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy1.png"));nLife = ENEMY1_MAXLIFE;break;case Enemy2:pEnemySprite = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy2.png"));nLife = ENEMY2_MAXLIFE;break;case Enemy3:pEnemySprite = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy3_n1.png"));nLife = ENEMY3_MAXLIFE;break;case Enemy4:pEnemySprite = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy3_n2.png"));nLife = ENEMY3_MAXLIFE;break;default:return;break;}this->addChild(pEnemySprite);Size winSize = Director::getInstance()->getWinSize();Size enemySize = pEnemySprite->getContentSize();int minX=enemySize.width/2;int maxX=winSize.width - enemySize.width/2;int rangeX=maxX-minX;int actualX=(rand()%rangeX) + minX;// 设置敌机Node方位 Node包含Spritethis->setPosition(Point(actualX, winSize.height + enemySize.height/2));
}
我们通过不同类型生成不同的敌机,并且赋予不同的生命。然后加入到Node里面去。接着就是设置这个Node的方位。ok,到这里,我们已经把敌机也产生了。最后剩下一个,就是我们让Node把精灵提供出来Sprite* EnemySprite::getSprite():
Sprite* EnemySprite::getSprite()
{return pEnemySprite;
}
篇幅太长了,我提供了头文件,而且几乎每个方法都实现了一遍。
这里就提供一下EnemyLayer.cpp:
#include "EnemyLayer.h"EnemyLayer::EnemyLayer()
{}EnemyLayer::~EnemyLayer()
{}bool EnemyLayer::init()
{if (!Layer::init()){return false;}// 敌机1被打爆动作帧cocos2d::Vector<SpriteFrame*> vecTemp;vecTemp.clear();vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy1_down1.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy1_down2.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy1_down3.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy1_down4.png"));Animation *pAnimation1 = Animation::createWithSpriteFrames(vecTemp);pAnimation1->setDelayPerUnit(0.1f);// 添加到AnimationCache,并且命名为Enemy1BlowupAnimationCache::getInstance()->addAnimation(pAnimation1, "Enemy1Blowup");this->schedule(schedule_selector(EnemyLayer::addEnemy1), 1.0f); // 每1秒出现一架敌机1// 敌机2被打爆动作帧vecTemp.clear();vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy2_down1.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy2_down2.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy2_down3.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy2_down4.png"));Animation *pAnimation2 = Animation::createWithSpriteFrames(vecTemp);pAnimation2->setDelayPerUnit(0.1f);AnimationCache::getInstance()->addAnimation(pAnimation1, "Enemy2Blowup");this->schedule(schedule_selector(EnemyLayer::addEnemy2), 5.0f);// 敌机3被打爆动作帧vecTemp.clear();vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy3_down1.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy3_down2.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy3_down3.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy3_down4.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy3_down5.png"));vecTemp.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy3_down6.png"));Animation *pAnimation3 = Animation::createWithSpriteFrames(vecTemp);pAnimation3->setDelayPerUnit(0.1f);AnimationCache::getInstance()->addAnimation(pAnimation1, "Enemy3Blowup");this->schedule(schedule_selector(EnemyLayer::addEnemy3), 10.0f);return true;
}void EnemyLayer::addEnemy1( float dt )
{EnemySprite *pEnemySprite = EnemySprite::create();pEnemySprite->setEnemyByType(Enemy1);this->addChild(pEnemySprite);// 设置运动轨迹 以及到终点时调用的函数auto actionMove=MoveTo::create(3.0f,Point(pEnemySprite->getPositionX(), 0 - pEnemySprite->getSprite()->getContentSize().height/2));auto actionDone = CallFuncN::create(CC_CALLBACK_1(EnemyLayer::removeEnemy, this, Enemy1));Sequence* sequence=Sequence::create(actionMove, actionDone, NULL); // 按顺序执行 敌机飞到边缘,敌机移动结束pEnemySprite->runAction(sequence);
}void EnemyLayer::addEnemy2( float dt )
{EnemySprite *pEnemySprite = EnemySprite::create();pEnemySprite->setEnemyByType(Enemy2);this->addChild(pEnemySprite);// 设置运动轨迹 以及到终点时调用的函数auto actionMove=MoveTo::create(4.5f,Point(pEnemySprite->getPositionX(), 0 - pEnemySprite->getSprite()->getContentSize().height/2));auto actionDone = CallFuncN::create(CC_CALLBACK_1(EnemyLayer::removeEnemy, this, Enemy2));Sequence* sequence=Sequence::create(actionMove, actionDone, NULL); // 按顺序执行 敌机飞到边缘,敌机移动结束pEnemySprite->runAction(sequence);
}void EnemyLayer::addEnemy3( float dt )
{EnemySprite *pEnemySprite = EnemySprite::create();pEnemySprite->setEnemyByType(Enemy3);this->addChild(pEnemySprite);// 设置运动轨迹 以及到终点时调用的函数auto actionMove=MoveTo::create(6.0f,Point(pEnemySprite->getPositionX(), 0 - pEnemySprite->getSprite()->getContentSize().height/2));auto actionDone = CallFuncN::create(CC_CALLBACK_1(EnemyLayer::removeEnemy, this, Enemy3));Sequence* sequence=Sequence::create(actionMove, actionDone, NULL); // 按顺序执行 敌机飞到边缘,敌机移动结束pEnemySprite->runAction(sequence);
}void EnemyLayer::removeEnemy( Node *pNode , EnemyType eType)
{EnemySprite* enemy=(EnemySprite*)pNode;if (enemy!=NULL){this->removeChild(enemy,true);}
}
今天周五!!回家,明天搬到公司附近住~~
【三】仿微信飞机大战cocos2d-x3.0rc1相关推荐
- Android游戏之仿 微信飞机大战
暑假实训的一个程序,也是我第一次接触java和android开发,模仿微信的飞机大战,效果图如下: 一:素材整理 素材来自网络,下载地址在此:http://downlo ...
- cocos2dx一仿微信飞机大战游戏实战一
学习cocos2dx的新手教程实例,简单做个打飞机的小游戏,嗯,先运行看看游戏的效果: 下面我们就开始编写吧,首先我们要解决的几个问题是这个游戏的设计思路,微信的飞机大战游戏,有几个技术点,一是游戏背 ...
- JavaScript趣味编程--仿微信飞机大战游戏--1.画飞机
之前的文章已经介绍了如何使用canvas来画正方形,这次介绍如何使用canvas来画一张图片. 1.新建项目 本次使用的工具Aptana Studio 3,打开软件之后,选择File->New- ...
- 【C语言游戏】微信飞机大战 | PlaneFight(EasyX,drawAlpha绘制透明贴图,计时器,计帧器,游戏难度自动调整,接受鼠标消息,源码素材免费分享)
一.数据结构介绍 struct aircraft //所有飞机的结构体 typedef struct aircraft{ int type;//飞机类型 int HP;//剩余血量 int bomb_ ...
- cocos2d-x-3.3-022-仿微信飞机大战-开篇介绍
原文同步发布于我的wiki,查看原文或更新请移步: 点击打开链接 写在最前面 微信飞机大战,触控的大神JackyStudio 已经在他的专栏微信飞机大战讲解中完整细致的实现了一遍,基于cocos2d- ...
- 用Javascript模拟微信飞机大战游戏
最近微信的飞机大战非常流行,下载量非常高. 利用JS进行模拟制作了一个简单的飞机大战[此源码有很多地方可以进行重构和优化] [此游戏中没有使用HTML5 任何浏览器都可以运行]. 效果图: 原理:利用 ...
- 仿雷电——飞机大战类游戏Ⅰ
文章目录 简介 第一阶段:游戏界面的绘画及图片加载 1.添加背景图片 第二阶段:使用多线程让动画动起来 第三阶段:键盘操控飞机 第四阶段:炮弹和飞机碰撞,爆炸 第五阶段:显示分数 简介 我们仿照 QQ ...
- cocos2d-x-3.3-024-仿微信飞机大战-如何引爆炸弹-实现范围攻击
原文同步发布于我的wiki,查看原文或更新请移步: 点击打开链接 承上文 先回答拓展思考里的问题,'物理引擎可否用来做碰撞检测?',答案是肯定的,具体见下面 cocos2d-x-3.3-019-碰撞检 ...
- 【cocos2d-x入门实战】微信飞机大战之十:UFO层特殊道具
原创作品,转载请标明:http://blog.csdn.net/jackystudio/article/details/11961795 游戏的趣味性就在于不时的给你一些惊喜.当然如果只是简单的子弹打 ...
最新文章
- 学计算机应用好还是汽车维修好,大学汽车运用与维修专业怎么样_学什么_前景好吗-520吉他网...
- 图灵访谈:柳泽大辅谈如何想出好创意
- Docker 容器技术 — Compose 编排
- java lambda 局部变量_java Lambda表达式访问局部变量详细介绍
- 支持 Drupal 的 虚拟空间
- Keil C51,内存与指针
- mysql数据库商业版与社区版的区别
- 痛!做C#半年,挣的不如做AI1个月?”看到第二句泪目……
- android驱动测试,Android: 通过 cucumber 驱动 monkey 做稳定性测试
- python人口普查数据数据分析_美国人口普查数据可视化探索和收入水平预测建模...
- 【嵌入式技术】Atmega128串口详解
- 米家电磁炉显示e10_MIJIA 米家 电磁炉
- [4G5G专题-8]:RRU 峰均比降低技术CFR(波峰系数削减)
- gst 测试摄像头命令
- Java Audio Video Encoder
- 语言-汉语-官话:官话
- org.apache.hadoop.hdfs.qjournal.client.QuorumException: Unable to check if JNs are ready for formatt
- top邮箱怎么登录,解决方案
- Wind安装程序出现x80070652错误问题
- ieda永久破解!!!
热门文章
- Meteor:前后端数据协作机制
- 地大计算机学院研究生调剂,中国地质大学关于2021年硕士研究生调剂条件的内容...
- hugegraph 分组排序(gremlin)
- Java实习生工作总结(二)
- 【xlwings api语言参考】Range.FindNext 方法
- USB学习笔记——OTG功能
- Redis事件驱动框架
- [86]ubuntu16.04下安装64位谷歌Chrome浏览器
- 廖的python教程_廖雪峰的Python教程教程-02
- canvas实现剪切蒙层