cocos2d-x教程:太空游戏

2023-12-11 09:40
文章标签 教程 游戏 cocos2d 太空

本文主要是介绍cocos2d-x教程:太空游戏,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

     原文来自:http://www.raywenderlich.com/33752/cocos2d-x-tutorial-for-ios-and-android-space-game

     第一次翻译,本身自己英语也不好,还好有谷歌翻译,加上是初学者,很多地方也不是很明白,不对的地方大家直接指出来。

    我这里只关注了IOS的部分,目前我用的是Cocos2d-x 2.2.1版本。

Getting Started

首先,从这里下载太空游戏资源包 ,然后解压到你的磁盘上。

      然后将文件单个的放到工程的Resources目录下,就像这样:



   加入一个太空船

  1. 让我们尝试看一下这样是否可行,打开工程的Classes\HelloWorldScene.h,添加下面的代码到HelloWorldScene类成员变量声明的地方。(为了偷懒不写命名空间,先添加宏USING_NS_CC;)    

CCSize visibleSize;
CCSpriteBatchNode *_batchNode;
CCSprite *_ship;


这里创建了两个私有的成员变量,一个是精灵批量节点,另一个表示太空船。

接着切换到HelloWorldScene.cpp文件,进入init()函数,从if语句的后面开始删除后面的代码,直到return true(不删除);

   2.     添加一个菜单项到init()最后,然后再添加下面的代码:

    visibleSize = CCDirector::sharedDirector()->getVisibleSize();_batchNode = CCSpriteBatchNode::create("Sprites.pvr.ccz");this->addChild(_batchNode);CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("Sprites.plist");_ship = CCSprite::createWithSpriteFrameName("SpaceFlier_sm_1.png");_ship->setPosition(ccp(visibleSize.width*0.1,visibleSize.height*0.5));_batchNode->addChild(_ship,1);


编译->运行,你将会看到一艘太空船出现在模拟器的屏幕上。



添加视图差滚动

接着,用parallax scrolling来让太空背景滚动起来是一个比较吊的方法。

然后,在HelloWorldScene.h中加一些私有的成员变量:

    CCParallaxNode *_backgroundNode;CCSprite *_spacedust1;CCSprite *_spacedust2;CCSprite *_planetsunrise;CCSprite *_galaxy;CCSprite *_spacialanomaly;CCSprite *_spacialanomaly2;


HelloWorldScene.cppinit()方法中添加:(在return true;的前面)

    _spacedust1 = CCSprite::create("bg_front_spacedust.png");_spacedust2 = CCSprite::create("bg_front_spacedust.png");_planetsunrise = CCSprite::create("bg_planetsunrise.png");_galaxy = CCSprite::create("bg_galaxy.png");_spacialanomaly = CCSprite::create("bg_spacialanomaly.png");_spacialanomaly2 = CCSprite::create("bg_spacialanomaly2.png");CCPoint dustSpeed = ccp(0.1,0.1);CCPoint bgSpeed = ccp(0.05,0.05);_backgroundNode->addChild(_spacedust1, 0, dustSpeed, ccp(0, visibleSize.height/2));_backgroundNode->addChild(_spacedust2, 0, dustSpeed,ccp(_spacedust1->getContentSize().width,visibleSize.height/2));_backgroundNode->addChild(_galaxy, -1, bgSpeed, ccp(0, visibleSize.height * 0.7));_backgroundNode->addChild(_planetsunrise, -1 , bgSpeed, ccp(600, visibleSize.height * 0));_backgroundNode->addChild(_spacialanomaly, -1, bgSpeed, ccp(900, visibleSize.height * 0.3));_backgroundNode->addChild(_spacialanomaly2, -1, bgSpeed, ccp(1500, visibleSize.height * 0.9));



编译->运行,你将看到这样的界面:



