C++ 与cocos2d-x-4.0完成太空飞机大战 (一)
动画演示
AppDelegate编码:AppDelegate.cpp
#include "AppDelegate.h"
#include "Action1.h"
#include "Util.h"
#if USE_AUDIO_ENGINE
#include "audio/include/AudioEngine.h"
using namespace cocos2d::experimental;
#endif
using namespace cocos2d;
using namespace std;
using namespace SpaceWar;
static cocos2d::Size designResolutionSize = cocos2d::Size(480, 800);
static cocos2d::Size smallResolutionSize = cocos2d::Size(480, 800);
static cocos2d::Size mediumResolutionSize = cocos2d::Size(1024, 768);
static cocos2d::Size largeResolutionSize = cocos2d::Size(2048, 1536);
AppDelegate::AppDelegate()
{
}
AppDelegate::~AppDelegate()
{
#if USE_AUDIO_ENGINE
AudioEngine::end();
#endif
}
void AppDelegate::initMultiResolution()
{
auto director = Director::getInstance();
auto glview = director->getOpenGLView();
glview->setDesignResolutionSize(designResolutionSize.width, designResolutionSize.height, ResolutionPolicy::NO_BORDER);
std::vector<std::string> searchPaths;
float scaleFactor = 1.0f;
Size frameSize = glview->getFrameSize();
if (frameSize.height > mediumResolutionSize.height)
{
searchPaths.push_back("res/HDR");
scaleFactor = largeResolutionSize.height / designResolutionSize.height;
}
else if (frameSize.height > smallResolutionSize.height)
{
searchPaths.push_back("res/HD");
scaleFactor = mediumResolutionSize.height / designResolutionSize.height;
}
else
{
searchPaths.push_back("res/SD");
scaleFactor = smallResolutionSize.height / designResolutionSize.height;
}
director->setContentScaleFactor(scaleFactor);
FileUtils::getInstance()->setSearchPaths(searchPaths);
}
void AppDelegate::initGLContextAttrs()
{
GLContextAttrs glContextAttrs = { 8, 8, 8, 8, 24, 8 };
GLView::setGLContextAttrs(glContextAttrs);
}
bool AppDelegate::applicationDidFinishLaunching()
{
initOpenGL();
initDirector();
initMultiResolution();
createAndRunScene();
return true;
}
void AppDelegate::initOpenGL()
{
auto director = Director::getInstance();
auto glview = director->getOpenGLView();
if (!glview) {
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) || (CC_TARGET_PLATFORM == CC_PLATFORM_LINUX)
glview = GLViewImpl::createWithRect("2", Rect(0, 0, designResolutionSize.width, designResolutionSize.height));
#else
glview = GLViewImpl::create("2");
#endif
director->setOpenGLView(glview);
}
}
void AppDelegate::initDirector()
{
auto director = Director::getInstance();
director->setAnimationInterval(1.0 / Util::FPS);
director->setDisplayStats(true);
}
void AppDelegate::createAndRunScene()
{
auto scene = Action1::createScene();
Director::getInstance()->runWithScene(scene);
}
void AppDelegate::applicationDidEnterBackground()
{
Director::getInstance()->stopAnimation();
}
void AppDelegate::applicationWillEnterForeground()
{
Director::getInstance()->startAnimation();
}
AppDelegate编码:AppDelegate.h
#pragma once
#include "cocos2d.h"
class AppDelegate : private cocos2d::Application
{
public:
AppDelegate();
virtual ~AppDelegate();
virtual void initGLContextAttrs();
virtual bool applicationDidFinishLaunching();
virtual void applicationDidEnterBackground();
virtual void applicationWillEnterForeground();
private:
void initOpenGL();
void initMultiResolution();
void initDirector();
void createAndRunScene();
};
关卡1场景编码:Action1.cpp
#include "Action1.h"
namespace SpaceWar {
Scene* Action1::createScene()
{
return Action1::create();
}
Action1::~Action1()
{
}
void Action1::bg_init()
{
auto bg_sprite = Sprite::create("action1.jpg");
if (bg_sprite != nullptr)
{
bg_sprite->setAnchorPoint(Vec2(0, 0));
bg_sprite->setPosition(Vec2(origin.x, origin.y));
Size bsize = bg_sprite->getContentSize();
this->addChild(bg_sprite, 0);
auto MoveBy = MoveBy::create(60.0f, Vec2(-(bsize.width - vSize.width), -1000));
auto MoveBy1 = MoveBy::create(60.0f, Vec2((bsize.width - vSize.width) / 2, -(bsize.height - 1000 - vSize.height - 100)));
auto actRepeatForever = CallFunc::create(std::bind(&Action1::bg_RepeatForever, this, bg_sprite));
auto sequence = Sequence::create(MoveBy, MoveBy1, actRepeatForever, NULL);
bg_sprite->runAction(sequence);
}
AudioEngine::play2d("m1.mp3", true, 1.0f);
}
void Action1::act_load()
{
es.actBase = this;
}
void Action1::bg_RepeatForever(Sprite* bg_sprite)
{
auto MoveBy1 = MoveBy::create(5.0f, Vec2(-100, 0));
auto MoveBy2 = MoveBy::create(5.0f, Vec2(100, 0));
auto sequence = Sequence::create(MoveBy1, MoveBy2, NULL);
auto repeat = RepeatForever::create(sequence);
bg_sprite->runAction(repeat);
}
bool Action1::onEnemyInScene(Node* nodeA, Node* nodeB)
{
EnemySprite* eSprite = dynamic_cast<EnemySprite*>(nodeA);
if (!eSprite->collisionEnable)
{
enemyNodes.insert({ nodeA->getName(), nodeA });
eSprite->collisionEnable = true;
}
return false;
}
bool Action1::onBulletCollisionEnemy(Node* nodeA, Node* nodeB)
{
BulletSprite* bSprite = dynamic_cast<BulletSprite*>(nodeA);
EnemySprite* eSprite = dynamic_cast<EnemySprite*>(nodeB);
if (eSprite->collisionEnable)
{
es.createChangeColorAnimate(nodeB);
eSprite->maxCollisionCount = eSprite->maxCollisionCount - bSprite->bulletPower;
if (eSprite->maxCollisionCount <= 0)
{
enemyNodes.erase(nodeB->getName());
addPlayerScore(bSprite->playerTag, eSprite->killScore);
es.createRuinAnimate(nodeB);
nodeB->removeFromParentAndCleanup(true);
}
}
nodeA->removeFromParentAndCleanup(true);
return false;
}
bool Action1::onBombCollisionEnemy(Node* nodeA, Node* nodeB)
{
EnemySprite* eSprite = dynamic_cast<EnemySprite*>(nodeB);
if (!eSprite->collisionEnable)
{
return false;
}
BombSprite* bSprite = dynamic_cast<BombSprite*>(nodeA);
eSprite->maxCollisionCount = eSprite->maxCollisionCount - bSprite->bombPower;
if (eSprite->maxCollisionCount <= 0)
{
enemyNodes.erase(nodeB->getName());
addPlayerScore(bSprite->playerTag, eSprite->killScore);
es.createRuinAnimate(nodeB);
nodeB->removeFromParentAndCleanup(true);
}
return false;
}
bool Action1::onAircraftCollisionEnemy(Node* nodeA, Node* nodeB)
{
AircraftSprite* aSprite = dynamic_cast<AircraftSprite*>(nodeA);
if (aSprite->collisionEnable == false)
{
return false;
}
EnemySprite* eSprite = dynamic_cast<EnemySprite*>(nodeB);
aSprite->maxCollisionCount = aSprite->maxCollisionCount - 1;
if (eSprite->collisionEnable)
{
eSprite->maxCollisionCount = eSprite->maxCollisionCount - 1;
if (eSprite->maxCollisionCount <= 0)
{
enemyNodes.erase(nodeB->getName());
addPlayerScore(aSprite->playerTag, eSprite->killScore);
es.createRuinAnimate(nodeB);
nodeB->removeFromParentAndCleanup(true);
}
}
if (aSprite->maxCollisionCount <= 0)
{
aircraftSpriteRuin(aSprite);
airL.createRuinAnimate(nodeA);
nodeA->removeFromParentAndCleanup(true);
}
return false;
}
void Action1::aircraftSpriteRuin(AircraftSprite* aSprite)
{
if (aSprite->armPower > 1 || aSprite->bombCount > 1)
{
RewardQueue rq;
rq.armPower = aSprite->armPower - 1;
rq.bombType = aSprite->bombType;
rq.bombCount = aSprite->bombCount - 1;
rq.x = aSprite->getPosition().x;
rq.y = aSprite->getPosition().y;
rewardQueue.push(rq);
}
if (aSprite->playerTag == 1)
{
airR.sprite = nullptr;
}
else
{
airL.sprite = nullptr;
}
}
bool Action1::onAircraftCollisionReward(Node* nodeA, Node* nodeB)
{
AircraftSprite* aSprite = dynamic_cast<AircraftSprite*>(nodeA);
RewardSprite* rSprite = dynamic_cast<RewardSprite*>(nodeB);
addPlayerScore(aSprite->playerTag, rSprite->rewardScore);
addPlayerSpeed(aSprite->playerTag, rSprite->airSpeed);
addPlayerPower(aSprite->playerTag, rSprite->armPower);
addPlayerArmType(aSprite->playerTag, rSprite->armType);
addPlayerMissileType(aSprite->playerTag, rSprite->missileType);
addPlayerBombCount(aSprite->playerTag, rSprite->bombCount);
addPlayerBombType(aSprite->playerTag, rSprite->bombType);
rewardPlayMusic(rSprite->rewardType);
nodeB->removeFromParentAndCleanup(true);
return false;
}
bool Action1::onContactBegin(PhysicsContact& contact)
{
auto nodeA = contact.getShapeA()->getBody()->getNode();
auto nodeB = contact.getShapeB()->getBody()->getNode();
if (nodeA && nodeB)
{
if (nodeA->getTag() == 10 && nodeB->getTag() == 1000)
{
return onEnemyInScene(nodeA, nodeB);
}
else if (nodeA->getTag() == 1000 && nodeB->getTag() == 10)
{
return onEnemyInScene(nodeB, nodeA);
}
else if (nodeA->getTag() == 5 && nodeB->getTag() == 10)
{
return onBulletCollisionEnemy(nodeA, nodeB);
}
else if (nodeA->getTag() == 10 && nodeB->getTag() == 5)
{
return onBulletCollisionEnemy(nodeB, nodeA);
}
else if (nodeA->getTag() == 6 && nodeB->getTag() == 10)
{
return onBombCollisionEnemy(nodeA, nodeB);
}
else if (nodeA->getTag() == 10 && nodeB->getTag() == 6)
{
return onBombCollisionEnemy(nodeB, nodeA);
}
else if (nodeA->getTag() == 100 && nodeB->getTag() == 10)
{
return onAircraftCollisionEnemy(nodeA, nodeB);
}
else if (nodeA->getTag() == 10 && nodeB->getTag() == 100)
{
return onAircraftCollisionEnemy(nodeB, nodeA);
}
else if (nodeA->getTag() == 100 && nodeB->getTag() == 50)
{
return onAircraftCollisionReward(nodeA, nodeB);
}
else if (nodeA->getTag() == 50 && nodeB->getTag() == 100)
{
return onAircraftCollisionReward(nodeB, nodeA);
}
}
return false;
}
void Action1::scheduleUpdate(float dt)
{
updateLable();
createAircrafts();
es.createEnemys();
reward.createReward();
while (!rewardQueue.empty())
{
RewardQueue rq = rewardQueue.front();
reward.createAirRewardSprite(Vec2(rq.x, rq.y), rq.armPower, rq.bombType, rq.bombCount);
rewardQueue.pop();
}
int rwCount = rewardScore.size();
if (airL.rewardPlayerCount < rwCount)
{
int rScore = rewardScore[airL.rewardPlayerCount];
if (airL.playerScore >= rScore)
{
addPlayers(0, 1);
++airL.rewardPlayerCount;
}
}
if (airR.rewardPlayerCount < rwCount)
{
int rScore = rewardScore[airR.rewardPlayerCount];
if (airR.playerScore >= rScore)
{
addPlayers(1, 1);
++airR.rewardPlayerCount;
}
}
}
}
关卡1场景编码:Action1.h
#pragma once
#include <list>
#include "cocos2d.h"
#include "audio/include/AudioEngine.h"
#include "EnemyScene1.h"
#include "ActionBase.h"
#include "Aircraft.h"
#include "Util.h"
#include "Control.h"
#include "ActionLabel.h"
#include "Reward.h"
using namespace cocos2d;
using namespace std;
namespace SpaceWar {
class Action1 : public ActionBase
{
public:
static Scene* createScene();
virtual ~Action1();
void bg_init();
void act_load();
void bg_RepeatForever(Sprite * bg_sprite);
bool onEnemyInScene(Node * nodeA, Node * nodeB);
bool onBulletCollisionEnemy(Node * nodeA, Node * nodeB);
bool onBombCollisionEnemy(Node * nodeA, Node * nodeB);
bool onAircraftCollisionEnemy(Node * nodeA, Node * nodeB);
void aircraftSpriteRuin(AircraftSprite * aSprite);
bool onAircraftCollisionReward(Node * nodeA, Node * nodeB);
bool onContactBegin(PhysicsContact& contact);
void scheduleUpdate(float dt);
CREATE_FUNC(Action1);
EnemyScene1 es;
};
}
关卡场景基类编码:ActionBase.cpp
#include "ActionBase.h"
namespace SpaceWar {
Scene* ActionBase::createScene()
{
return ActionBase::create();
}
bool ActionBase::init()
{
if (!Scene::initWithPhysics())
{
return false;
}
Director::getInstance()->setClearColor(Color4F(255, 255, 255, 255));
vSize = Director::getInstance()->getVisibleSize();
origin = Director::getInstance()->getVisibleOrigin();
frameTime = Director::getInstance()->getAnimationInterval();
airL.actBase = this;
airR.actBase = this;
bg_init();
int tag = 1000;
auto body = PhysicsBody::createEdgeBox(vSize, PHYSICSBODY_MATERIAL_DEFAULT, 3);
body->setCategoryBitmask(0b111);
body->setCollisionBitmask(0b000);
body->setContactTestBitmask(0b110);
body->setTag(tag);
auto edgeNode = Node::create();
edgeNode->setPosition(Point(vSize.width / 2, vSize.height / 2));
edgeNode->setPhysicsBody(body);
edgeNode->setTag(tag);
this->addChild(edgeNode);
auto closeItem = MenuItemImage::create("CloseNormal.png", "CloseSelected.png", CC_CALLBACK_1(ActionBase::menuCloseCallback, this));
if (closeItem != nullptr)
{
float x = origin.x + vSize.width - closeItem->getContentSize().width / 2;
float y = origin.y + closeItem->getContentSize().height / 2;
closeItem->setPosition(Vec2(x, y));
auto menu = Menu::create(closeItem, NULL);
menu->setPosition(Vec2::ZERO);
this->addChild(menu, 1);
}
actLabel.actBase = this;
actLabel.init();
reward.actBase = this;
reward.init();
auto contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin = CC_CALLBACK_1(ActionBase::onContactBegin, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);
auto listener = EventListenerKeyboard::create();
listener->onKeyPressed = CC_CALLBACK_2(ActionBase::onKeyPressed, this);
listener->onKeyReleased = CC_CALLBACK_2(ActionBase::onKeyReleased, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
schedule(CC_SCHEDULE_SELECTOR(ActionBase::scheduleUpdate), 0.1f);
schedule(CC_SCHEDULE_SELECTOR(ActionBase::scheduleUpdateMove), 1 / 60);
act_load();
return true;
}
bool ActionBase::anyRay(PhysicsWorld& world, const PhysicsRayCastInfo& info, void* data)
{
*((Point*)data) = info.contact;
return false;
}
void ActionBase::bg_init()
{
}
void ActionBase::act_load()
{
}
void ActionBase::createAircrafts()
{
if (airL.playerCount > 0 && airL.sprite == nullptr)
{
--airL.playerCount;
airL.init(0, 0);
this->addChild(airL.sprite, 1);
AudioEngine::play2d("fj_start.ogg", false, 0.2f);
}
if (airR.playerCount > 0 && airR.sprite == nullptr)
{
--airR.playerCount;
airR.init(1, 1);
this->addChild(airR.sprite, 1);
AudioEngine::play2d("fj_start.ogg", false, 0.2f);
}
}
void ActionBase::onKeyPressed(EventKeyboard::KeyCode keyCode, Event* event)
{
Util::onKeyPressed(keyCode, &colAct);
}
void ActionBase::onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event)
{
Util::onKeyReleased(keyCode, &colAct);
}
void ActionBase::scheduleUpdateMove(float dt)
{
airL.controlAction(0);
airR.controlAction(1);
}
bool ActionBase::onContactBegin(PhysicsContact & contact)
{
return false;
}
void ActionBase::updateLable()
{
actLabel.updateLable(&airL, &airR);
}
void ActionBase::rewardPlayMusic(int rmark)
{
if (rmark >= 0 && rmark < 20)
{
AudioEngine::play2d("reward_power.ogg", false, 0.5f);
}
else if (rmark >= 20 && rmark < 30)
{
AudioEngine::play2d("reward_money.ogg", false, 0.5f);
}
else if (rmark >= 30 && rmark < 50)
{
AudioEngine::play2d("reward_power.ogg", false, 0.5f);
}
}
void ActionBase::addPlayers(int tag, int count)
{
if (count < 0)
{
return;
}
AudioEngine::play2d("reward_play.ogg", false, 0.5f);
if (tag == 1)
{
airR.playerCount += count;
}
else
{
airL.playerCount += count;
}
}
void ActionBase::scheduleUpdate(float dt)
{
}
void ActionBase::addPlayerScore(int tag, int score)
{
if (score < 0)
{
return;
}
if (tag == 1)
{
airR.playerScore += score;
showScoreLabel(&airR, score);
}
else
{
airL.playerScore += score;
showScoreLabel(&airL, score);
}
}
void ActionBase::showScoreLabel(Aircraft* air, int score)
{
if (air->sprite == nullptr)
{
return;
}
auto scoreLabel = Label::createWithTTF("+" + to_string(score), "fonts/msyh.ttf", 14);
Color4B c4b = Color4B(255, 0, 0, 255);
if (scoreLabel != nullptr)
{
scoreLabel->setTextColor(c4b);
scoreLabel->setPosition(air->sprite->getPosition());
this->addChild(scoreLabel, 1);
auto moveBy = MoveBy::create(2.0f, Vec2(random(-40.0f, 40.0f), -100.0f));
scoreLabel->runAction(moveBy);
auto fadeOut = FadeOut::create(2.0f);
scoreLabel->runAction(fadeOut);
auto blink = Blink::create(2.0f, 40);
auto actRuin = CallFunc::create(std::bind(&ActionBase::removeRuinLabel, this, scoreLabel));
auto sequence1 = Sequence::create(blink, actRuin, NULL);
scoreLabel->runAction(sequence1);
}
}
void ActionBase::removeRuinLabel(Label* lable)
{
lable->removeFromParentAndCleanup(true);
}
void ActionBase::addPlayerSpeed(int tag, int speed)
{
if (speed < 0)
{
return;
}
if (tag == 1)
{
if (airR.sprite->airSpeed < 4)
{
airR.sprite->airSpeed += speed;
}
else
{
addPlayerScore(tag, 500);
}
}
else
{
if (airL.sprite->airSpeed < 4)
{
airL.sprite->airSpeed += speed;
}
else
{
addPlayerScore(tag, 500);
}
}
}
void ActionBase::addPlayerPower(int tag, int power)
{
if (power < 0)
{
return;
}
if (tag == 1)
{
if (airR.sprite->armPower < 6)
{
airR.sprite->armPower += power;
}
else
{
addPlayerScore(tag, 500);
}
}
else
{
if (airL.sprite->armPower < 6)
{
airL.sprite->armPower += power;
}
else
{
addPlayerScore(tag, 500);
}
}
}
void ActionBase::addPlayerArmType(int tag, int armType)
{
if (armType < 0)
{
return;
}
if (tag == 1)
{
if (airR.sprite->armType != armType)
{
airR.sprite->armType = armType;
}
else
{
addPlayerPower(tag, 1);
}
}
else
{
if (airL.sprite->armType != armType)
{
airL.sprite->armType = armType;
}
else
{
addPlayerPower(tag, 1);
}
}
}
void ActionBase::addPlayerMissilePower(int tag, int missilePower)
{
if (missilePower < 0)
{
return;
}
if (tag == 1)
{
if (airR.sprite->missilePower < 6)
{
airR.sprite->missilePower += missilePower;
}
else
{
addPlayerScore(tag, 500);
}
}
else
{
if (airL.sprite->missilePower < 6)
{
airL.sprite->missilePower += missilePower;
}
else
{
addPlayerScore(tag, 500);
}
}
}
void ActionBase::addPlayerMissileType(int tag, int missileType)
{
if (missileType < 0)
{
return;
}
if (tag == 1)
{
if (airR.sprite->missileType != missileType)
{
airR.sprite->missileType = missileType;
}
else
{
addPlayerMissilePower(tag, 1);
}
}
else
{
if (airL.sprite->missileType != missileType)
{
airL.sprite->missileType = missileType;
}
else
{
addPlayerMissilePower(tag, 1);
}
}
}
void ActionBase::addPlayerBombCount(int tag, int bombCount)
{
if (bombCount < 0)
{
return;
}
if (tag == 1)
{
if (airR.sprite->bombCount < 5)
{
airR.sprite->bombCount += bombCount;
}
else
{
addPlayerScore(tag, 500);
}
}
else
{
if (airL.sprite->bombCount < 5)
{
airL.sprite->bombCount += bombCount;
}
else
{
addPlayerScore(tag, 500);
}
}
}
void ActionBase::addPlayerBombType(int tag, int bombType)
{
if (bombType < 0)
{
return;
}
if (tag == 1)
{
if (airR.sprite->bombType != bombType)
{
airR.sprite->bombType = bombType;
}
addPlayerBombCount(tag, 1);
}
else
{
if (airL.sprite->bombType != bombType)
{
airL.sprite->bombType = bombType;
}
addPlayerBombCount(tag, 1);
}
}
void ActionBase::menuCloseCallback(Ref* pSender)
{
Director::getInstance()->end();
}
}
关卡场景基类编码:ActionBase.h
#pragma once
#include <map>
#include <list>
#include <vector>
#include <queue>
#include "cocos2d.h"
#include "audio/include/AudioEngine.h"
#include "EnemyScene1.h"
#include "Aircraft.h"
#include "Util.h"
#include "Control.h"
#include "ActionLabel.h"
#include "Reward.h"
#include "RewardQueue.h"
using namespace cocos2d;
using namespace std;
namespace SpaceWar {
class ActionBase : public cocos2d::Scene
{
public:
static Scene* createScene();
virtual bool init();
virtual bool anyRay(PhysicsWorld & world, const PhysicsRayCastInfo & info, void * data);
virtual void bg_init();
virtual void act_load();
virtual void createAircrafts();
virtual void menuCloseCallback(cocos2d::Ref* pSender);
virtual void onKeyPressed(EventKeyboard::KeyCode keyCode, Event* event);
virtual void onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event);
virtual void scheduleUpdateMove(float dt);
virtual bool onContactBegin(PhysicsContact& contact);
virtual void updateLable();
virtual void rewardPlayMusic(int rmark);
virtual void addPlayers(int tag, int count);
virtual void scheduleUpdate(float dt);
virtual void addPlayerScore(int tag, int score);
virtual void showScoreLabel(Aircraft* air, int score);
virtual void removeRuinLabel(Label* lable);
virtual void addPlayerSpeed(int tag, int speed);
virtual void addPlayerPower(int tag, int power);
virtual void addPlayerArmType(int tag, int armType);
virtual void addPlayerMissilePower(int tag, int missilePower);
virtual void addPlayerMissileType(int tag, int missileType);
virtual void addPlayerBombCount(int tag, int bombCount);
virtual void addPlayerBombType(int tag, int bombType);
Aircraft airL;
Aircraft airR;
Control colAct;
ActionLabel actLabel;
Reward reward;
float frameTime = 0.0f;
Size vSize;
Vec2 origin;
queue<RewardQueue> rewardQueue;
vector<int> rewardScore = { 1000, 5000, 10000, 50000, 100000, 500000, 1000000 };
map<string, Node*> enemyNodes;
};
}
C++ 与cocos2d-x-4.0完成太空飞机大战 (二)