如何使用Sprite Kit制作像切怎么用绳子制作鞭子这样的游戏

阅读:1602次
原文地址:/70837/how-to-port-your-sprite-kit-game-from-ios-to-os-x
泰然翻译组:阳光新鲜。校对:glory。
你可能想过将自己的Sprite Kit游戏移植到Mac OS X平台?事实上,这比你想像的还简单。苹果开发Sprite Kit的目的是让ios和Mac OS X开发尽可能的一样,甚至你可以使用相同的工程环境同时完成两个平台的开发。这篇引导将告诉你怎样获取一个ios Sprite Kit项目--然后将他修改成Mac OS X版本。你将学习到如何在同一个XCode工程中维护两个版本并且学习如何在不拷贝一大堆代码的情况下保证两个版本同步。如果你选择完成这个教程,那么你最好有一定的Mac OS X基础。尽管如此,Sprite Kit的一个优美的特性就是你不需要有比较丰富的经验就可以做出一个漂亮的App。如果想学习更多的关于Mac开发的知识,请查看这里让我们开始吧在下载我们教程需要的原始工程,并在你的iPhone上调试运行。这个实例工程和原始的有一些不同,这是为了将ios和Mac OS X版的游戏区分开来。水平仪支持项目使用了水平仪,这样可以让玩家可以通过倾斜设备来上下移动精灵,像这样:更具毁灭性的力量忍者星正在遭受魔法忍者力量史诗般的毁灭性攻击!好吧,也许不是史诗般的,但是这个版本使用了非常不错的粒子效果以给忍者一些视觉冲击。一些技术上的改进Vicki Wnderlich 发挥自己的才能给游戏添加了新的背景以使游戏看起来更具美感。当然,状态栏是隐藏的,并且游戏支持iPad的分辨率。使用项目和目标开发一个项目文件里包含你的工作用到的所有文件,其中 target 决定了你的工程该如何编译。一个项目可以包含多个目标。这种方式可以让你用多种方式编译你的项目,选择目标和哪些特定的文件关联,和一些特殊的目标设置。这些也许能给你一些关于将这个项目用Mac OS X编译的启示。让我们看一下项目的目标。打开 SpriteKitSimpleGame 项目,在界面的左上角,选择你的项目打开项目设置。然后在项目窗口中选择 SpriteKitSimpleGame。好,现在这里有两个目标,一个是ios另一个是ios单元测试,如下:二选一,在项目和目标的列表都展开后你可以选择 SpriteKitSimpleGame :当你构建应用时,你的target必须支持当前设备。查看当前设备是否被目标支持,点击左上角停止按钮右边的 SpriteKitSimpleGame 下拉按钮,显示如下:这里也是你要创建Mac OS X目标的地方。创建一个MacOSX目标确保你的Xcode窗口保持激活状态,按下图的方式选择 File/New/Target :Xcode提示你为目标选择一个模板。选择 OS X\Application\SpriteKit Game 模板然后点下一步,如下所示:最后在 product name 中输入 SpriteKitSimpleGameMac 然后点击完成,像这样:注意:如果你打算将应用上传到苹果商店,你的 bundle 和 identifier 必须在
分别注册。Profiles和provisioning文件分别用于ios和Mac OS X开发中。尝试在Mac OS X上运行你的app,在列表中选择 SpriteKitSimpleGameMac,然后选择 My Mac 64-bit,如下:你认为当你使用新的目标运行你的项目时会发生什么?
A - 游戏完美运行 - 教程到此结束!
B - 编译中发生数个错误。
C - 游戏可以编译,但运行时跳出。
D - 游戏可以运行,但运行结果不是你预期的。
如果你猜D那么你猜对了,就像一个新工程运行的很好但是使用的是标准模板。不用着急,这个工程马上就回变为令人惊讶的忍者游戏,但首先你需要清空工程已让我们能更方便的开始工作。将你的文件整理成多个目标现在,你有了一个Mac OS X目标,你将对他进行修改已使你的app能运行在osx下。随着时间的推移,跟踪这些文件将变得越来越困难,所以最好先设置系统以更好的组织所有文件。最小化你所有的组然后新建一个叫 SharedResources 的组,如下所示:这个组将包含可以让Mac OS X和ios目标公用的资源。好了,现在创建一个叫 Testing 的组,然后将单元测试项目移动到里面,像这样:将用于单元测试的项目移入特定的文件夹可以避免看起来杂乱。现在你在项目里为文件组织了一个新的结构,你现在要做的是移动文件到指定的位置。展开 SharedResources 和 SpriteKitSimpleGame 文件夹。从 SpriteKitSimpleGame 拖动 Particles 和 Sounds组到 SharedResources.下一步,将 sprites.atlas folder, MyScene.h, MyScene.m, GameOverScene.h and GameOverScene.m 文件也拖动过来。你的文件夹结构看上去应该如下所示:删除 Spaceship.png 文件 - 你将不再需要他了。这只是你在创建 sprite Kit 模板时自动生成的样板文件。所有共享的资源都已经放到 SharedResources 组了。所有留在 SpriteKitSimpleGame 的文件都与 ios 游戏的启动与管理有关。展开 SpriteKitSimpleGameMac 组。在开始下一步之前,你需要删除这个文件夹的实例文件。从 SpriteKitSimpleGameMac 中删除 MyScene.h, MyScene.m and Spaceship.png 文件,选择移动到垃圾箱。然后你的文件列表应该像这样:注意:你的Mac目标的组中不能含有ViewController类;取代它的应该是AppDelegate文件。 UIViewController 类是 UIKit 的一部分,他在Mac os x上是不起作用的。取代他的是AppDelegate,他将创建一个NSWindow实例以呈现Sprite Kit场景。最后检查一下,你的完整的展开列表应该和下面的一样:你已经删除了所有不必要的项目,并且重新组织了一下。现在,是时候修改目标编译时所指向的文件了。添加目标成员展开 FrameWorks 组选择 UIKit.framework,像这样:展开右边的 Utilities Panel 选择 File Inspector,像这样:在File Inspector的下半部分你会看到Target Membership区域。这里显示的是你的目标将要显示的文件。UIKit 只是用在ios平台上,所以将Mac OS X的目标去掉,如下所示:Cocoa Framework 只能在mac os x上使用,所以确保他在mac目标上被选中,在ios目标上被取消:Sprite Kit Framework 在ios和mac上都可以使用,所以像这样设置:每个文件都有他自己的Membership除了atlases纹理文件以外。Atlas文件是你唯一需要自己设置Membership的文件,其他的包括纹理都是自动设置的。尽管如此,类在这方面有一些特别。你不能给.h文件设置Membership,但你必须给.m文件设置Membership。带着你的新发现加深对Target Membership的理解,完成你的SharedResources组,确保SpriteKitSimpleGame 和 SpriteKitSimpleGameMac所有的文件都设置完成。总体上来讲,你需要8次设置。下一步,完成SpriteKitSimpleGame组的文件,并确保SpriteKitSimpleGame的文件和两个目标都有关联 - 他们应该已经被设置好了,但是这里最好再设置一下。最后,完成SpriteKitSimpleGameMac组,确保SpriteKitSimpleGameMac组的文件全都标记过。同样,你什么改变都不需要左,但是检查一下也无妨。现在你的工程已经正确设置了ios和mac的目标,你接下来终于可以做你最擅长的事情 - 写程序!构建与运行游戏基于之前的工作,你的项目应该构建并且在ios上正确运行。之前做的修改应该不对实际的游戏效果产生影响。尽管去次,如果你编译OS的目标时,你将看到一连串的错误。这是因为你为对ios与osx代码之间差异给予说明。构建和运行你的项目使用SpriteKitSimpleGameMac目标;你将会看到什么?你将会遇到Module ‘CoreMotion’ not found的错误。Mac OS X没有CoreMotion和与他等价的类;你将围绕这个错误并且使用键盘控制主角移动。尽管如此,你的初级目标就是使项目能够构建,具体的实现细节放在后面。但是我们如何修复它呢?你不能直视移除CoreMotion,否则ios版本就不能用了。你不能使用if语句解决,因为编译器会检查每一行代码并对他不认识的东西抛出错误。打开MyScene.m然后替换:@import CoreM
替换成下面的代码:#if TARGET_OS_IPHONE
@import CoreM
不同于if语句的规则,#if是在预处理中执行。TARGET_OS_IPHONE如果是ios平台则返回true。注意:如果你计划使用#if检查当前的平台是否为Mac,如果是就执行一系列方法,那么你应该使用TARGET_OS_IPHONE。
TARGET_OS_MAC看起来也可以 - 但问题是他在ios下也返回true。
这看起来很糟糕,但苹果在他们的实例中使用!TARGET_OS_IPHONE来表示包含多平台的目标,所以这是一个小故障,看起来他们并不想修改。现在你需要找到和CoreMotion有关的代码,并给他加上#if。在MyScene.m中的实例变量中找下列代码:CMMotionManager *_motionM
然后将他替换成:#if TARGET_OS_IPHONE
CMMotionManager *_motionM
滚动到int方法,寻找下列代码:_motionManager = [[CMMotionManager alloc] init];
_motionManager.accelerometerUpdateInterval = 0.05;
[_motionManager startAccelerometerUpdates];
替换成如下代码:#if TARGET_OS_IPHONE
_motionManager = [[CMMotionManager alloc] init];
_motionManager.accelerometerUpdateInterval = 0.05;
[_motionManager startAccelerometerUpdates];
现在,找到如下代码[self updatePlayerWithTimeSinceLastUpdate:timeSinceLast];
替换成如下代码:#if TARGET_OS_IPHONE
[self updatePlayerWithTimeSinceLastUpdate:timeSinceLast];
最后,当然这并不是最不重要的。找到updatePlayerWithTimeSinceLastUpdate方法:用下面的代码包裹整个方法:#if TARGET_OS_IPHONE
- (void)updatePlayerWithTimeSinceLastUpdate:> (CFTimeInterval)timeSinceLast
如果你使用ios目标编译,所有的#if将返回TRUE,所以app会像以前一样编译。相反的,如果使用mac os x目标进行编译,所有的#if将返回FALSE,所有的程序块将不会被编译。仔细查看touchesEnded:withEvents方法在MyScene.m。Mac版本不支持触屏,所以这个方法已经失效了。Mac版将使用鼠标作为屏幕触控的完美替代品。为了避免给代码增加一个新分支,你将创建一个继承自SKScene类以帮助用来控制屏幕触控和鼠标点击!添加事件操作选择你的SharedResources组。在菜单栏上选择File \ New \ File…,如下所示:选择Objective-C Class不管你是ios还是os策略,点下一步。命名为SKMScene继承于SKScene。将文件直接置于工程文件夹下,确保ios和mac目标都被选中。打开SKMScene.h替换代码:@import SpriteK
@interface SKMScene : SKScene
//Screen Interactions
-(void)screenInteractionStartedAtLocation:(CGPoint)
-(void)screenInteractionEndedAtLocation:(CGPoint)
你将用SKMScene重写上面的两个方法。将下面的代码直接加在SKMScene.m文件的@implementation SKMScene:行下:#if TARGET_OS_IPHONE
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
[self screenInteractionStartedAtLocation:positionInScene];
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
[self screenInteractionEndedAtLocation:positionInScene];
- (void)touchesCancelled:(NSSet *)touches
withEvent:(UIEvent *)event
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
[self screenInteractionEndedAtLocation:positionInScene];
-(void)mouseDown:(NSEvent *)theEvent {
CGPoint positionInScene = [theEvent locationInNode:self];
[self screenInteractionStartedAtLocation:positionInScene];
- (void)mouseUp:(NSEvent *)theEvent
CGPoint positionInScene = [theEvent locationInNode:self];
[self screenInteractionEndedAtLocation:positionInScene];
- (void)mouseExited:(NSEvent *)theEvent
CGPoint positionInScene = [theEvent locationInNode:self];
[self screenInteractionEndedAtLocation:positionInScene];
-(void)screenInteractionStartedAtLocation:(CGPoint)location {
/* Overridden by Subclass */
-(void)screenInteractionEndedAtLocation:(CGPoint)location {
/* Overridden by Subclass */
这确实是一串很长的代码,但如果你从头到尾读下来,还是能找到其中的道理的。触摸屏幕和返回的方法在TARGET_OS_IPHONE程序块里。然后你创建一个包含位置信息的CGPoint触摸点并且调用screenInteraction相关的方法。点击或释放鼠标将会调用#else处的方法。和上面一样,你创建一个包含点击信息的CGPoint并且调用和screenInteraction有关的方法。使用这个子类的好处是触摸和点击都调用screenInteraction方法。screenInteraction方法没有代码,所以你需要在你的子类中重写。打开MyScene.h并且在#import下添加如下类的声明:#import "SKMScene.h"
然后修改父类为如下内容:@interface MyScene : SKMScene
这确保你的游戏场景继承于SKMScene子类。你可以替代你子类中的触摸事件。在MyScene.m寻找如下行:-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
用下面的代码替换他:-(void)screenInteractionEndedAtLocation:(CGPoint)location {
接下了,删除以下几行你已经不需要的方法:UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
使用Mac目标构建和运行你的项目;他应该可以编译通过,并且没有错误:恭喜你 - 你已经成功的在Mac上运行了你的Sprite Kit game!你得注意这里有一些bug:
在一些苹果设备上,首次点击游戏会有短暂的卡顿。
在一些苹果上粒子效果可能显示不正常。
有些屏幕的尺寸可能有问题。
背景音乐没声音。
接下来我将带您改正所有的这些bug - 你在这个过程中将学到一些在做跨平台应用时经常遇到的问题。纠正预加载错误这个bug不会在所有的系统上出现,但一旦出现就会有性能问题。“First-time-through”通常源于资源加载。Texture atlases是经常被使用的资源,但是我们的应用不包换动画和大型混合图片,所以问题出在别的地方。音效更有可能出问题,当用户点击屏幕时,音效还没有加载。修复这个问题,添加如下变量在 MyScene.m:SKAction *_playPewP
下一步,在initWithSize的if语句中添加如下代码:_playPewPew = [SKAction playSoundFileNamed:@"pew-pew-lei.caf" waitForCompletion:NO];
这个修改后你的应用在场景初始化时预加载声音。在screenInteractionEndedAtLocation寻找下列代码:[self runAction:[SKAction playSoundFileNamed:@"pew-pew-lei.caf" waitForCompletion:NO]];
替换成:[self runAction:_playPewPew];
运行应用;点击鼠标确保延迟消失了。如果你的系统没有表现出这个问题,那么你也应该修改一下防止在其他系统上运行时发生。纠正SKS错误。在写这篇文档时我发现在xcode5上运行,粒子效果会出现问题。你需要在Sks文件中重写引用的纹理文件。技术上,你的Sks文件没有发生任何错误 - 你不会在所有的系统中体验到这种错误 - 但你需要尽量避免他出现。在MyScene.m的projectile:dideCollideWithMonster中寻找下面的代码:SKEmitterNode *emitter = [NSKeyedUnarchiver unarchiveObjectWithFile:[[NSBundle mainBundle] pathForResource:@"SmallExplosion" ofType:@"sks"]];
将下面的代码直接添加到你找的的代码下面:emitter.particleTexture = [SKTexture textureWithImageNamed:@"spark"];
你之前所做的事情是为了告诉XCode哪里寻找粒子纹理。创建你的应用;现在你可以欣赏你史诗般无障碍的粒子效果。修复图片大小错误打开SpriteKitSimpleGameMac组然后选择AppDelegate.m。查看你在applicationDidFinishLaunching中设置的尺寸。1024 * 768 - 这是非视网膜屏的ipad分辨率。现在查看一下sprites.atlas的内容。不出所料,所有的ipad版本图片都有~ipad后缀,这样你的应用在ipad上运行时就知道该使用哪种图片。不幸的事,这里没有~mac后缀;取代他的是,你需要创建一个为mac使用的texture atlas纹理。为了保证你的工程尽量的小,你应该使你的应用的分辨率尽可能的小。右键sprites.atla选择Show in Finder。复制sprites.atlas然后删除所有不带~ipad后缀的文件。下一步,删除~ipad后缀文件,但是留下@2x后缀文件。注意:必须留下@2x文件以支持配备视网膜屏的Macbook Pro。重命名文件夹为spritesMac.atlas然后拖动重命名的文件夹到你的工程。在Choose options for adding these files对话框中,确保只有SpriteKitSimpleGameMac目标被选中,如下所示:点击完成。现在文件夹已经被导入了,选择sprites.atlas,在Membership关闭mac的目标。这可以保证每一个texture atlas都和其他的区分开。让纹理文件夹的组织和原则一致,移动ios纹理到ios组mac纹理到mac组,如下:下一步,选择Project\Clean。这将删除所有的旧文件从你的构建目录(如果你忘了做这一步,sprites.atlas会仍然存在)。运行你的应用;你应该看到所有的纹理都按适当的尺寸载入,如下:现在你的应用已经支持iPhone, iPad 和 Mac OS X的系统分辨率 - 也兼容视网膜屏。修复音轨问题最后,你需要处理音轨的问题。查看SpriteKitSimpleGame组的ViewController.m文件。viewWillLayoutSubviews有一小部分代码是AVAudioPlayer的实例,设置他永远循环。NSError *
NSURL *backgroundMusicURL = [[NSBundle mainBundle] URLForResource:@"background-music-aac" withExtension:@"caf"];
self.backgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:backgroundMusicURL error:&error];
self.backgroundMusicPlayer.numberOfLoops = -1;
[self.backgroundMusicPlayer prepareToPlay];
[self.backgroundMusicPlayer play];
啊哈-你的mac工程里没有ViewController。因此,你需要在AppDelegate调用这些代码来替代。在SpriteKitSimpleGameMac组的AppDelegate.m文件中寻找如下代码:@implementation AppDelegate
替换:@import AVF
@implementation AppDelegate {
AVAudioPlayer *backgroundMusicP
下一步,在applicationDidFinishLaunching顶部添加如下代码:NSError *
NSURL * backgroundMusicURL = [[NSBundle mainBundle] URLForResource:@"background-music-aac" withExtension:@"caf"];
backgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:backgroundMusicURL error:&error];
backgroundMusicPlayer.numberOfLoops = -1;
[backgroundMusicPlayer prepareToPlay];
[backgroundMusicPlayer play];
构建应用;音乐开始播放了!你已经解决了mac版本上所有的bug,但你还有一个游戏控制的问题没有解决。使用键盘ios版的忍者移动依靠的是倾斜设备。这种工作是依靠CoreMotion类处理的,游戏的主循环调用updatePlayerWithTimeSinceLastUpdate:以计算主角当前帧的位置。我们现在需要一个不同的方法来监听键盘事件。将下面代码添加到MyScene.m文件的updatePlayerWithTimeSinceLastUpdate:方法的#endif语句之前:#else
-(void)keyDown:(NSEvent *)theEvent {
这个方法用于响应键盘操作。注意有个keyUp方法响应键盘的抬起事件,事件是键盘从按下到抬起的时间。你不想处理响应所有的键盘事件;你可以在NSEvent中找到你需要处理的按键。在keyDown的花括号中添加如下代码:-(void)keyDown:(NSEvent *)theEvent {
NSString *keyPressed = [theEvent charactersIgnoringModifiers];
if ([keyPressed length] == 1) {
NSLog(@"Key: %c",[keyPressed characterAtIndex:0]);
这里你可以提取你按下的字母,没有任何修饰键。这意味着组合键如Command + S将被忽略.同样的,你只检查按下的一个字母,这样可以过滤掉你不想要的字符事件。你将吧按压事件输出到控制台。运行工程;你输入的按键将输出到debug区域,如下:你可以使用上下键来移动你的精灵,试着按一些键看控制台输出什么:恩,这看起来有点糟糕。方向键是功能键的一部分,所以他没有合适的字符可以代表。但这没关系:我这里有一个简单的方法可以检测功能键的按压。NSEvent可以帮助你很好的管理mac上鼠标和键盘的操作。这个引导教程只介绍了NSEvent的一部分;强烈推荐你仔细查看。现在,快速浏览一下NSEvent文档中关于按键时间的部分。按键和NSUpArrowFunctionKey与NSDownArrowFunctionKey有关。返回MyScene.m找到keyDown:添加代码。注释掉NSLog语句并且立即粘贴如下代码:unichar charPressed = [keyPressed characterAtIndex:0];
switch (charPressed) {
case NSUpArrowFunctionKey:
[_player runAction:[SKAction moveByX:0.0f y:50.0f duration:0.3]];
case NSDownArrowFunctionKey:
[_player runAction:[SKAction moveByX:0.0f y:-50.0f duration:0.3]];
在这里你将按Unicode的方式比较上下按键。然后使用SKAction上下移动角色。运行工程;按上下键你将看到角色上下移动如下图:你需要花更多的时间修改mac版游戏,但你需要确保你没有影响到ios版本部分的运行效果!运行你的ios目标并且充分的玩每一个部分确保你之前的更改没有影响到ios部分的功能。未来要做的事?你可以从在得到完整的工程。现在,你应该已经还好的理解了将ios工程转换成mac/ios工程所需的工作,你一定希望让创建的Sprite Kit游戏一开始就具有跨平台功能。我在上放了一个Sprite Kit跨平台的模板,这对你一定有用的。想学习更多的ios和osx游戏的知识(尤其是和场景尺寸,图片大小,横纵比,和UIKit对比Cocoa Touch的坐标系统相关的),看看我们即将出版的
,这里你可以找到更多详细的内容。如果你有一些注释或问题,在下面踊跃发言哦!
相关文章推荐用SpriteKit游戏引擎做一款十字消游戏
招聘信息:
从网上受益,再回馈网上,这就是我想做的。刚做iOS的时候,从里面的教程收获颇多。因此,想分享iOS下的游戏开发引擎SpriteKit,让看过这篇博文的读者学习之后能够亲自动手制作一些自己喜欢的游戏。也许下一个“Flappy Bird”就是出自你的手上。一、教程说明SpriteKit是苹果自己的原生游戏引擎,可以方便开发简单的2D小游戏。因此如果仅仅熟悉Object-C语言的开发者,又不想使用Cocos2dx的开发者来说,是一个福音。这篇教程会以项目出发,一步一步的完成一个十字消除的游戏,让大家迅速上手。二、先导知识做游戏为什么要使用游戏引擎?让我们从0开始思考一下,我们现在要做一款十字消除类型的游戏,我们想好了游戏的基本玩法,找美术做好了游戏的素材。我们开始编程,将想法一步一步实现。(1)将美术素材导入,程序需要将美术素材,按照指定方式来显示。(2)需要通过交互(触摸,手势,鼠标,键盘等),来控制游戏里面的元素,进行我们核心的游戏。以上就是一个游戏引擎要完成的基本工作。在很久以前,完成以上两步,需要程序员熟悉计算机图形显示和交互事件响应模型等底层的知识。现在游戏引擎帮你完成这些简单的事情。PS:游戏引擎的工作远远不止于以上两条基本的情况,还有一些物理引擎的工作,使得在游戏中的元素具有自然届的一些诸如重力,摩擦力,阻尼运动等特性。三、准备工作1.首先你要有个核心的玩法,这里选择一个简单的十字消除的玩法来做教学实验。基本游戏玩法如导图所示,不同颜色的方砖随机分布在一定区域。点击空白的格子,如果空白格子的上下左右四个方向存在两个或两个以上相同颜色的方砖,这些方砖就会消除。在限制时间内,消除的方砖越多,得分越高。2.你得搞到美术素材,由于这个游戏比较简单,因此可以上网随便找找。5个彩色方砖可以,5个可爱的小动物可以,QQ头像也凑合,实在不行,可以按照教程里面的方式,使用程序生成的彩色方砖(其实也蛮风格化的)。好了,万事具备,只欠编程了。我们打开我们的Xcode吧。什么?Xcode是什么?额(让我吐几口血)~请到iOS开发教程页面,那里比较适合你。(1)按“”(或菜单栏选File->New->Project)新建一个project工程,选择Single View App Application,输入你想要的名字即可,这里我们使用DemoGame。(2)导入SpriteKit库。选择DemoGame的target,按照如下步骤,添加SpriteKit Framework。四、编制有趣的方块十字消除游戏吧1.小试牛刀首先,点击Main.storyBoard,选择ViewController里面的view,在Identity检查器中,指定Custom Class 为SKView。然后在ViewController.m里面添加一下代码。编辑ViewController.m文件,输入如下代码。//&1
SKView&*skView&=&(SKView&*)self.
SKScene&*scene&=&[[SKScene&alloc]&initWithSize:CGSizeMake(self.view.frame.size.width,&self.view.frame.size.height)];
scene.backgroundColor&=&[UIColor&greenColor];
[skView&presentScene:scene];将StoryBoard里指定的SKView使用变量获得。实例化一个SKScene对象,并将该对象的背景颜色设置为绿色。SKView调用presentScene:方法,加载SKScene。按“Command+R”(Run)执行代码,你将看到这样的结果:所有的游戏素材都将在SKScene里面显示,整个素材是以树的形式来组织的,树根节点就是SKScene节点。树的叶子和分支节点是SKNode类或者其子类(实际上SKScene也是SKNode的子类),我们的工作就是将美术素材通过SKNode节点,在SKScene上挂载,最终显示在屏幕上。2.加入背景和彩色方格ok,现在我们依靠程序生成棋盘格式的背景,我们的目标是8*8的黑白相间的棋盘格背景(我去,目标不是星辰大海吗?)。做之前,需要注意SpriteKit的坐标系是以左下为原点(0,0),与iOS APP开发时的左上原点不同。由于现在iPhone手机的屏幕种类也比较多,因此需要在初始化的时候,动态的获取屏幕的宽度,进而得到方块背景的宽度。废话不多说,看代码吧!按“?N”(New->File)新建一个“Cocoa Touch Class”,并命名为myScene,继承自SKScene。切换到myScene.m里面,加入私有变量:@interface&GameScene&()
//&1&根据屏幕的长度,计算方块的长度
@property&(nonatomic)&CGFloat&SquareL
//&2&纪录游戏棋盘的原点
@property&(nonatomic)&CGPoint&backgroundO
//&3&纪录所有彩色方块的数据结构
@property&(nonatomic&,strong)&NSMutableArray&*colorFulS
//&4&顺序处理触摸操作的队列
@property&(nonatomic,strong)&dispatch_queue_t&dealQ
@end加入以下代码,重写initWithSize:方法。-&(id)initWithSize:(CGSize)size
&&&&self&=&[super&initWithSize:size];
&&&&if&(self)&{
&&&&&&&&self.backgroundColor&=&[UIColor&cyanColor];
&&&&&&&&//&1
&&&&&&&&[self&addBackground];
&&&&&&&&//&2
&&&&&&&&[self&addSquare];
&&&&&&&&//&3&触摸消除处理的顺序队列
&&&&&&&&self.dealQueue&=&dispatch_queue_create("com.tallmantech.colorful",&NULL);
&&&&&&&&//&4&存放彩色方块的数组
&&&&&&&&self.colorFulSquares&=&[[NSMutableArray&alloc]&init];
&&&&return&
}(1)addBackground加入黑白方块背景。在以上代码后面加上如下代码:-(void)addBackground
&&&&//&1&获取当前Scene的款度和高度
&&&&CGFloat&width&=&self.size.
&&&&CGFloat&height&=&self.size.
&&&&//&2&因为需要8*8的方格背景,获取单个方格的宽度
&&&&_SquareLength&=&width&/&8;
&&&&CGFloat&SqureLength&=&_SquareL
&&&&//&3&背景需要居中,因为坐标系原点在左下,所以高度设置在一半减去4个方格的长度
&&&&_backgroundOrigin&=&CGPointMake(0,&height/2&-&SqureLength*4);
&&&&//&4&挂载背景方格
&&&&SKSpriteNode&*
&&&&for&(&int&i&=&0;&i&<&8;&i++)&{
&&&&&&&&for&(int&j&=&0;&j&<&8;&j++)&{
&&&&&&&&&&&&//&4.1&初始化棋牌格的颜色和大小
&&&&&&&&&&&&if&(&(i%2&==&0&&&&j%2&==&0)&||&(i%2&==&1&&&&j%2&==&1))&{
&&&&&&&&&&&&&&&&node&=&[[SKSpriteNode&alloc]&initWithColor:[UIColor&lightGrayColor]&size:CGSizeMake(SqureLength,&SqureLength)];
&&&&&&&&&&&&}
&&&&&&&&&&&&else&{
&&&&&&&&&&&&&&&&node&=&[[SKSpriteNode&alloc]&initWithColor:[UIColor&whiteColor]&size:CGSizeMake(SqureLength,&SqureLength)];
&&&&&&&&&&&&}
&&&&&&&&&&&&//&4.2&设置棋盘格的位置
&&&&&&&&&&&&node.position&=&CGPointMake(_backgroundOrigin.x&+&SqureLength/2+&SqureLength*j,&_backgroundOrigin.y&+&SqureLength/2+&SqureLength*i);
&&&&&&&&&&&&node.name&=&@"backSquare";
&&&&&&&&&&&&[self&addChild:node];
}第4项那一大坨是虾米喝?就“挂载背景方格”就想敷衍读者?好吧,小武老老实实的开始给大家讲解。所有的美术元素都是以树形节点来管理的,我们的背景黑白块也是,使用SKSpriteNode结构,该结构是SpriteKit里面提供的基本结构,初始化能够传入图片等素材,可以执行各种动画效果,还有播放帧动画等功能。8*8一共有64块方块,也就是64个节点,我们用两个循环来控制初始化。主要负责两件事情,节点初始化(颜色和大小)和位置。节点初始化initWithColor:size:方法。位置设置node的position成员变量。这里要说明的是卯点(archor point)的概念,每个SKSpriteNode,都有默认的卯点位置在(0.5,0.5)的位置,即SKSpriteNode的几何中心。该点代表SKSpriteNode节点在其父节点坐标系里的坐标位置,即node的position成员变量。按“Command+R”运行一下,看看结果。这货现在是这个样子:加入黑白棋盘格(2)addSquare加入彩色方块。接下来,加入彩色的方砖,就是我们要消除的对象。在8*8的格子里面,充满80%的五颜六色的彩色方砖。好了,一大坨代码正在路上。。。-&(void)addSquare
&&&&//&1&设置彩色方砖的长度
&&&&CGFloat&colorSquareLength&=&_SquareLength&-&8;
&&&&int&index&=&5;
&&&&SKSpriteNode&*
&&&&for&(&int&i&=&0;&i&<&8;&i++)&{
&&&&&&&&for&(int&j&=&0;&j&<&8;&j++)&{
&&&&&&&&&&&&//&2&产生随机数对6求余,&结果会有0,1,2,3,4,5,保证有1/6的
&&&&&&&&&&&&//&空闲,如果结果5,就不添加彩色方砖。
&&&&&&&&&&&&index&=&arc4random()%6;
&&&&&&&&&&&&NSLog(@"%d",index);
&&&&&&&&&&&&if&(index&==&5)&{
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&}
&&&&&&&&&&&&//&3&根据0到4的结果,初始化不同颜色彩色方砖。
&&&&&&&&&&&&switch&(index)&{
&&&&&&&&&&&&&&&&case&0:
&&&&&&&&&&&&&&&&&&&&node&=&[[SKSpriteNode&alloc]&initWithColor:[UIColor&yellowColor]&size:CGSizeMake(colorSquareLength,&colorSquareLength)];
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&case&1:
&&&&&&&&&&&&&&&&&&&&node&=&[[SKSpriteNode&alloc]&initWithColor:[UIColor&magentaColor]&size:CGSizeMake(colorSquareLength,&colorSquareLength)];
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&case&2:
&&&&&&&&&&&&&&&&&&&&node&=&[[SKSpriteNode&alloc]&initWithColor:[UIColor&orangeColor]&size:CGSizeMake(colorSquareLength,&colorSquareLength)];
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&case&3:
&&&&&&&&&&&&&&&&&&&&node&=&[[SKSpriteNode&alloc]&initWithColor:[UIColor&purpleColor]&size:CGSizeMake(colorSquareLength,&colorSquareLength)];
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&case&4:
&&&&&&&&&&&&&&&&&&&&node&=&[[SKSpriteNode&alloc]&initWithColor:[UIColor&brownColor]&size:CGSizeMake(colorSquareLength,&colorSquareLength)];
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&default:
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&}
&&&&&&&&&&&&
&&&&&&&&&&&&//&4&指定节点的位置,并将彩色方砖的位置和颜色信息存入node的userData字段中去了。
&&&&&&&&&&&&CGFloat&positionX&=&_backgroundOrigin.x&+&_SquareLength/2+&_SquareLength*j;
&&&&&&&&&&&&CGFloat&positionY&=&_backgroundOrigin.y&+&_SquareLength/2+&_SquareLength*i;
&&&&&&&&&&&&node.position&=&CGPointMake(positionX,&positionY);
&&&&&&&&&&&&
&&&&&&&&&&&&NSMutableDictionary&*userData&=&[NSMutableDictionary&dictionaryWithObjectsAndKeys:@"colorSquare",@"nodeType",[NSValue&valueWithCGPoint:CGPointMake(positionX,&positionY)],@"position",[node&color],@"color",@"YES",@"exsit",nil];
&&&&&&&&&&&&//&&&&&&&&&&&&NSLog(@"userData:%@",userData);
&&&&&&&&&&&&node.userData&=&userD
&&&&&&&&&&&&//&5&设置节点的名字,并加入到scene场景。
&&&&&&&&&&&&node.name&=&@"colorSquare";
&&&&&&&&&&&&[self.colorFulSquares&addObject:node];
&&&&&&&&&&&&[self&addChild:node];
}按“Command+R”运行一下,加入彩色方砖后,这货现在是这个样子(每次随机会有不同的排列组合):好了,至此我们核心的游戏美术素材都添加完成了,大家可以看到,没有美工也还能做游戏,但是相当痛苦3.加入游戏核心玩法,十字消除彩色方砖。3.1 核心玩法处理OK,原先以为撰写教程是十分简单的事情,但是现在发现也需要耗费心力。我们终于进入了核心玩法的实现,十字消除彩色方砖。我们先来心里默念下,核心玩法,首先点击一个空白位置,我要找到上下左右四个方向是否有方砖。只要这些方砖里面存在颜色相等的方砖情况下,这些颜色相等的方砖将一起消失。OK,归纳起来就两步:(1)点击空白方格,找到上下左右四个方向的方砖。在工程中加入辅助方法,代码如下:-&(NSMutableArray&*)findFourDirectSquareOfSKNode:(SKNode&*)node
&&&&NSMutableArray&*tempArray&=&[[NSMutableArray&alloc]&init];
&&&&//&1&从node的userData字段寻找出位置信息
&&&&NSValue&*positionValue&=&(NSValue&*)[node.userData&objectForKey:@"position"];
&&&&CGPoint&position&=&[positionValue&CGPointValue];
&&&&CGFloat&positionX&=&position.x;
&&&&CGFloat&positionY&=&position.y;
&&&&//&2&获取游戏界面中,最小位置(左下)和最大位置(右上),作为边界
&&&&CGFloat&minX&=&_backgroundOrigin.x+_SquareLength/2;
&&&&CGFloat&minY&=&_backgroundOrigin.y+_SquareLength/2;
&&&&CGFloat&maxX&=&_backgroundOrigin.x+_SquareLength/2&+&_SquareLength*7;
&&&&CGFloat&maxY&=&_backgroundOrigin.y+_SquareLength/2&+&_SquareLength*7;
&&&&//&3&left&向左寻找彩色方块节点
&&&&for&(CGFloat&x&=&positionX&-&_SquareL&x&>=&minX;&x=x-_SquareLength)&{
&&&&&&&&SKNode&*node&=&[self&nodeAtPoint:CGPointMake(x,&positionY)];
&&&&&&&&if&([self&isExsitColorNode:node])&{
&&&&&&&&&&&&[tempArray&addObject:node];
&&&&&&&&&&&&
&&&&//&4&right&向右寻找
&&&&for&(CGFloat&x&=&positionX&+&_SquareL&x&=&minY;&y=y-_SquareLength)&{
&&&&&&&&SKNode&*node&=&[self&nodeAtPoint:CGPointMake(positionX&,&y)];
&&&&&&&&if&([self&isExsitColorNode:node])&{
&&&&&&&&&&&&[tempArray&addObject:node];
&&&&&&&&&&&&
&&&&//&6&up&向上寻找
&&&&for&(CGFloat&y&=&positionY&+&_SquareL&y&<=&maxY;&y=y+_SquareLength)&{
&&&&&&&&SKNode&*node&=&[self&nodeAtPoint:CGPointMake(positionX&,&y)];
&&&&&&&&if&([self&isExsitColorNode:node])&{
&&&&&&&&&&&&[tempArray&addObject:node];
&&&&&&&&&&&&
&&&&//&7&返回结果
&&&&return&tempA
}遍历所指节点的上下左右方向,找到这四个方向的彩色方砖,放入数组tempArray里面去,返回结果。(2)这些方砖里面是否有相同颜色的方砖,有的话就消除。通过上面获取的tempArray,我们需要判断是否存在颜色相同的彩色方砖,增加如下的辅助方法:-&(NSMutableDictionary&*)findSameSquareInArray:(NSMutableArray&*)tempArray
&&&&//&&&&NSLog(@"colorNodes:%@",tempArray);
&&&&NSMutableDictionary&*resultDic&=&[[NSMutableDictionary&alloc]&init];
&&&&for&(SKNode&*node&in&tempArray)
&&&&&&&&NSMutableArray&*valueA
&&&&&&&&UIColor&*color&=&[node.userData&objectForKey:@"color"];
&&&&&&&&if&(color&==&nil)&
&&&&&&&&&&&&return&
&&&&&&&&if&([resultDic&objectForKey:color]&==&nil)
&&&&&&&&&&&&valueArray&=&[[NSMutableArray&alloc]&init];
&&&&&&&&&&&&
&&&&&&&&else
&&&&&&&&&&&&valueArray&=&(NSMutableArray&*)[resultDic&objectForKey:color];
&&&&&&&&[valueArray&addObject:node];
&&&&&&&&[resultDic&setObject:valueArray&forKey:color];
&&&&return&resultD
}这里使用了dictionary,将color作为key,将相同颜色的node的数组作为了Value。如果,对应color的数组大于2的话,说明有两个以上相同颜色的node节点。这两步为该游戏的关键步骤,不清楚的可以反复多看看。3.2 触摸处理好了!我们这个时候来讲讲屏幕触碰的处理。在SKScene里面,给定了一个-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event方法来处理触碰响应。touches是一个set,我们需要从里面任取一个点,来作为触碰点,并找到位于该点的SKNode元素。代码如下:-(void)touchesBegan:(NSSet&*)touches&withEvent:(UIEvent&*)event
&&&&/*&Called&when&a&touch&begins&*/
&&&&//&1&从touches中取得UITouch,并得到坐标。
&&&&UITouch&*touch&=&[touches&anyObject];
&&&&CGPoint&location&=&[touch&locationInNode:self];
&&&&//&由于我们是按照坐标来判断位置的,有时候背景方砖和彩砖之间的缝隙可能被按下,形成错误的判断,这里我们做一个矫正,获取该位置所代表方块区域的中心位置。
&&&&CGPoint&nodePosition&=&[self&nodePosition:location];
&&&&//&2&通过location,获取点击的节点
&&&&SKNode&*node&=&[self&nodeAtPoint:nodePosition];
&&&&//&3&如果是背景方块,进入处理
&&&&if&([node.name&isEqual:@"backSquare"])
&&&&&&&&//&4&这里在一个队列里面,将点击操作排队,解决响应快速点击的问题
&&&&&&&&__weak&typeof(self)&weakSelf&=&
&&&&&&&&dispatch_async(self.dealQueue,&^{
&&&&&&&&&&&&//&5&处理寻找相同色彩的方块,并消除的函数。
&&&&&&&&&&&&[weakSelf&dealWithBackNode:node];
&&&&&&&&&&&&//&6&这里判断是否还存在可以消除的彩色方块,没有的话,说明当前局应该结束了,我们在这里刷新一下,生成新的游戏,继续不断的玩下去。
&&&&&&&&&&&&if&(![self&isExsitColorSquareToEliminate])
&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&[self&refreshGame];
&&&&&&&&&&&&&&&&NSLog(@"refresh&game");
&&&&&&&&&&&&}
&&&&&&&&&&&&
&&&&&&&&});
&&&&else&if&([node.name&isEqual:@"colorSquare"])
-&(void)dealWithBackNode:(SKNode&*)node
&&&&//&1&获取四周的彩色方块。
&&&&NSMutableArray&*tempA
&&&&tempArray&=&[self&findFourDirectSquareOfSKNode:node];
&&&&//&&&&NSLog(@"colorNodes:%@",tempArray);
&&&&//&2&统计相同颜色的方块。
&&&&NSMutableDictionary&*resultDic&=&[self&findSameSquareInArray:tempArray];
&&&&//&&&&NSLog(@"resultDic:%@",&resultDic);
&&&&//&3&遍历dictionary,如果相同颜色方块数大于1,说明是可以消除的方块,对它们进行消除。
&&&&[resultDic&enumerateKeysAndObjectsUsingBlock:^(id&key,&id&obj,&BOOL&*stop)&{
&&&&&&&&NSMutableArray&*array&=&(NSMutableArray&*)
&&&&&&&&if&([array&count]&>&1)&{
&&&&&&&&&&&&for&(SKNode&*node&in&array)&{
&&&&&&&&&&&&&&&&//&4&进行消除的时候,为消除后的节点置一个消除的标志,方便快速点击时,有的方块实际已经消除了,却还被寻找四个方向的函数纪录下来。
&&&&&&&&&&&&&&&&[node.userData&setObject:@"NO"&forKey:@"exsit"];
&&&&&&&&&&&&&&&&//&5&使用SKAction加入消失动画,并将自己从父节点上移除。
&&&&&&&&&&&&&&&&SKAction&*fadeOut&=&[SKAction&fadeOutWithDuration:0.5];
&&&&&&&&&&&&&&&&SKAction&*removeAction&=&[SKAction&removeFromParent];
&&&&&&&&&&&&&&&&SKAction&*all&=&[SKAction&sequence:@[fadeOut,&removeAction]];
&&&&&&&&&&&&&&&&[node&runAction:all];
&&&&&&&&&&&&}
}SKAction是SpriteKit提供的一个很方便的动画处理机制,使得一个节点产生很多很多的动画,动画可以一起执行,也可以按照一定顺序执行。具体的可以后面通过专门的文章来描述和学习。3.3 游戏结束判断和刷新游戏游戏结束的条件就是没有任何的彩色方砖可以被消除,通过遍历背景的黑白方砖,来判断每个位置是否有能够消除的彩色方砖,其逻辑本质上,和触摸消除处理相似。代码如下:-&(BOOL)isExsitColorSquareToEliminate
&&&&//&1&遍历所有方块位置
&&&&for&(int&i&=&0;&i&<&8;&i++)
&&&&&&&&for&(int&j&=&0;&j&&1)
&&&&&&&&&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&&&&&&&&&return&YES;
&&&&&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&}
&&&&return&NO;
}刷新游戏的逻辑,就是删除所有没有消除的彩色方块,随机重新生成彩色方块。-&(void)refreshGame
&&&&//&1&将所有彩色方块从父节点删除
&&&&for&(&SKNode&*node&in&self.colorFulSquares)
&&&&&&&&[node&removeFromParent];
&&&&//&2&从管理数组中删除所有彩色方块节点
&&&&[self.colorFulSquares&removeAllObjects];
&&&&//&3&随机加入新方块,生成新游戏&
&&&&[self&addSquare];
}五、开始游戏吧!整个工程的完整代码可以从这里。“Command+R”,开始进行有趣的游戏吧!六、何去何从好吧,我们完成了一个基本的彩色方块十字消除的游戏,但是它并不完整。还有很多动画效果,过场,分数统计等需要完善,预知详情如何,请看下一个教程,来完善我们的这个小游戏。
微信扫一扫
订阅每日移动开发及APP推广热点资讯公众号:CocoaChina
您还没有登录!请或
点击量4567点击量4012点击量3938点击量3237点击量3073点击量2896点击量2733点击量2585点击量2570
&2016 Chukong Technologies,Inc.
京公网安备89}

我要回帖

更多关于 maya如何制作绳子 的文章

更多推荐

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

点击添加站长微信