现在是让背景滚动的时候了,首先在HelloWorldScene.h中声明update方法——你可能会随便添加到private区或者public区,但是update方法是作为内部用,所以更适合加到private区。

 void update(float dt);

然后到HelloWordScene.cpp中去实现它:

void HelloWorld::update(float dt)
{CCPoint backgroundScrollVert = ccp(-1000,0);_backgroundNode->setPosition(ccpAdd(_backgroundNode->getPosition(), ccpMult(backgroundScrollVert, dt)));
}


最后,在init()函数返回前调用scheduleUpdate():

this->scheduleUpdate();

编译->运行,你就会看到背景滚动起来了。

Continuous Scrolling

但是,你会注意到背景滚出了屏幕边界,就没有重复滚了,你应该修改它。

在工程中,我们新建一个C++的类文件,命名为CCParallaxNodeExtras:

这样,我们的工程中就多增加了两个文件:



然后,用下面的代码替换掉CCParallaxNodeExtras.h中的内容:

#ifndef __SpaceGame__CCParallaxNodeExtras__
#define __SpaceGame__CCParallaxNodeExtras__#include "cocos2d.h"
USING_NS_CC;
class CCParallaxNodeExtras:public CCParallaxNode
{
public:CCParallaxNodeExtras();static CCParallaxNodeExtras *node();void incrementOffset(CCPoint offset,CCNode *node);
};#endif /* defined(__SpaceGame__CCParallaxNodeExtras__) */


这个类继承了CCParallaxNode,新加了incrementOffset方法用来更新parallax node的子节点的位置。背景从左边移出的部分就会加到背景的右边,形成连续滚动的效果。


接着,用下面的代码替换掉CCParallaxNodeExtras.cpp中的内容:

#include "CCParallaxNodeExtras.h"class CCPointObject : CCObject
{CC_SYNTHESIZE(CCPoint, m_tRatio, Ratio);CC_SYNTHESIZE(CCPoint, m_tOffset, Offset);CC_SYNTHESIZE(CCNode*, m_pChild, Child);
};CCParallaxNodeExtras::CCParallaxNodeExtras()
{CCParallaxNode();
}CCParallaxNodeExtras* CCParallaxNodeExtras::node()
{return new CCParallaxNodeExtras();
}void CCParallaxNodeExtras::incrementOffset(cocos2d::CCPoint offset, cocos2d::CCNode *node)
{for (int i=0; i<m_pParallaxArray->num; ++i) {CCPointObject *point = (CCPointObject*)m_pParallaxArray->arr[i];CCNode *curNode = point->getChild();if (curNode->isEqual(node)) {point->setOffset(ccpAdd(point->getOffset(), offset));break;}}
}



next,在HelloWorldScene.h中添加头文件:

#include "CCParallaxNodeExtras.h"


then,改变_backgroundNode的定义,如下

CCParallaxNodeExtras *_backgroundNode;

.cpp文件中:

_backgroundNode = CCParallaxNodeExtras::node();


finally,把下面代码加到update方法中:

CCArray *spaceDusts = CCArray::createWithCapacity(2);spaceDusts->addObject(_spacedust1);spaceDusts->addObject(_spacedust2);for (int i=0; i<spaceDusts->count(); ++i) {CCSprite *spaceDust = (CCSprite*)(spaceDusts->objectAtIndex(i));float xPosition = _backgroundNode->convertToWorldSpace(spaceDust->getPosition()).x;float size = spaceDust->getContentSize().width;if (xPosition < -size/2) {_backgroundNode->incrementOffset(ccp(spaceDust->getContentSize().width*2,0), spaceDust);}}CCArray *backGrounds = CCArray::createWithCapacity(4);backGrounds->addObject(_galaxy);backGrounds->addObject(_planetsunrise);backGrounds->addObject(_spacialanomaly);backGrounds->addObject(_spacialanomaly2);for (int i=0; i<backGrounds->count(); ++i) {CCSprite *background = (CCSprite*)backGrounds->objectAtIndex(i);float xPosition = _backgroundNode->convertToWorldSpace(background->getPosition()).x;float size = background->getContentSize().width;if (xPosition < -size) {_backgroundNode->incrementOffset(ccp(2000, 0), background);}}



