2(d)怎样做

Cocos2d-x初学者教程 - 简书
下载简书移动应用
写了112723字,被166人关注,获得了405个喜欢
Cocos2d-x初学者教程
请保留此段版权声明:本文由@树上男爵郝鹏程[] 原创翻译,最初发表于,转载请务必注明出处。
原文:Cocos2d-x是一款快速、强大、易用的开源2D游戏引擎。它与苹果的Sprit Kit略像,但又有一大优势——跨平台。这意味着,开发者只需要写一个版本的代码就可以开发出能在iOS、Android、Windows Phone、Mac OS X、Windows Desktop和Linux上运行的游戏来。这对于游戏开发者来说意义重大。在此教程中,你将学会用Cocos2d-x和C++开发一个简单的2D游戏。是的——忍者来袭!注意:本教程假设你拥有C++开发的基础先修知识。如果你没有接触过C++,请学习后再来阅读。
下载Cocos2d-x的最新版本(www.cocos2d-x.org/download);本教程使用3.5版本。把文件下载下来,放到你想把Cocos2d-x安装到的地方,例如你的主目录,然后解压。打开Terminal和CD,进入你刚刚解压的文件夹。例如,如果你把项目放到了你的主目录里,那就运行如下命令:cd ~/cocos2d-x-3.5/现在,运行接下来这个命令:python setup.py这里配置了必要的shell环境变量。若系统出现提示,要求配置像 NDK_ROOT, ANDROID_SDK_ROOT和ANT_ROOT这些Android特有的变量,你只需按三次回车完成设置就好了。注意:Cocos2d需要你在电脑上安装Python 2.7以上的版本。如果你不清楚目前电脑的Python版本,可以在命令行中输入python,则版本信息就会被显示出来(然后按Ctrl-D关闭)。如果你安装了一个老版本的Python,请在下载安装最新版本。如下图所示,脚本文件提示执行另一条命令来完成安装:
Paste_Image.png
注意:使用不同的shell可能会导致你看到不同的输出结果。在上面的屏幕截图中,由于我使用了Bash,安装文件提示“source /Users/rwenderlich/bash_profile.”。但如果我用的是Zsh,那它就会提示让我运行“source /Users/rwenderlich/.zshrc”。按照说明输入命令。这里有一个节省时间的技巧:你可以在/Users/your_user_name这里使用波浪线(~),以此来减少你输入下面这条命令的长度:source ~/.zshrc
(or source ~/.bash_profile)此命令重新提交了你的shell配置,让它可以访问新变量。现在你可以从任一目录在Terminal中调用cocos命令了。运行下面的命令,创建一个名为SimpleGame的C++游戏模板:cocos new -l cpp -d ~/Cocos2d-x-Tutorial SimpleGame你的主目录里创建了一个名为Cocos2d-x-Tutorial的目录。其中,子目录SimpleGame存放了你的项目文件。注意:可以输入cocos --help或cocos -h来获取cocos子命令的相关信息。输入后缀“--help”或“-h”,你可以了解到子命令的各种选项,例如你可以输入cocos new -h来查看new命令的选项。在Finder中双击~/Cocos2d-x-Tutorial/SimpleGame/proj.ios_mac/SimpleGame.xcodeproj,在Xcode中打开项目。进入Xcode之后,请确保SimpleGame Mac处于活跃状态,如图所示:
Paste_Image.png
Cocos2d-x可以开发多种平台的游戏,但本教程将着重讲开发OS X应用。该项目可以很容易地向其他平台移植(是的,小事一桩!),本教程的最后部分将会简单讨论。在模板项目中编译并运行你的应用吧:
Paste_Image.png
分辨率设定
Cocos2d-x游戏默认被命名为“MyGame”,分辨率为960x640,但这些细节设定都很容易更改。打开AppDelegate.cpp,在AppDelegate::applicationDidFinishLaunching中找到如下一行:glview = GLViewImpl::create("My Game");将其替换为下面的代码:glview = GLViewImpl::createWithRect("SimpleGame", Rect(0,0, 480, 320), 1.0);这样,游戏名称被改为“SimpleGame”,分辨率也被设置成了与模板背景相适配的480x320。重新编译并运行新版应用,它变得更小了:
Paste_Image.png
注意一下你给createWithRect设定的第三个参数——1.0。这个参数将框架进行缩放,经常被用于测试比你的屏幕更大的分辨率。例如,想在一个小于的屏幕上测试分辨率的东西,你可以设定参数为0.5,以此将窗口缩小到960x540的大小。这样虽然改变了游戏在桌面设备上的框架大小,但它在iOS设备上就失效了;游戏的分辨率会自动适配iOS设备的屏幕大小。这里以iPhone6为例:
Paste_Image.png
你该如何处理多个分辨率呢?在本教程中,你将会创建基于960x640分辨率的单个游戏资源,然后在实际运行中将其进行必要的缩放。要想实现这一点,你需要在AppDelegate::applicationDidFinishLaunching中,找到director上setDisplayStats的上一行,添加以下代码:
Size designSize = Size(480,320);
Size resourceSize = Size(960,640);
director-&setContentScaleFactor(resourceSize.height / designSize.height);
director-&getOpenGLView()-&setDesignResolutionSize(
designSize.width, designSize.height, ResolutionPolicy::FIXED_HEIGHT);
上面的代码的作用如下:
定义了designSize——你创建游戏逻辑时使用的尺寸,并定义了resourceSize——你的资源所基于的分辨率。
必要的时候,这些代码会让游戏的对资源进行缩放,缩放会基于游戏的设计和提供的资源尺寸进行。参阅以查看更多关于Cocos2d-x处理分辨率问题的说明。添加精灵
接下来,点击下载,并且将其解压到方便的位置。全选你刚刚解压的SimpleGameResources文件夹中的文件,在你的Xcode项目中将它们拖入Resources组中。当有对话框弹出的时候,一定要在点Finish之前检查Copy items if needed, SimpleGame iOS 和 SimpleGame Mac。
Paste_Image.png
接下来,打开HelloWorldScene.h,在include cocos2d.h后面的地方添加以下代码:
using namespace cocos2d;这就指定了你会使用cocos2d这一命名空间(namespace);于是,你可以用Sprite来代替cocos2d::Sprite。倒也不是非这样不可,但这会让你的开发过程变得愉快一些。:]现在,你需要一个私有成员变量来指向你的player精灵。在HelloWorld的声明语句中添加以下代码:
然后,打开HelloWorldScene.cpp,将HelloWorld::init方法中的内容换成以下内容:
if ( !Layer::init() ) {
auto origin = Director::getInstance()-&getVisibleOrigin();
auto winSize = Director::getInstance()-&getVisibleSize();
auto background = DrawNode::create();
background-&drawSolidRect(origin, winSize, Color4F(0.6,0.6,0.6,1.0));
this-&addChild(background);
_player = Sprite::create("player.png");
_player-&setPosition(Vec2(winSize.width * 0.1, winSize.height * 0.5));
this-&addChild(_player);
下面是本方法的详细说明:
首先,调用父类的init方法。只有调用成功后你才能继续HelloWorldScene的安装。
其次,使用游戏的Director singleton来获取窗口的边界。
再次,创建DrawNode,绘制了一个填充屏幕的灰色矩形,并将其添加到场景中。这成为了游戏的背景。
最后,通过图像名称创建player精灵。将它放置在屏幕左边界10%距离的地方,垂直居中,并将其添加到场景中。编译并运行游戏;哈哈,父老乡亲们快来看啊,小忍者进村了!:]
Paste_Image.png
移动的怪物
忍者需要一个人生目标,所以得在场景里添加点怪物让他去打。为了让游戏更好玩,怪物最好能来回走动——否则就会看起来没啥挑战性。我们要在屏幕右侧很近的地方创建怪物,然后创建一个动作来让他们移动到左侧。首先,打开HelloWorldScene.h,并且添加如下的方法声明:
void addMonster(float dt);
然后,在HelloWorldScene.cpp中添加如下的方法实现:
void HelloWorld::addMonster(float dt) {
auto monster = Sprite::create("monster.png");
auto monsterContentSize = monster-&getContentSize();
auto selfContentSize = this-&getContentSize();
int minY = monsterContentSize.height/2;
int maxY = selfContentSize.height - monsterContentSize.height/2;
int rangeY = maxY - minY;
int randomY = (rand() % rangeY) + minY;
monster-&setPosition(Vec2(selfContentSize.width + monsterContentSize.width/2, randomY));
this-&addChild(monster);
int minDuration = 2.0;
int maxDuration = 4.0;
int rangeDuration = maxDuration - minD
int randomDuration = (rand() % rangeDuration) + minD
auto actionMove = MoveTo::create(randomDuration, Vec2(-monsterContentSize.width/2, randomY));
auto actionRemove = RemoveSelf::create();
monster-&runAction(Sequence::create(actionMove,actionRemove, nullptr));
虽然相对而言比较直白,但下面还是讲一下这些代码的作用:
本方法第一部分与之前对player做的相似:创建一个怪物的精灵,将其放置在紧靠屏幕右侧的地方。它的y轴坐标被设定为随机,这样才好玩。
接下来设定怪物动作的时长,本方法在2秒和4秒之间计算出了一个随机值。每个怪物都要在屏幕上移动相同的距离,所以时长的随机性导致了怪物们速度的随机性。
最后,本方法创建了一个让怪物从右到左横穿屏幕的动作,并且让怪物去执行这个动作。对此本文后面会有更详细的解释。Cocos2d-x提供了很多非常便捷的内置动作,它们可以帮助你随着时间轻松改变精灵的状态,包括移动动作、旋转动作、淡出动作、动画动作,等等。在此,你在怪物身上用到了3个动作:
MoveTo:在一定的时间内将对象从一个点移动到另一个点。
RemoveSelf:将一个节点从其父节点中移除,从而有效地将其从场景中“删除”。在本例中,当怪物变得不可见时,你使用此动作来把怪物从场景中移除。这非常重要,否则就会有无限多的怪物出现,最终耗尽设备的资源。
Sequence:允许你按顺序实现一系列的其他动作,每次实现一个。这意味着,你可以让怪物移动穿过整个场景,到达特定的位置之后再将其从屏幕上移除。在你的忍者粉墨登场之前,还有最后一件事情——你需要实际地调用这个方法来创建怪物。为了让游戏更有趣,你需要不停地量产怪物。很简单,在HelloWorld::init末尾return之前的地方,添加如下代码:
srand((unsigned int)time(nullptr));
this-&schedule(schedule_selector(HelloWorld::addMonster), 1.5);srand((unsigned int)time(nullptr));语句初始化了随机数生成器。如果不执行这一步,每次运行程序都会产生一样的随机数。这还叫什么随机啊对不对?:]之后,你向schedule方法传递HelloWorld::addMonster,每隔1.5秒它将调用一次addMonster()。这里,Cocos2dx使用了C++的指针来整合函数。如果你不太懂它的原理的话,请去查阅更多信息。好了!编译并运行你的项目;现在你应该可以看到怪物们正在欢乐地(或者本例中它们看上去其实挺愤怒的!)在屏幕中来回移动了:
Paste_Image.png
勇敢的小忍者需要保护自己。在游戏中有很多种方式可以实现开火,但在本例中你将使用点击屏幕的方式,将飞镖朝玩家点击屏幕的所在的方向发射出去。biubiu!:]方便起见,你要用MoveTo动作来完成这个效果——现在我们不得不做点数学题了。MoveTo动作需要为飞镖设定一个目的地,但是你不能直接使用输入的地址,因为那个点只代表了发射时候相对于玩家的方向。你需要让飞镖一直沿着这个方向移动直到最终到达屏幕外的目的地。下图说明了这一情况:
Paste_Image.png
从原始点到接触点的x坐标距离和y坐标距离组成了一个小三角形;你只需要按照同样的比率做一个大三角形——你还清楚自己希望一个端点是处于屏幕之外的。这些计算是以Cocos2d-x所包括的向量数学程序来执行的。但是,在你能够计算往何处移动之前,你需要启用输入事件操作来获取用户点击的位置。将以下代码添加至HelloWorld::init的末尾、return之前的地方:
auto eventListener = EventListenerTouchOneByOne::create();
eventListener-&onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
this-&getEventDispatcher()-
&addEventListenerWithSceneGraphPriority(eventListener, _player);Cocos2d-x 3及以上版本使用EventDispatcher来处理各种各样的事件,如触摸、加速计和其他键盘事件。注意:整篇的讨论中,“touch”指的是触屏或者点击。Cocos2d-x对于这两种事件类型采取相同的方法。为了从EventDispatcher中获取事件,你需要注册一个EventListener。有两种触摸事件的监听器:
EventListenerTouchOneByOne:此类型对每个触摸事件调用一次回调方法。
EventListenerTouchAllAtOnce:此类型对所有的触摸事件调用一次回调方法。每个事件监听器支持4个回调,但你只需要为自己关心的事件绑定方法。
onTouchBegan:手指第一次碰到屏幕时被调用。如果你使用的是EventListenerTouchOneByOne,你必须返回true才能获取另外3个触摸事件。
onTouchMoved:手指接触屏幕并移动(保持接触)时被调用。
onTouchEnded:手指离开屏幕时被调用。
onTouchCancelled:在特定的结束事件处理的环境中被调用,如你正在触屏的时候,一个电话打了进来打断了这个app进程。在本游戏中,你只用关心触摸发生的时间就好了。声明你的回调函数来在HelloWorldScene.h中获取触摸的通知,像这样:
bool onTouchBegan(Touch touch, Event unused_event);
然后,在HelloWorldScene.cpp中执行你的回调函数:
bool HelloWorld::onTouchBegan(Touch *touch, Event *unused_event) {
- Just an example for how to get the
_player object
//auto node = unused_event-&getCurrentTarget();
Vec2 touchLocation = touch-&getLocation();
Vec2 offset = touchLocation - _player-&getPosition();
if (offset.x & 0) {
auto projectile = Sprite::create("projectile.png");
projectile-&setPosition(_player-&getPosition());
this-&addChild(projectile);
offset.normalize();
auto shootAmount = offset * 1000;
auto realDest = shootAmount + projectile-&getPosition();
auto actionMove = MoveTo::create(2.0f, realDest);
auto actionRemove = RemoveSelf::create();
projectile-&runAction(Sequence::create(actionMove,actionRemove,
nullptr));
上面的这个方法比较复杂,让我们来一步一步回顾一下。
第一行被注释掉了,但它说明了作为第二个参数传递给addEventListenerWithSceneGraphPriority(eventListener, _player)的_player对象被访问的方式。
此处获取了场景坐标系中触摸的坐标,然后计算了这个点相对于玩家当前位置的偏移量。这是Cocos2d-x中向量数学的一个例子。
如果offset的x值是负值,这表明玩家正试图朝后射击。在本游戏中这是不允许的(真正的忍者不会往后看!),所以只需要返回就好了,不用发射飞镖。
在玩家所在的位置创建一个飞镖,将其添加到场景中。
之后,调用normalize()来将偏移量转化为单位向量,即长度为1的向量。将其乘以1000,你就获得了一个指向用户触屏方向的长度为1000的向量。为什么是1000呢?因为长度应当足以超过当前分辨率下屏幕的边界。:]
将此向量添加到飞镖的位置上去,这样你就有了一个目标位置。
最后,创建一个动作,将飞镖在2秒内移动到目标位置,然后将它从场景中移除。编译并运行程序;点击屏幕,让你的忍者朝着敌人们发射吧!
Paste_Image.png
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
被以下专题收入,发现更多相似内容:
我们从来不关心Warning,只关心Error;
· 48人关注
无论你是新手,还是老司机。都可以为新生代血液尽一份绵薄之力!
· 13人关注
cocos2d-x 游戏开发相关技术,欢迎投稿
· 4人关注
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
选择支付方式:酷勤网 C 程序员的那点事!
当前位置: >
浏览次数:次
如下部分主要关于如何将炮台瞄准射击方向。这是很多游戏的必要条件&&包括一类我最喜欢的游戏题材,塔防游戏。(本系列第1部分详见)
所以下文主要谈论这一话题及在简单游戏中添加旋转炮台。
若你有遵照上一指南的操作,那么现在你就可以轻松接下去。
接着,下载新玩家精灵和抛射体精灵图像,将它们添加至项目中,将之前的Player.jpg和Projectile.jpg从项目中删除。然后将生成精灵的代码行修改成如下内容:
// In the init method
CCSprite *player = [CCSprite spriteWithFile:@&Player2.jpg&];
// In the ccTouchesEnded method
CCSprite *projectile = [CCSprite spriteWithFile:@&Projectile2.jpg&];
注意这次,我们无需具体设定精灵的宽度和高度,而是让Cocos2D替我们完成这些操作。
编译和运行你的项目,若运行顺利,你会看到炮塔发射子弹。但画面看起依然有些不妥,因为炮塔并没有旋转至射击方向,所以下面我们将就此进行修复。
Screenshot(from raywenderlich)
旋转至射击方向
在旋转炮塔前,我们首先需要存储玩家精灵的的引用,这样我们稍后才能够进行旋转。打开HelloWorldScene.h,修改class,将如下变量纳入在内:
CCSprite *_
然后在init方法中修改代码,将玩家对象添加至图层中:
_player = [[CCSprite spriteWithFile:@&Player2.jpg&] retain];
_player.position = ccp(_player.contentSize.width/2, winSize.height/2);
[self addChild:_player];
最后在dealloc中添加清除代码:
[_player release];
现在我们已获得一个玩家对象的引用,接着将其进行旋转!要进行旋转,我们首先需要确定旋转角度。
关于确定角度,不妨试着回想高中的三角法。是否还记得助记符SOH CAH TOA?这令我们牢记,角度的正切值=对边/邻边。下图进一步说明:
Shooting Angle Math(from raywenderlich)
就如上图所示,我们想要旋转的角度=Arc(Y坐标/X坐标)。
但有两点我们需要牢记。首先,计算Arc(Y坐标/X坐标)时,所得结果是弧度,而Cocos2D处理的是角度。幸运的是,Cocos2D提供便捷的转换宏指令。
其次,虽然我们通常将上述画面的角度视作正角(约20&),但在Cocos2D旋转中,正角将呈顺时针模式,如下图所示:
Shooting Angle Cocos(from raywenderlich)
所要要瞄准正确方向,我们需要将结果乘以-1。所以如果我们将上述图像的角度乘以-1,我们就会得到-20&,这表示逆时针旋转20&。
现在就将此放入代码中。将下述代码添加至ccTouchesEnded中,就在你调用抛射体的runAction前。
// Determine angle to face
float angleRadians = atanf((float)offRealY / (float)offRealX);
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
float cocosAngle = -1 * angleD
_player.rotation = cocosA
编译和运行项目,炮台如今应该转向射击方向。
Screenshot(from raywenderlich)
旋转然后进行射击
目前一切进展顺利,但画面稍微有些奇怪,因为炮塔直接瞄准特定方向射击,而不是呈现动态流畅模式。这个问题可以解决,但需要进行稍微的代码重构。
首先,打开HelloWorldScene.h,将如下变量添加至class中:
CCSprite *_nextP
然后修改你的ccTouchesEnded,添加名为ccTouchesEnded的新方法,这样它就呈现如下样式:
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if (_nextProjectile != nil)
// Choose one of the touches to work with
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
// Set up initial location of projectile
CGSize winSize = [[CCDirector sharedDirector] winSize];
_nextProjectile = [[CCSprite spriteWithFile:@&Projectile2.jpg&] retain];
_nextProjectile.position = ccp(20, winSize.height/2);
// Determine offset of location to projectile
int offX = location.x & _nextProjectile.position.x;
int offY = location.y & _nextProjectile.position.y;
// Bail out if we are shooting down or backwards
if (offX &= 0)
// Play a sound!
[[SimpleAudioEngine sharedEngine] playEffect:@&pew-pew-lei.caf&];
// Determine where we wish to shoot the projectile to
int realX = winSize.width + (_nextProjectile.contentSize.width/2);
float ratio = (float) offY / (float) offX;
int realY = (realX * ratio) + _nextProjectile.position.y;
CGPoint realDest = ccp(realX, realY);
// Determine the length of how far we&re shooting
int offRealX = realX & _nextProjectile.position.x;
int offRealY = realY & _nextProjectile.position.y;
float length = sqrtf((offRealX*offRealX)+(offRealY*offRealY));
float velocity = 480/1; // 480pixels/1sec
float realMoveDuration = length/
// Determine angle to face
float angleRadians = atanf((float)offRealY / (float)offRealX);
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
float cocosAngle = -1 * angleD
float rotateSpeed = 0.5 / M_PI; // Would take 0.5 seconds to rotate 0.5 radians, or half a circle
float rotateDuration = fabs(angleRadians * rotateSpeed);
[_player runAction:[CCSequence actions:
[CCRotateTo actionWithDuration:rotateDuration angle:cocosAngle],
[CCCallFunc actionWithTarget:self selector:@selector(finishShoot)],
// Move projectile to actual endpoint
[_nextProjectile runAction:[CCSequence actions:
[CCMoveTo actionWithDuration:realMoveDuration position:realDest],
[CCCallFuncN actionWithTarget:self selector:@selector(spriteMoveFinished:)],
// Add to projectiles array
_nextProjectile.tag = 2;
- (void)finishShoot {
// Ok to add now & we&ve finished rotation!
[self addChild:_nextProjectile];
[_projectiles addObject:_nextProjectile];
// Release
[_nextProjectile release];
_nextProjectile =
代码看起来很多,但我们做出的调整不多(游戏邦注:大多是细微的代码重构)。下列是我们所做出的调整:
* 若nextProjectile存在数值,我们会在函数开始处输出内容(通过bail()函数),这意味着我们处在射击过程中。
* 在应用本地对象前,给添加至情境中的抛射体命名。在此版本中,我们在变量nextProjectile中创建对象,但随后才进行添加。
* 我们定义预期的炮塔旋转速度,半秒旋转半圈。记住一圈有两个PI弧度。
* 所以为计算出旋转需耗费多久时间,我们将移动弧度乘以速度。
* 随后我们就开始系列操作,将炮台旋转至正确角度,然后调用函数,将抛射体添加至情境中。
所以不妨大胆进行尝试!编译和运行项目,炮塔现在应该旋转得更流畅。
现在我们拥有旋转的炮塔、射击的怪兽及优质的音效。
但我们的炮塔过于简单,怪兽只进行一次射击,关卡只有一个。
下面我们将对项目进行扩展,这样我们就能够制作出难度程度不同的各类怪兽,在游戏中植入多层次的关卡。
更棘手的怪兽
为融入更多趣味性,我们将制作两种类型的怪兽:软弱但快速的怪兽,强壮但缓慢的怪兽。
现在就来设置怪兽class。设置怪兽class的方式很多,我们将采用最简单的方式,就是将怪兽class设置成CCSprite子类。我们将创建两个怪兽子类:一个针对软弱但快速的怪兽,一个针对强壮但缓慢的怪兽。
切换至File\New File,选择Cocoa Touch Class\Objective-C类,勾选NSObject子类,然后点击Next。将文件命作Monster.m,选中&Also create Monster.h&。
然后将Monster.h替换成如下内容:
#import &cocos2d.h&
@interface Monster : CCSprite {
int _curHp;
int _minMoveD
int _maxMoveD
@property (nonatomic, assign)
@property (nonatomic, assign) int minMoveD
@property (nonatomic, assign) int maxMoveD
@interface WeakAndFastMonster : Monster {
@interface StrongAndSlowMonster : Monster {
这里相当明了:我们从CCSprite导出怪兽,添加若干变量,追踪怪兽状态,然后针对两类怪兽导出两个怪兽子类。
然后打开Monster.m,添加执行(implementation)项:
#import &Monster.h&
@implementation Monster
@synthesize hp = _curHp;
@synthesize minMoveDuration = _minMoveD
@synthesize maxMoveDuration = _maxMoveD
@implementation WeakAndFastMonster
+ (id)monster {
WeakAndFastMonster *monster =
if ((monster = [[[super alloc] initWithFile:@&Target.png&] autorelease])) {
monster.hp = 1;
monster.minMoveDuration = 3;
monster.maxMoveDuration = 5;
@implementation StrongAndSlowMonster
+ (id)monster {
StrongAndSlowMonster *monster =
if ((monster = [[[super alloc] initWithFile:@&Target2.png&] autorelease])) {
monster.hp = 3;
monster.minMoveDuration = 6;
monster.maxMoveDuration = 12;
这里真正的代码是,我们用于返回各类实体的静态方式,设置默认HP及移动持续时间。
现在将我们的新怪兽类植入剩余的代码中。首先将import(输入)添加至HelloWorldScene.m顶部的新文件中:
#import &Monster.h&
然后通过修改addTarget方法,构建新类的实体,而不是直接创建精灵。将spriteWithFile代码行替换成如下内容:
//CCSprite *target = [CCSprite spriteWithFile:@&Target.png& rect:CGRectMake(0, 0, 27, 40)];
Monster *target =
if ((arc4random() % 2) == 0) {
target = [WeakAndFastMonster monster];
target = [StrongAndSlowMonster monster];
这里各类型的怪兽有50%的繁衍几率。此外,由于我们已将怪兽速度移至类中,因此将最高/最低持续时间代码修改成如下样式:
int minDuration = target.minMoveD //2.0;
int maxDuration = target.maxMoveD //4.0;
最后是对updateMethod的些许调整。首先在说明targetsToDelete前添加一个布尔值(boolean)。
BOOL monsterHit = FALSE;
然后在CGRectIntersectsRect测试中添加如下代码(游戏邦注:而不是直接在targetsToDelete中添加对象):
//[targetsToDelete addObject:target];
monsterHit = TRUE;
Monster *monster = (Monster *)
monster.hp&;
if (monster.hp &= 0) {
[targetsToDelete addObject:target];
所以根本来说,我们不会直接杀死怪兽,我们会扣除一个HP值,只在数值处在0或0以下时消灭它。此外,注意若抛物体击中怪兽,我们就会摆脱循环机制,这意味着抛物体一次只能够击中一个怪兽。
最后,按照如下方式修改projectilesToDelete测试:
if (monsterHit) {
[projectilesToDelete addObject:projectile];
[[SimpleAudioEngine sharedEngine] playEffect:@&explosion.caf&];
编译和运行代码,若一切进展顺利,你会看到两类怪兽从屏幕中穿过&&这令炮塔的存在更具挑战性。
Screenshot(from raywenderlich)
为植入多重关卡,我们首先要进行代码重构。代码重构非常简单,但其中包括丰富内容,文章就不加以详述。
相反,我将从更高层面概述所完成的操作,详细介绍样本项目。
抽象提取一个Level类。目前,主要是关于&关卡&的HelloWorldScene硬编码信息,例如,生成哪个怪兽,生成频率是多少等。所以第一步就是,抽取若干这类信息,将其植入Level类中,这样我们就能够在HelloWorldScene中重复使用同个逻辑,创造多重关卡。
重复利用情境。目前,每次切换情境时,我们都会创造新的情境类实体。这里的一个弊端是,若没有小心管理,你就会在于init方法中加载资源时出现延误。
由于我们的游戏相当简单,因此我们需要进行的操作是,创建各情境的实体,调用reset()方法,清除之前的状态(游戏邦注:如来自上个关卡的怪兽或抛物体)。
将应用授权当作转换台。目前,我们没有什么总体状态,例如处于哪个关卡或关卡的具体设置是什么,各情境只是就具体应切换至哪个情境进行硬编码。
我们将就此进行修改,这样App Delegate商店就能够指示总体状态,例如关卡信息,因为这是个方便所有情境访问的中心地带。我们还在App Delegate植入特定方法,以切换情境,将逻辑元素聚集起来,降低内部情境的依赖性。
所以这些是代码重构的重点。记住这只是其中一种设置方式。
在此,我们已创建众多游戏要素&&旋转的炮塔,众多不同特性的敌人,多重关卡,胜败情境,当然还有优质音效!
游戏邦注:原文发布于2010年3月,文章叙述以当时为背景。
& 相关主题:
本文来源:}

我要回帖

更多关于 cocos2d x做什么 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信