Now,Getting started
创建一个基于SpriteKit Game模板的iOS项目—ZombieConga.项目模板的基本介绍在此略过~
In Sprite Kit, a single object called a scene controls each “screen” of your app. A sceneis a subclass of Sprite Kit’sSKSceneclass.
在Sprite Kit当中,通过一个叫做scene的对象来控制程序中的”场景”.每一个scene都是SKScene类的子类.
Right now this app just has a single scene, MyScene. Open MyScene.m and you’ll see the code that displays the label and rotating space ship. It’s not important to understand this code quite yet – you’re going to remove it all and build up your game one step at a time.
现在程序中只有一个叫做”MyScene”的类,打开”MyScene.m”,你会看到显示标签和旋转的飞船的代码,这段代码并不难理解,现在需要做的是把这些代码统统干掉~初始化函数中仅需要一句:
self.backgroundColor = [SKColor whiteColor];
Zombie Conga is designed to run in landscape mode, so let’s configure the app to launch in landscape.
Zombie Conga是一个专门为横屏设计的软件,所以配置app的启动模式为横屏.
Since you changed the device orientation to landscape, you have to make a chance to the code as well. At the time of writing, the Sprite Kit template uses the View Controller’s main view’s size as the size to create the scene in viewDidLoad, but this size is not guaranteed to be correct at viewDidLoad time.
由于设置了横屏,还需要对代码进行些许更改.Sprite Kit在ViewDidLoad方法中使用ViewController的主view的大小来创建scene,但是在viewDidLoad方法运行时这个大小并不能保证正确.
There are many ways to fix this, but it’s easiest to open ViewController.m, rename viewDidLoad to viewWillLayoutSubviews:, and make a few minor changes as highlighted below:
有很多方法可以修正这一问题,不过最简单的就是把viewDidLoad改成viewWillLayoutSubviews,同时对代码进行少量更改:
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
// Configure the view.
SKView * skView = (SKView *)self.view;
if (!skView.scene) {
skView.showsFPS = YES;
skView.showsNodeCount = YES;
// Create and configure the scene.
SKScene * scene = [MyScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:scene];
}
}
This works because self.view.frame.size is guaranteed to be correct at viewWillLayoutSubviews time, so it will properly use the landscape size. The reason you now check to see if skView.scene exists before creating it is to avoid creating the scene twice (this method can be called more than once).
这一修改是因为视图大小会在viewWillLayoutSubviews方法执行前被设定为正确的值.判断skView.scene是否已经存在是为了防止重复创建(这个方法可能不止调用一次).
There’s two last things: to get this game started on the right foot, you should disable the status bar and set up an app icon. To disable the status bar, open ViewController.m and add this to the bottom:
最后两件事:禁用状态条,添加app图标.通过在ViewController.m中添加如下代码来禁用状态条:
-(BOOL)prefersStatusBarHidden {
return YES;
}
And to set up an app icon, open Images.xassets and select the AppIcon entry. Then in the resources for this chapter, drag all of the files from the “App Icon” folder into the area on the right.
打开 Image.xassets,选中AppIcon,把资源文件中的App Icon文件夹拖到右侧的区域内
(资源文件稍后可以在作者的个人网站http://www.nestor.me 上下载)
显示一个sprite
When making 2D games, you usually put images on the screen representing your game’s hero, monsters, bullets, and so on. Each of these images is called asprite.
当编写2D游戏时,我们通常会将一系列图片放置在屏幕上来呈现游戏中的英雄,怪物,子弹等等,所有这些图片都被称作”sprite”.
Sprite Kit has a special class that makes it easy to create and work with sprites, calledSKSpriteNode. This is what you’ll use to add all your sprites to the game.
Sprite Kit有一个专门用来创建sprite的类,叫做SKSpriteNode.我们将用其来创建游戏中所用到的所有的sprite
In the resources for this chapter, you will find a folder called Art that includes all the images and sounds you need for Zombie Conga
在资源文件中找到一个名为Art的文件夹,它包含了项目中需要用到的所有图片和声音资源
(你懂的...)
创建一个Sprite
Open MyScene.m, and add this line to initWithSize:, right after setting the background color:
打开MyScene.m文件,在设置背景色的代码下边添加如下代码:
SKSpriteNode *bg = [SKSpriteNode spriteNodeWithImageNamed:@"background"];
Note that you do not need to pass the image’s extension, as Sprite Kit will automatically determine that for you.
创建一个sprite的时候不需要写图片的扩展名,SK会自动检测
添加一个Sprite到Scene
It’s just that a sprite will not show up onscreen until you add it as a child of the scene, or one of the scene’s descendent nodes.
sprite不会自动显示在屏幕上,除非你把它作为child添加到scene上,或者说作为scene的子节点
To do this, add this line of code right after the previous line:
可以通过添加如下代码来完成:
[self addChild:bg];
设置sprite的位置
By default, a sprite is positioned at (0, 0), which in Sprite Kit represents the bottom left. Note that this is different from the UIKit coordinate system in iOS, where (0, 0) represents the top left.
默认情况下,sprite会被放置在(0,0)点,位于屏幕的左下方.与iOS UIKit左上角为(0,0)点的坐标系不同
Try positioning the zombie somewhere else by setting the position property. Add this line of code right before calling [self addChild:bg]:
通过设置position属性来把sprite放置在其他的位置上,在添加背景之前加上这段代码:
bg.position = CGPointMake(self.size.width/2, self.size.height/2);
Here you are setting the background to the center of the screen. Even though this is just one line of code, there are four important things to understand
这样就可以把背景放到屏幕的中心了,即便只有1行代码,也有着4个需要理解的要点:
The type of the positionproperty isCGPoint, which is a simple structure that hasxandycomponents:
position属性的类型是CGPoint,一个包含x和y值的结构体
2. You can easily create a new CGPointwith the macro shown above,CGPointMake.
可以通过CGPointMack(x,y)这个宏来创建CGPoint;
3. Since you are writing this code in an SKScene subclass, you can access the size of the scene at any time with theself.sizeproperty. Theself.sizeproperty’s type isCGSize, which is a simple structure likeCGPointthat has widthandheightcomponents.
通过self.size属性可以在任何时候访问SKScene的大小,该属性的类型是一个包含width和height的结构体,叫做CGSize
4. Note that a sprite’s position is within the coordinate space of its parent node, which in this case is the scene itself.
sprite的坐标位于他的父节点的坐标系内部,这里的背景sprite的父节点就是scene本身
Note that when you set the position of the background sprite, you’re actually setting thecenterof the background sprite to that position. This means two things:
注意,当你在设置背景sprite的时候,实际上实在设置它的中心点坐标,这意味着两件事
设置Sprite的锚点
Since this background image is bigger than the size of the screen, you are actually looking at the center part of the image right now. Look at the original image to see for yourself.
由于背景图片的实际大小要比屏幕大,实际上你现在看到的是背景图片的中间部分,不信看看原图
2. This also explains why you could only see the upper half of the sprite earlier. Before you set the position, the position defaulted to (0, 0). This was placing the center of the sprite at the lower left corner of the screen – so you could only see the top half.
这也解释了为什么在最开始的时候你只能看见图片的上半部分.在设置位置之前,默认的坐标点是0,0.这把sprite放置在了屏幕的左下角,所以你只能看到它的上半部分
You can change this behavior by setting a sprite’s anchor point. Think of the anchor point as “the spot within a sprite that you pin to a particular position.” For example, here is an illustration showing a sprite positioned at the center of the screen, but with different anchor points:
你可以通过更改sprite的锚点来改变这一行为.可以把这个锚点理解成为”被钉到指定的位置的点”.(翻译了也不容以看懂,形象点说,下边是一块木板,木板上放了一张图片,你拿一个大头针钉上去,木板上被钉的点就是目标点,图片上被钉的点就是锚点)
bg.anchorPoint = CGPointZero;
bg.position = CGPointZero;
CGPointZero is a handy shortcut for (0, 0). Here you set the anchor point of the sprite to (0, 0) to pin the lower-left corner of the sprite to wherever you set the position – in this case also (0, 0).
这两行代码把bg的锚点设为0,0也就是图片的左下角,然后把bg放到了0,0点,也就是屏幕的左下角,于是就把整个背景的最左边的部分正好放置在了屏幕上.
Here you changed the anchor point for the background for learning purposes. However, usually you can leave the anchor point at its default of (0.5, 0.5), unless you have a specific need to rotate the sprite around a particular point – an example of which is described in the next section.
这里改变背景的锚点主要是为了学习的目的.通常来说,你可以保持默认的锚点,也就是0.5,0.5的中心点,除非你有让sprite围绕某一个点来进行旋转的需求~之后会讲到这个例子.
旋转一个sprite
To rotate a sprite, simply set its zRotationproperty. Try it out on the background sprite by adding this line right before calling[self addChild:bg]:
bg.zRotation = M_PI / 8;
要旋转一个sprite,只需要简单的设置它的zRotation属性,尝试设置背景sprite的zRotation属性为M_PI / 8;
Rotation values are in radians, which are a method of measuring angles. This example rotates the sprite pi / 8 radians, which is equal to 22.5 degrees.
旋转的值基于弧度,一种用来测量角度的方法.这个例子里将sprite旋转pi/8的弧度对应了22.5°.(M_PI == 180°)
I don’t know about you, but I find it easier to think about rotations in degrees, rather than in radians. Later on, you’ll create helper routines to convert between degrees and radians.
我不知道你怎么想,反正我是认为通过角度旋转要比通过弧度旋转容易的多,稍后我们将会创建一个在角度和弧度之前相互转换的工具.
This brings up an interesting point. Sprites are rotated about their anchor points. Since you set the anchor point to (0, 0), this sprite rotates around the bottom-left corner.
这里引出了一个又去的点,sprite会基于他们的锚点进行旋转.由于之前设置了锚点为0,0,这个背景sprite将会围绕着左下角进行旋转.
If you’re wondering when you might want to change the anchor point in a real game, consider the case where you’re creating a character’s body out of different sprites – one for the head, torso, left arm, right arm, left leg and right leg:
或许你会好奇在真正的游戏开发中,什么时候需要修改一个sprite的锚点?试想这样一个场景,当你通过不同的sprite来创建一个游戏人物的身体时—头,躯干,左臂,右臂,左腿,右腿(意思就是关键的连接点)
If you wanted to rotate these body parts at their joints, you’d have to modify the anchor point for each sprite, as shown in the diagram above.
如果你需要在关接触旋转身体的各个部分,就需要像上图(作者很懒,请脑补…)所示的那样修改每一个sprite的锚点
But again, usually you should leave the anchor point at default unless you have a specific need like shown here.
但是通常情况下我们不会修改锚点,除非你有像上述情况一样的特殊需求.
获得Sprite的大小
Sometimes when you’re working with a sprite, you want to know how big it is. A sprite’s size defaults to the size of the image. The class representing this image is called atexturein Sprite Kit.
有些时候我们会想要知道sprite的大小.一个sprite的默认大小与图片的大小相同,在Sprite Kit中我们把这些图片称为材质
NSLog(@“%@",NSStringFromCGSize(bg.size));
通过这行代码可以查看背景sprite的大小.
ZombieConga[16228:70b] {1136, 320}
Sprites 和 nodes
Earlier you learned that that if you want to make a sprite to appear onscreen, you need to add it as a child of the scene, or as one of its descendent nodes. This section will delve more deeply into the concept of nodes.
刚才我们了解到如果想要把一个sprite放到屏幕上,需要把它作为一个child添加给scene,或者说作为scene的子节点.这一部分我们将深入探讨以下节点的概念.
Everything that appears on the screen in Sprite Kit derives from a class called SKNode. The scene class (SKScene) derives from SKNode, and the sprite class (SKSpriteNode) also derives from SKNode.
在SK中,所有显示在瞑目上的东西都派生自一个叫做SKNode的类.SKScene和SKSpriteNode均派生自SKNode.
SKSpriteNode inherits a lot of its capabilities from SKNode. It turns out the position and rotation properties are derived from SKNode, not something particular to SKSpriteNode. This means that, just as you can set the position or rotation of a sprite, you can do the same thing with the scene itself, or anything else that derives from SKNode.
SKSpriteNode继承了SKNode非常多的功能,它所提供的position和rotation属性就是由SKNode继承来的,并非SKSpriteNode自己的东西.这意味着你可以向操纵SKSpriteNode的位置和旋转一样早总scene或者其他任何集橙子SKNode的类.
You can think of everything that appears on the screen as a graph of nodes, often referred to as a scene graph. Here’s an example of what such a graph might look like for Zombie Conga if there was one zombie, two cats and one crazy cat lady in the game:
You’ll learn more about nodes and the neat things you can do with them in Chapter 5, Scrolling. For now, you will be adding your sprites as direct children of the scene itself.
你可以把屏幕上出现的所有的东西理解成为一堆节点的图表,通常来说他们会以一个scene作为参照.(后边的没什么实际意义,不翻了)
总结
And that’s it! As you can see, adding a sprite to a scene takes only three lines of code:
就这么简单!就像你看到的,添加一个sprite到场景上总共就三行代码
1. Create the sprite.//创建一个sprete
2. Position the sprite.//设置他的位置
3. Add it to the scene graph.//把它添加到场景上
(不仅让我想起了把大象关冰箱…)
挑战
添加一个僵尸
Now it’s time for your first challenge – add the zombie to the scene! Here are a few hints:
是时候做点什么了—添加一个僵尸到场景上,这里有几条提示
You’ll need to add three lines of code, which should go inside initWithSize: right after the line that logs the size of the background.
在initWithSize:方法中处理背景大小的代码后边添加三行代码
The first line should create an SKSpriteNode using zombie1.png and store it in _zombie.
第一行使用zombie1.png创建一个SKSpriteNode储存在成员变量_zombie中
The second line should position the zombie sprite at (100, 100).
第二行把僵尸sprite放置在(100,100)上
• The third line should add the zombie to the scene.
第三行把僵尸添加到场景上