CCArray是基于STL的,用createWithCapacity构造方法将会自动帮你释放对象。

编译->运行,现在你的背景就能无限的滚动了!


Adding Stars

添加星星相当简单,只需在init()方法中加入:

 HelloWorld::addChild(CCParticleSystemQuad::create("Stars1.plist"));HelloWorld::addChild(CCParticleSystemQuad::create("Stars2.plist"));HelloWorld::addChild(CCParticleSystemQuad::create("Stars3.plist"));


Moving the Ship with Accelerometer

cocos2d-x 提供了围绕加速器输入的一个抽象层。来看看它是怎么工作的?

First,在HelloWordScene.h中加入一个新的private变量:

float _shipPointPerSecY;


then,添加一个public方法:

virtual void didAccelerate(CCAcceleration *pAccelerationValue);

then, 在init()中让加速计可用:

this->setAccelerometerEnabled(true);

next,在HelloWordScene.cpp中实现上面的方法:

 void HelloWorld::didAccelerate(cocos2d::CCAcceleration *pAccelerationValue)
{
#define KFILTERINGFACTOR 0.1
#define KRESTACCELX -0.6
#define KSHIPMAXPOINTSPERSEC (visibleSize.height*0.5)
#define KMAXDIFFX 0.2double rollingX;pAccelerationValue->x = pAccelerationValue->y;rollingX = (pAccelerationValue->x * KFILTERINGFACTOR) + (rollingX * (1.0 - KFILTERINGFACTOR));float accelX = pAccelerationValue->x - rollingX;float accelDiff = accelX - KRESTACCELX;float accelFraction = accelDiff / KMAXDIFFX;_shipPointPerSecY = KSHIPMAXPOINTSPERSEC * accelFraction;
}


finally,在update方法后面添加下面代码:

    float maxY = visibleSize.height - _ship->getContentSize().height/2;float minY = _ship->getContentSize().height/2;float diff = _shipPointPerSecY * dt;float newY = _ship->getPosition().y + diff;newY = MIN(MAX(newY, minY), maxY);_ship->setPosition(ccp(_ship->getPosition().x,newY));


didAccelerate方法的参数提供了一个包含x,y,z加速计数据信息CCAcceleration类型的变量,在这篇cocos2d-x教程中,你只要关心加速计上的x,就能让你的太空船在跟着手机旋转。

编译->运行,来看看效果。(加速计在模拟器上没有效果的,所以要用真机才能看到效果)


Adding Asteroids(小行星)

添加一些小行星到游戏中,同样先在HelloWordScene.h中加入private成员变量:

    CCArray *_asteroids;int _nextAsteroid;float _nextAsteroidSpawn;


then,添加一些public方法:

    float randomValueBetween(float low,float high);void setInvisible(CCNode *node);float getTimeTick();


next,去实现这些方法:

float HelloWorld::randomValueBetween(float low, float high)
{return (((float)arc4random() / 0xFFFFFFFFu) * (high - low)) + low;
}float HelloWorld::getTimeTick()
{timeval time;gettimeofday(&time, NULL);unsigned long millisecs = (time.tv_sec * 1000) + (time.tv_usec / 1000);return (float)millisecs;
}


randomValueBetween是一个辅助方法,用来获取在一个浮点数范围内的随机数。

getTimeTick是一个可移植的方法,用来获取以毫秒为单位的时间。(作为一个跨平台方法,替代了CACurrentMediaTime,但产生的是毫秒而不是秒)

next,为了创建一个asteroids数组,添加下面的代码到init()中。

