上一篇:【二】仿微信飞机大战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相关推荐

  1. Android游戏之仿 微信飞机大战

    暑假实训的一个程序,也是我第一次接触java和android开发,模仿微信的飞机大战,效果图如下:                 一:素材整理 素材来自网络,下载地址在此:http://downlo ...

  2. cocos2dx一仿微信飞机大战游戏实战一

    学习cocos2dx的新手教程实例,简单做个打飞机的小游戏,嗯,先运行看看游戏的效果: 下面我们就开始编写吧,首先我们要解决的几个问题是这个游戏的设计思路,微信的飞机大战游戏,有几个技术点,一是游戏背 ...

  3. JavaScript趣味编程--仿微信飞机大战游戏--1.画飞机

    之前的文章已经介绍了如何使用canvas来画正方形,这次介绍如何使用canvas来画一张图片. 1.新建项目 本次使用的工具Aptana Studio 3,打开软件之后,选择File->New- ...

  4. 【C语言游戏】微信飞机大战 | PlaneFight(EasyX,drawAlpha绘制透明贴图,计时器,计帧器,游戏难度自动调整,接受鼠标消息,源码素材免费分享)

    一.数据结构介绍 struct aircraft //所有飞机的结构体 typedef struct aircraft{ int type;//飞机类型 int HP;//剩余血量 int bomb_ ...

  5. cocos2d-x-3.3-022-仿微信飞机大战-开篇介绍

    原文同步发布于我的wiki,查看原文或更新请移步: 点击打开链接 写在最前面 微信飞机大战,触控的大神JackyStudio 已经在他的专栏微信飞机大战讲解中完整细致的实现了一遍,基于cocos2d- ...

  6. 用Javascript模拟微信飞机大战游戏

    最近微信的飞机大战非常流行,下载量非常高. 利用JS进行模拟制作了一个简单的飞机大战[此源码有很多地方可以进行重构和优化] [此游戏中没有使用HTML5 任何浏览器都可以运行]. 效果图: 原理:利用 ...

  7. 仿雷电——飞机大战类游戏Ⅰ

    文章目录 简介 第一阶段:游戏界面的绘画及图片加载 1.添加背景图片 第二阶段:使用多线程让动画动起来 第三阶段:键盘操控飞机 第四阶段:炮弹和飞机碰撞,爆炸 第五阶段:显示分数 简介 我们仿照 QQ ...

  8. cocos2d-x-3.3-024-仿微信飞机大战-如何引爆炸弹-实现范围攻击

    原文同步发布于我的wiki,查看原文或更新请移步: 点击打开链接 承上文 先回答拓展思考里的问题,'物理引擎可否用来做碰撞检测?',答案是肯定的,具体见下面 cocos2d-x-3.3-019-碰撞检 ...

  9. 【cocos2d-x入门实战】微信飞机大战之十:UFO层特殊道具

    原创作品,转载请标明:http://blog.csdn.net/jackystudio/article/details/11961795 游戏的趣味性就在于不时的给你一些惊喜.当然如果只是简单的子弹打 ...

最新文章

  1. 学计算机应用好还是汽车维修好,大学汽车运用与维修专业怎么样_学什么_前景好吗-520吉他网...
  2. 图灵访谈:柳泽大辅谈如何想出好创意
  3. Docker 容器技术 — Compose 编排
  4. java lambda 局部变量_java Lambda表达式访问局部变量详细介绍
  5. 支持 Drupal 的 虚拟空间
  6. Keil C51,内存与指针
  7. mysql数据库商业版与社区版的区别
  8. 痛!做C#半年,挣的不如做AI1个月?”看到第二句泪目……
  9. android驱动测试,Android: 通过 cucumber 驱动 monkey 做稳定性测试
  10. python人口普查数据数据分析_美国人口普查数据可视化探索和收入水平预测建模...
  11. 【嵌入式技术】Atmega128串口详解
  12. 米家电磁炉显示e10_MIJIA 米家 电磁炉
  13. [4G5G专题-8]:RRU 峰均比降低技术CFR(波峰系数削减)
  14. gst 测试摄像头命令
  15. Java Audio Video Encoder
  16. 语言-汉语-官话:官话
  17. org.apache.hadoop.hdfs.qjournal.client.QuorumException: Unable to check if JNs are ready for formatt
  18. top邮箱怎么登录,解决方案
  19. Wind安装程序出现x80070652错误问题
  20. ieda永久破解!!!

热门文章

  1. Meteor:前后端数据协作机制
  2. 地大计算机学院研究生调剂,中国地质大学关于2021年硕士研究生调剂条件的内容...
  3. hugegraph 分组排序(gremlin)
  4. Java实习生工作总结(二)
  5. 【xlwings api语言参考】Range.FindNext 方法
  6. USB学习笔记——OTG功能
  7. Redis事件驱动框架
  8. [86]ubuntu16.04下安装64位谷歌Chrome浏览器
  9. 廖的python教程_廖雪峰的Python教程教程-02
  10. canvas实现剪切蒙层