Sprite Kit — Scenes

来源:互联网 发布:守望先锋 队友数据 编辑:程序博客网 时间:2024/06/05 17:50

忙起来就顾不上了...这周进度落的有点多~第一篇还有一章,这周争取弄完吧~


However, right now all the action takes place in a single scene of the game: the default MyScene created for you by the Sprite Kit project template.


就目前而言,所有的动作都在一个场景下完成:又Sprite Kit项目模板默认创建的MyScene.


In Sprite Kit, you don’t have to place everything within the same scene. Instead, you can create multiple unique scenes, one for each “screen” of the app, much like how view controllers work in iOS development.


在Sprite Kit中,我们不需要把左右的东西都放在一个场景内,而是分置在不同的场景里,每个场景都单独占用一个屏幕,有点类似于iOS中的视图控制器.


In this short chapter, you’ll add two new scenes: one for when the player wins or loses the game, and another for the main menu. You’ll also learn a bit about using the cool transitions you saw in the ActionsCatalog demo from last chapter’s Challenge 1.


在这一章中,我们会添加两个场景:游戏结果场景和菜单场景.同时我们还会学习一些在上一章demo中非常帅气的过渡效果.


But first, you need to wrap up some gameplay logic so you can detect when the player should win or lose the game. Let’s get started!


第一步,我们要建立一些判断玩家胜利或者失败的游戏逻辑~


Win and lose conditions

胜负条件


Here’s how the player will win or lose Zombie Conga:


下面是游戏中的胜负条件:


Win Condition: If the player creates a conga line of 30 cats or more, the player wins!


胜利条件:如果玩家收集了超过30只猫,那就赢了~


Lose Condition: The player will start with five lives. If the player spends all of his or her lives, the player loses.


失败条件:玩家开始会有5条命,如果玩家把他们用完了,游戏就失败了~


Right now when the crazy cat ladies collide with the zombie, nothing bad happens – there’s only a sound. To make this game challenging, you’ll change this so that collisions with a cat lady result in the following effects:


现在的情况是当老太太碰到了僵尸的时候并没有什么坏事发生—只会播放一段声音.为了让游戏更有挑战性,我们对碰撞效果做一些修改:


The zombie loses a life.


僵尸会失去一条命.


2. The zombie loses two cats from his conga line.


老太太会从队伍里面抱走两只猫.


Let’s make it so. Inside MyScene.m, add a new private instance variable to keep track of the zombie’s lives, and another to keep track of whether the game is over:


一起实现以下.在MyScene.m里,添加两个成员变量,一个用来记录僵尸剩余的姓名,另一个来判断程序是否结束:


int _lives; BOOL _gameOver;

Inside initWithSize:, right after setting the background color, initialize _lives to 5 and _gameOver to NO:


在initWithSize:方法中,设置背景色的代码后边,初始化_lives为5,_gameOver为NO:


_lives = 5;_gameOver = NO;

Next, add this new helper method to make the zombie lose two cats from his conga line:


下一步,添加一个新的辅助方法来处理丢失两只猫的功能:


- (void)loseCats {        // 1    __block int loseCount = 0;    [self enumerateChildNodesWithName:@“train" usingBlock:^(SKNode *node, BOOL *stop) {        // 2        CGPoint randomSpot = node.position;        randomSpot.x += ScalarRandomRange(-100, 100);        randomSpot.y += ScalarRandomRange(-100, 100);        // 3        node.name = @""; [node runAction:[SKAction sequence:@[[SKAction group:@[[SKAction rotateByAngle:M_PI * 4 duration:1.0], [SKAction moveTo:randomSpot duration:1.0], [SKAction scaleTo:0 duration:1.0]]],[SKAction removeFromParent]]]];        // 4        loseCount++;        if (loseCount >= 2) {        *stop = YES;         }    }]; }

Here you set up a variable to keep track of how many cats have been removed from the conga line so far, then you enumerate through the conga line.


这里我们声明了一个变量来追踪有多少只猫在队伍中移除了,然后遍历康茄舞的队伍.


2. You find a random offset from the cat’s current position.


基于当前遍历到的猫所在的位置计算一个随机的偏移量


3. You run a little animation to make the cat move toward the random spot, spinning around and scaling to 0 along the way. Finally, the animation removes the cat from the scene. You also set the cat’s name to an empty string so that it’s no longer considered a normal cat or a cat in the conga line.


调用一些动画来让猫向着那个随机位置移动,在这个过程中一边旋转一边缩小到0.动画的最后把猫从场景中移除.


4. You update the variable that is keeping track of how many cats have been removed from the conga line. Once two or more have been removed, you set the stop Boolean to YES, which causes Sprite Kit to stop enumerating the conga line at that point.


更新以下记录移除猫数量的变量.一旦移除了2个以上的猫,那么就把stop变量设置位YES,这样Sprite Kit就会停止遍历了.


Now that you have this helper method, call it in checkCollisions, right after playing the enemy collision sound:


现在我们有了辅助方法,在checkCollisions方法中播放声音的代码后调用该方法:


[self loseCats]; _lives--;

You are ready to add the code to check if the player should win or lose. Begin by checking for a lose condition. Add this to the end of update:


现在需要判断游戏结果了.从失败条件开始,在update:方法的末尾添加下列代码:


if (_lives <= 0 && !_gameOver) {    _gameOver = YES;    NSLog(@"You lose!");}

To check for the win condition, make the following modifications to moveTrain (some of the code is snipped for brevity):


判断是否胜利,对moveTrain方法进行下列更改(为了保持版面简洁,有些代码被省略了):


- (void)moveTrain {    __block int trainCount = 0;    __block CGPoint targetPosition = _zombie.position;    [self enumerateChildNodesWithName:@“train" usingBlock:^(SKNode *node, BOOL *stop) {         trainCount++;        // Rest of code...    }];}


Here you keep track of how many cats are in the train, and if they’re greater than 30, and the game isn’t over already, you set the game to be over and log out a message.


我们现在已经记录了队伍中猫的数量,如果超过30只,而且游戏并没有结束,我们就结束掉游戏,同时打印一条消息.


Creating a new scene

创建一个新的场景


To create a new scene, you simply create a new class that derives from SKScene. You can then implement initWithSize:, update:, touchesBegan:, or any of the other methods that you overrode in MyScene to implement the behavior you want.


要创建一个场景,我们只需要创建一个继承自SKScene的类.然后重写它的initWithSize:,update:,touchesBegan:或者任何其他的方法来满足你的需求.


创建一个名叫GameOverScene的类.(原文废话太多,不贴了)


Transitioning to a scene

过渡到一个场景


There are three steps to transition from one scene to another:


要从一个场景过渡到另一个场景有三步:


Create the new scene. First you create an instance of the new scene itself. Typically you’d use the default initWithSize: initializer, although you can always choose to create your own custom initializer if you want to be able to pass in some extra parameters. Later in this chapter, you’ll do just that.


创建一个场景.首先创建一个场景的实例.通常来说,我们会使用initWithSize:构造方法,如果需要传递其他的参数,我们也可以创建自己的构造方法.稍后我们会使用这种方式.


2. Create a transition object. Next you create a transition object to specify the type of animation you would like to display the new scene. For example, there are cross fade transitions, flip transitions, door-opening transitions, and many more.


创建一个过渡对象.下一步创建一个过渡对象来确定我们希望用来过渡的动画.举个例子,有淡入淡出,反转,开门等等效果.


3. Call the SKView’s presentScene:transition: method. In iOS, SKView is the UIView that displays Sprite Kit content on the screen. You can get access to this via a property on the scene – self.view. You can then call the presentScene:transition: method to animate to the passed-in scene (created in step 1) with the passed-in transition (created in step 2).


调用SKView的presentScene:transition:方法.在iOS中,SKView是Sprite Kit中用来显示屏幕内容的view.可以通过self.view属性访问.然后调用presentScene:transition:方法来使用第二步中创建的过渡效果过渡到第一步中创建的场景.


Let’s try this out. Open MyScene.m and add the following import to the top of the file:


一起来试一下.打开MyScene.m文件,在文件顶部添加下面代码:


#import "GameOverScene.h"

Next add the following lines in moveTrain, right after where you log “You Win!” tothe console:


然后在moveTrain方法中,打印”You Win!”的代码下面添加代码:


// 1SKScene * gameOverScene =[[GameOverScene alloc] initWithSize:self.size];// 2SKTransition *reveal =[SKTransition flipHorizontalWithDuration:0.5];// 3[self.view presentScene:gameOverScene transition:reveal];


Now add those exact same lines to update:, right after where you log “You lose!” to the console.


然后添加上述代码到update:方法中打印”You lose!”的代码后边.


Build and run, and either win or lose the game. Feel free to cheat and change the number of cats to win to less than 30 – after all, you’re the developer! When you do, you should see the scene transition to a new blank scene:


编译运行,现在无论输赢都将过渡到一个新的空场景:


Creating a custom scene initializer

创建一个自定义的构造函数


Open GameOverScene.h and declare your custom initializer right before the @end:


打开GameOverScene.h然后在@end前面添加一个自定义构造函数的定义:


- (id)initWithSize:(CGSize)size won:(BOOL)won;

This custom initializer takes just one extra parameter: a Boolean that should be YES if the player won and NO if the player lost.


这个自定义的构造函数只是加了一个额外的参数:一个判断玩家是否胜利的布尔值.


Now open GameOverScene.m and start the implementation of the method as follows:


现在打开GameOverScene.m然后实现这个函数:


- (id)initWithSize:(CGSize)size won:(BOOL)won {    if (self = [super initWithSize:size])     {         SKSpriteNode *bg;        if (won)         {            bg = [SKSpriteNode spriteNodeWithImageNamed:@"YouWin.png"];            [self runAction:[SKAction sequence:@[[SKAction waitForDuration:0.1], [SKAction playSoundFileNamed:@“win.wav" waitForCompletion:NO]]] ];        }         else         {            bg = [SKSpriteNode spriteNodeWithImageNamed:@"YouLose.png"];             [self runAction:[SKAction sequence:@[[SKAction waitForDuration:0.1], [SKAction playSoundFileNamed:@“lose.wav" waitForCompletion:NO]]]];        }        bg.position = CGPointMake(self.size.width/2, self.size.height/2);         [self addChild:bg];// More here    }    return self; }

This first calls the superclass’s initWithSize: initializer, passing in the size. It then looks at the won Boolean to choose the proper background image to set and sound effect to play.


首先调用了父类的initWithSize:构造方法,把size传递过去.然后根据won的值来选择适当的背景图片和音效.


In Zombie Conga, you want the game over scene to display for a few seconds and then automatically transition back to the main scene. To do this, first import the header for your main scene at the top of GameOverScene.m:


在游戏中,有希望游戏结束的场景持续显示几秒钟,然后自动过渡到主场景.要实现这一效果,首先在GameOverScene.m文件顶部引入主场景的头文件:


#import "MyScene.h"

Then add these lines of code right after the “More here” comment:


然后在”More here”注释的位置添加下列代码:


SKAction * wait = [SKAction waitForDuration:3.0]; SKAction * block = [SKAction runBlock:^{    MyScene * myScene = [[MyScene alloc] initWithSize:self.size];     SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5];    [self.view presentScene:myScene transition: reveal]; }];[self runAction:[SKAction sequence:@[wait, block]]];


By now, this should all be review for you. The code runs a sequence of actions on the scene, first waiting for 3 seconds, and then calling a block of code. The block of code creates a new instance of MyScene and transitions to that with a flip animation.


这些都是我们学过的东西了.这段代码在游戏结束的场景运行了一个动作序列,首先等待列3秒,然后调用了一个block.在block中创建了一个MyScene的场景,病太浓干过反转效果过渡到了场景中.


One last step – you need to modify your code in MyScene to use this new custom initializer. Open MyScene.m and inside update:, change the line that creates the GameOverScene to indicate that this is the lose condition:


最后一步 — 我们需要修改MyScene来调用这个自定义的构造函数.打开MyScene.m文件,在update:方法中修改创建GameOverScene的代码,标记其为游戏失败:


SKScene * gameOverScene =[[GameOverScene alloc] initWithSize:self.size won:NO];

Inside moveTrain, change the same line but indicate that this is the win condition:


在moveTrain方法中,修改同一行代码,但是标记游戏结果位胜利:


SKScene * gameOverScene = [[GameOverScene alloc] initWithSize:self.size won:YES];

Build and run, and try to win the game. If you do, you’ll see the win scene, which will then flip back to a new game after a few seconds.


编译运行,尝试获胜,如果赢了就会过渡到胜利场景,几秒钟过后又会开始一个新的游戏.


Gratuitous music

背景音乐


You almost have a complete game, but you’re missing one thing – some awesome background music!


我们已经有了一个基本完整的游戏了,但是还有一件事 — 一些超赞的背景音乐!


Luckily, we’ve got you covered. Add the following import to the top of MyScene.m:


幸好,有哥罩着你.在MyScene.m中添加下列import:


@import AVFoundation;


译者注:这里并没有使用
#import <AVFoundation/AVFoundation.h>
但是效果是一样的,而且@import会自动把framework导入到工程内,无需在手动添加~属于iOS7SDK的新特性.


There is no built-in way to play background music in Sprite Kit, so you’ll have to fall back on other iOS APIs to do it. One easy way to play music in iOS is by using the AVAudioPlayer class inside the AVFoundation framework. The first step is to import the framework using iOS 7’s new @import keyword.


在Sprie Kit中并没有直接用来播放声音的方法,所以我们需要 使用其他的iOS API.最简单的方法就是使用AVFoundation框架中的AVAudioPlayer类.第一步就是通过iOS7的新关键字,@import来导入框架.

Next, add the following private instance variable to store the music player:


下一步,添加一个用来保存音乐播放器的私有成员变量:


AVAudioPlayer *_backgroundMusicPlayer;


Then add the a helper routine to play the background music:


然后添加一个用来播放音乐的方法:


-(void)playBackgroundMusic:(NSString *)filename {    NSError *error;    NSURL *backgroundMusicURL = [[NSBundle mainBundle] URLForResource:filename withExtension:nil];    _backgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:backgroundMusicURL error:&error];    _backgroundMusicPlayer.numberOfLoops = -1;    [_backgroundMusicPlayer prepareToPlay];        [_backgroundMusicPlayer play];}

This creates an instance of AVAudioPlayer, passes in the URL of the sound to play, sets up a few properties and then calls play to start the music rolling.


这里创建了一个AVAudioPlayer的实例,并传递了一个声音文件的URL,设定了一些属性,然后开始播放音乐.


Finally, add this line to initWithSize:, right after setting the background color:


最后,在initWithSize:方法中添加下列代码:


[self playBackgroundMusic:@"bgMusic.mp3"];

Here you set up the game to play the background music when the scene first loads.


这里我们让游戏在场景第一次加载的同时开始播放背景音乐.


Next, you need to stop the background music when the player switches scenes, so they can hear the “you win” or “you lose” sound effects. To do this, add this line right after the “You Win!” log line inmoveTrain:


然后我们需要在玩家切换场景的时候停止背景音乐,这样他们才能听到”you win”或者”you lose”的音效.要实现这个效果,在moveTrain:方法中输出”You Win!”的代码后添加下列代码:


[_backgroundMusicPlayer stop];

Also add that same line right after the “You Lose!” log line in update:.


在”You Lose!”的代码后面做同样的处理.


Challenges

挑战


This was a short and sweet chapter, and the challenges will be equally so. There’s just one challenge this time – adding a main menu scene to the game.


这章的内容不多,所以挑战内容也是如此.就一个任务,给游戏添加一个菜单场景.


Usually it will include options to start a new game, continue a game, access game options, and so on.


通常包含新游戏,继续游戏,选项等等.


For Zombie Conga, the main menu scene will be very simple – it will simply show an image and allow the player to tap to continue straight to a new game.


对僵尸康茄舞来说,菜单场景非常简单 — 显示一个图片,用户点击一下来开始新游戏.


Your challenge is to implement a main menu scene that shows the MainMenu.png image as a background and transitions upon screen tap to the main action scene using a “doorway” transition over 0.5 seconds.


你的任务是实现一个拿MainMenu.png当做背景的菜单场景.然后在用户点击屏幕的时候用0.5秒的时间通过”doorway”效果过渡到主场景.


原创粉丝点击