#define KNUMASTEROIDS 15_asteroids = new CCArray();for (int i=0; i<KNUMASTEROIDS; ++i) {CCSprite *asteroid = CCSprite::createWithSpriteFrameName("asteroid.png");asteroid->setVisible(false);_batchNode->addChild(asteroid);_asteroids->addObject(asteroid);}


这里,用CCArray类来存储CCSprite类型的对象,注意你是手动new出来的(而不是用arrayWithCapacity)是为了避免autorelease机制。

finally,添加下面代码到update方法中:

    float curTimeMillis = getTimeTick();if (curTimeMillis > _nextAsteroidSpawn){float randMillisecs = randomValueBetween(0.2, 1.0) * 1000;_nextAsteroidSpawn = randMillisecs + curTimeMillis;float randY = randomValueBetween(0.0, visibleSize.height);float randDuration = randomValueBetween(2.0, 10.0);CCSprite *asteroid = (CCSprite*)_asteroids->objectAtIndex(_nextAsteroid);_nextAsteroid++;if (_nextAsteroid >= _asteroids->count()) {_nextAsteroid = 0;}asteroid->stopAllActions();asteroid->setPosition(ccp(visibleSize.width + asteroid->getContentSize().width/2,randY));asteroid->setVisible(true);asteroid->runAction(CCSequence::create(CCMoveBy::create(randDuration, ccp(-visibleSize.width - asteroid->getContentSize().width, 0)),CCCallFuncN::create(this,callfuncN_selector(HelloWorld::setInvisible)),NULL));


注意:因为CCSequence::actions方法是被定义为具有可变数目的参数,你可能想忽略最后的NULL参数,因为它在C++中是可以这样的。

           但是为了兼容性,cocos2d-x开发者决定保持与Cocos2d兼容,这就需要用NULL来结尾,如果你没有加NULL的话,程序可能会崩溃。

最后一步,添加setInvisible回调方法:

void HelloWorld::setInvisible(cocos2d::CCNode *node)
{node->setVisible(false);
}


编译->运行,你就会看到下面的结果:出现了很多小行星



Shooting Lasers(激光射击)

到了让太空船射击的时候了,像以前一样添加private变量:

    CCArray *_shipLasers;int _nextShipLaser;


再添加public方法:

virtual void ccTouchesBegan(CCSet *touches,CCEvent *evnet);


then,还是在init()中添加下面代码:

#define KNUMLASERS 5_nextShipLaser = 0;_shipLasers = new CCArray();for (int i=0; i< KNUMLASERS; ++i) {CCSprite* shipLaser = CCSprite::createWithSpriteFrameName("laserbeam_blue.png");shipLaser->setVisible(false);_batchNode->addChild(shipLaser);_shipLasers->addObject(shipLaser);}this->setTouchEnabled(true);


finally,实现出处TouchesBegan 方法:

void HelloWorld::ccTouchesBegan(cocos2d::CCSet *touches, cocos2d::CCEvent *evnet)
{CCSprite *shipLaser = (CCSprite*)_shipLasers->objectAtIndex(_nextShipLaser++);if (_nextShipLaser >= _shipLasers->count()){_nextShipLaser = 0;}shipLaser->setPosition(ccpAdd(_ship->getPosition(), ccp(shipLaser->getContentSize().width/2,0)));shipLaser->setVisible(true);shipLaser->stopAllActions();shipLaser->runAction(CCSequence::create(CCMoveBy::create(0.5, ccp(visibleSize.width, 0)),CCCallFuncN::create(this, callfuncN_selector(HelloWorld::setInvisible)),NULL));}


编译->运行,点击屏幕就能看到我们发射的激光了




Basic Collision Detection(基本碰撞检测)

next,你将添加一些代码来检测激光和小行星的碰撞,当激光打到小行星时,发生爆炸。


first,添加private变量:

int _lives;


then,在update方法中添加:

    CCObject *asteroid1;CCObject *shipLaser1;CCARRAY_FOREACH(_asteroids, asteroid1){CCSprite* asteroid = (CCSprite*)asteroid1;if (!asteroid->isVisible()){continue;}CCARRAY_FOREACH(_shipLasers, shipLaser1){CCSprite* shipLaser = (CCSprite*)shipLaser1;if (!shipLaser->isVisible()){continue;}if (shipLaser->boundingBox().intersectsRect(asteroid->boundingBox())){shipLaser->setVisible(false);asteroid->setVisible(false);continue;}}if (_ship->boundingBox().intersectsRect(asteroid->boundingBox())){asteroid->setVisible(false);_ship->runAction(CCBlink::create(1.0, 9));_lives-- ;}}



编译->运行,你就可以炸毁小行星了!

当然,你会注意到当激光打到小行星,并没有爆炸效果,因为我们没有给它添加爆炸粒子效果。前面在添加星星的时候,我们用到了粒子系统,这个问题留给读者。

Win/Lose Detection(输赢检测)

HelloWorldScene.h中类定义前面加入一个枚举:

typedef enum{KENDREASONWIN,KENDREASONLOSE
}EndReason;


然后是两个private成员变量:

    double _gameOverTime;bool _gameOver;


接着是两个private成员方法:

    void endScene(EndReason endReason);void restartTapped();


then,进入init()方法,加入:

    _lives = 3;double curTime = getTimeTick();_gameOverTime = curTime + 30000;


update的中加入:

    if (_lives <=0) {_ship->stopAllActions();_ship->setVisible(false);this->endScene(KENDREASONLOSE);}else if(curTimeMillis>= _gameOverTime){this->endScene(KENDREASONWIN);}


finally,实现刚才的那两个方法:

void HelloWorld::restartTapped()
{CCDirector::sharedDirector()->replaceScene(CCTransitionZoomFlipX::create(0.5, this->scene()));this->scheduleUpdate();
}
void HelloWorld::endScene(EndReason endReason)
{if (_gameOver) {return;}_gameOver = true;char message[10] = "You Win";if (endReason == KENDREASONLOSE) {strcpy(message, "You Lose");}CCLabelBMFont *label = CCLabelBMFont::create(message, "Arial.fnt");label->setScale(0.1);label->setPosition(ccp(visibleSize.width/2,visibleSize.height/2));this->addChild(label);strcpy(message, "Restart");CCLabelBMFont *restartLabel = CCLabelBMFont::create(message, "Arial.fnt");CCMenuItemLabel *restartItem = CCMenuItemLabel::create(restartLabel, this, menu_selector(HelloWorld::restartTapped));restartItem->setScale(0.1);restartItem->setPosition(ccp(visibleSize.width/2, visibleSize.height*0.4));CCMenu *menu = CCMenu::create(restartItem,NULL);menu->setPosition(CCPointZero);this->addChild(menu);restartItem->runAction(CCScaleTo::create(0.5, 1.0));label->runAction(CCScaleTo::create(0.5, 1.0));this->unscheduleUpdate();}


编译->运行,如果你受伤多次,你就会死!


音效

HelloWordScene.cpp的顶部加入所需的头文件和命名空间

#include "SimpleAudioEngine.h"
using namespace CocosDenshion;


init()返回前加入:

    SimpleAudioEngine::sharedEngine()->playBackgroundMusic("SpaceGame.wav", true);SimpleAudioEngine::sharedEngine()->preloadEffect("explosion_large.wav");SimpleAudioEngine::sharedEngine()->preloadEffect("laser_ship.wav");


当激光打到小行星时,加入爆炸声,也就是update()方法中:(绿色部分)

if (shipLaser->boundingBox().intersectsRect(asteroid->boundingBox())){<span style="color:#006600;"> SimpleAudioEngine::sharedEngine()->playEffect("explosion_large.wav");</span>shipLaser->setVisible(false);asteroid->setVisible(false);continue;}


最后就是发射激光声,ccTouchesBegan()的开头加入:

 SimpleAudioEngine::sharedEngine()->playEffect("laser_ship.wav");

编译->运行,还不错吧,算是完成了!




最后,完整的太空游戏代码点击这里下载。

 



这篇关于cocos2d-x教程:太空游戏的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/480250

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

国产游戏崛起:技术革新与文化自信的双重推动

近年来,国产游戏行业发展迅猛,技术水平和作品质量均得到了显著提升。特别是以《黑神话:悟空》为代表的一系列优秀作品,成功打破了过去中国游戏市场以手游和网游为主的局限,向全球玩家展示了中国在单机游戏领域的实力与潜力。随着中国开发者在画面渲染、物理引擎、AI 技术和服务器架构等方面取得了显著进展,国产游戏正逐步赢得国际市场的认可。然而,面对全球游戏行业的激烈竞争,国产游戏技术依然面临诸多挑战,未来的

沁恒CH32在MounRiver Studio上环境配置以及使用详细教程

目录 1.  RISC-V简介 2.  CPU架构现状 3.  MounRiver Studio软件下载 4.  MounRiver Studio软件安装 5.  MounRiver Studio软件介绍 6.  创建工程 7.  编译代码 1.  RISC-V简介         RISC就是精简指令集计算机(Reduced Instruction SetCom

前端技术(七)——less 教程

一、less简介 1. less是什么? less是一种动态样式语言,属于css预处理器的范畴,它扩展了CSS语言,增加了变量、Mixin、函数等特性,使CSS 更易维护和扩展LESS 既可以在 客户端 上运行 ,也可以借助Node.js在服务端运行。 less的中文官网:https://lesscss.cn/ 2. less编译工具 koala 官网 http://koala-app.

【Shiro】Shiro 的学习教程(三)之 SpringBoot 集成 Shiro

目录 1、环境准备2、引入 Shiro3、实现认证、退出3.1、使用死数据实现3.2、引入数据库,添加注册功能后端代码前端代码 3.3、MD5、Salt 的认证流程 4.、实现授权4.1、基于角色授权4.2、基于资源授权 5、引入缓存5.1、EhCache 实现缓存5.2、集成 Redis 实现 Shiro 缓存 1、环境准备 新建一个 SpringBoot 工程,引入依赖:

火柴游戏java版

代码 /*** 火柴游戏* <p>* <li>有24根火柴</li>* <li>组成 A + B = C 等式</li>* <li>总共有多少种适合方式?</li>* <br>* <h>分析:</h>* <li>除去"+"、"="四根,最多可用火柴根数20根。</li>* <li>全部用两根组合成"1",最大数值为1111。使用枚举法,A和B范围在0~1111,C为A+B。判断</li>** @

国产游戏行业的崛起与挑战:技术创新引领未来

国产游戏行业的崛起与挑战:技术创新引领未来 近年来,国产游戏行业蓬勃发展,技术水平不断提升,许多优秀作品在国际市场上崭露头角。从画面渲染到物理引擎,从AI技术到服务器架构,国产游戏已实现质的飞跃。然而,面对全球游戏市场的激烈竞争,国产游戏技术仍然面临诸多挑战。本文将探讨这些挑战,并展望未来的机遇,深入分析IT技术的创新将如何推动行业发展。 国产游戏技术现状 国产游戏在画面渲染、物理引擎、AI

Windows环境利用VS2022编译 libvpx 源码教程

libvpx libvpx 是一个开源的视频编码库,由 WebM 项目开发和维护,专门用于 VP8 和 VP9 视频编码格式的编解码处理。它支持高质量的视频压缩,广泛应用于视频会议、在线教育、视频直播服务等多种场景中。libvpx 的特点包括跨平台兼容性、硬件加速支持以及灵活的接口设计,使其可以轻松集成到各种应用程序中。 libvpx 的安装和配置过程相对简单,用户可以从官方网站下载源代码