В этом руководстве представлен обзор новых функций платформы SpriteKit, представленных в iOS 8. Новые функции призваны упростить поддержку расширенных игровых эффектов и включают поддержку пользовательских шейдеров фрагментов OpenGL ES, освещения, теней, новых расширенных возможностей. физические эффекты и анимация, а также интеграция со SceneKit. В этом руководстве вы узнаете, как реализовать эти новые функции.
Формат серии
Эта серия разделена на два руководства и охватывает самые важные новые функции платформы SpriteKit. В первой части мы рассмотрим шейдеры, освещение и тени. Во второй части я расскажу об интеграции физики и SceneKit.
В то время как каждая часть этой серии стоит отдельно, я рекомендую следовать шаг за шагом, чтобы правильно понять новые возможности платформы SpriteKit. Прочитав обе части, вы сможете создавать как простые, так и более сложные игры, используя новые функции платформы SpriteKit.
Загрузите проект Xcode, который мы создали в предыдущей статье, с GitHub, если вы хотите подписаться на него.
1. Физика
В iOS 8 SpriteKit представил новые физические функции, такие как физика на пиксель, ограничения, обратная кинематика и физика.
Кинематика — это процесс расчета трехмерного положения конца связанной структуры с учетом углов всех соединений. Обратная кинематика (IK) делает противоположное. С учетом конечной точки конструкции, какие углы должны быть выполнены соединениями для достижения этой конечной точки? Следующее изображение разъясняет эти понятия.
SpriteKit позволяет использовать спрайты для представления соединений, которые используют отношения родитель-потомок для создания иерархии соединений. Для каждого отношения вы определяете обратные кинематические ограничения для каждого соединения и контролируете минимальный и максимальный угол поворота между ними. Обратите внимание, что каждый сустав вращается вокруг своей точки привязки.
Шаг 1: Обратная кинематика (IK)
Откройте PhysicsSceneEditor и добавьте спрайт croquette-o.png в желтый прямоугольник. Выберите спрайт и измените Имя в Инспекторе SKNode на Корень . Установите для параметра « Тип тела определения физики» значение « Нет» .
Добавьте второй спрайт, wood.png и измените его Имя на FirstNode . Измените родительское поле на Root. Переместите FirstNode , поместив его справа от Root, и измените его размер, чтобы создать прямоугольник, как показано ниже. Установите для параметра « Тип тела определения физики» значение « Нет» .
Результат должен выглядеть примерно так:
Обратите внимание, что при выборе узла спрайта в его центре появляется белый круг. Этот круг представляет точку привязки узла спрайта, вокруг которой выполняется каждое вращение.
Шаг 2: Добавьте больше спрайтов
Выполните предыдущие шаги и добавьте еще два спрайта.
Первый спрайт
- Добавьте еще один спрайт croquette-o.png .
- Измените его имя SecondNode .
- Измените его Родителя на FirstNode .
- Разместите его справа от FirstNode .
- Измените тип тела определения физики на None .
Второй спрайт
- Добавьте еще один спрайт wood.png .
- Измените его поле имени на ThirdNode .
- Измените его Parent на SecondNode .
- Расположите его справа от второго узла .
- Измените его размер, чтобы создать прямоугольник.
- Измените тип тела определения физики на None .
Результат должен выглядеть примерно так:
Шаг 3: Редактировать и моделировать
Чтобы проверить совместные соединения, взаимодействия и ограничения, вам не нужно создавать и запускать свой проект. Xcode предоставляет два режима: редактировать и моделировать.
Режим имитации обеспечивает среду тестирования в реальном времени, а режим редактирования используется для создания и редактирования вашей сцены. До сих пор мы работали в режиме редактирования. Обратите внимание, что любые изменения, сделанные в режиме имитации, не сохраняются.
В нижней части редактора сцены вы можете увидеть, в каком режиме вы сейчас работаете. Если нижняя панель редактора сцены белая, значит, вы находитесь в режиме редактирования. Синий фон означает, что вы находитесь в режиме симуляции. Нажмите на ярлык в нижней панели, чтобы переключиться между двумя режимами.
Измените режим для имитации и выберите спрайты FirstNode, SecondNode и ThirdNode. Вы можете выбрать несколько спрайтов, нажав Command .
Затем нажмите Shift-Control-Click и переместите спрайты по сцене. В результате узлы спрайтов анимируются и вращаются. Тем не менее, вращение странно и должно быть исправлено.
Шаг 4: IK Ограничения
Вернитесь в режим редактирования и добавьте несколько ограничений к узлам спрайта. Выберите каждый узел спрайта и измените его свойства следующим образом.
Выберите узлы спрайтов Root и SecondNode и установите максимальный угол ограничения IK равным 0
. Выберите узлы спрайтов FirstNode и ThirdNode и установите для точки привязки X значение 0
а для максимального угла IK — 90
.
Изменяя эти свойства, положение и размер узлов спрайта будут меняться. После добавления ограничений вручную отрегулируйте их размер и положение и переключитесь в режим имитации, чтобы проверить добавленные нами новые ограничения.
На скриншоте ниже показана правильная конфигурация ограничений.
Шаг 5: Узел магнитного поля
Магнитные поля также являются новыми в SpriteKit. Давайте посмотрим, как это работает, добавив магнитное поле на физическую сцену. Откройте PhysicsScene.m и переменную экземпляра с именем SKFieldNode
типа SKFieldNode
.
1
2
3
|
@implementation PhysicsScene {
SKFieldNode *magneticFieldNode;
}
|
В didMoveToView:
метод, мы сначала конфигурируем сцену, создавая экземпляр SKPhysicsBody
для сцены и добавив гравитационную силу. Это означает, что любые узлы в сцене будут вытянуты вниз.
1
2
3
|
SKPhysicsBody *physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
[self.physicsWorld setGravity:CGVectorMake(0, -9)];
[self setPhysicsBody:physicsBody];
|
Чтобы настроить объект MagneticFieldNode, вам необходимо настроить его физическое тело, а также его положение и силу. Обратите внимание, что каждый SKFieldNode
имеет свои собственные свойства. В следующем фрагменте кода показано, как настроить узел магнитного поля. Мы добавляем новый узел в качестве дочернего узла на сцену.
1
2
3
4
5
|
magneticFieldNode = [SKFieldNode magneticField];
[magneticFieldNode setPhysicsBody:[SKPhysicsBody bodyWithCircleOfRadius:80]];
[magneticFieldNode setPosition:CGPointMake(100, 100)];
[magneticFieldNode setStrength:3];
[self addChild:magneticFieldNode];
|
Шаг 6: Взаимодействия
Чтобы увидеть магнитное поле в действии, нам нужно добавить несколько узлов, с которыми может взаимодействовать нота магнитного поля. В следующем фрагменте кода мы создаем триста спрайтов. Обратите внимание, что каждый узел спрайта имеет свое собственное физическое тело, и мы установили для свойства YES
значение YES
.
01
02
03
04
05
06
07
08
09
10
11
12
|
for (int i = 0; i < 300; i++) {
SKSpriteNode *node4 = [SKSpriteNode spriteNodeWithTexture:[SKTexture textureWithImageNamed:@»wood.png»] size:CGSizeMake(25, 25)];
[node4 setPhysicsBody:[SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(25, 25)]];
[node4 setPosition:CGPointMake(arc4random()%640, arc4random()%950)];
[node4.physicsBody setDynamic:YES];
[node4.physicsBody setAffectedByGravity:YES];
[node4.physicsBody setAllowsRotation:true];
[node4.physicsBody setMass:0.9];
[self addChild:node4];
}
|
Завершенный didMoveToView:
метод должен выглядеть следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
-(void)didMoveToView:(SKView *)view {
SKPhysicsBody *physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
[self.physicsWorld setGravity:CGVectorMake(0, -9)];
[self setPhysicsBody:physicsBody];
magneticFieldNode = [SKFieldNode magneticField];
[magneticFieldNode setPhysicsBody:[SKPhysicsBody bodyWithCircleOfRadius:80]];
[magneticFieldNode setPosition:CGPointMake(100, 100)];
[magneticFieldNode setStrength:3];
[self addChild:magneticFieldNode];
for (int i = 0; i < 300; i++) {
SKSpriteNode *node4 = [SKSpriteNode spriteNodeWithTexture:[SKTexture textureWithImageNamed:@»wood.png»] size:CGSizeMake(25, 25)];
[node4 setPhysicsBody:[SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(25, 25)]];
[node4 setPosition:CGPointMake(arc4random()%640, arc4random()%950)];
[node4.physicsBody setDynamic:YES];
[node4.physicsBody setAffectedByGravity:YES];
[node4.physicsBody setAllowsRotation:true];
[node4.physicsBody setMass:0.9];
[self addChild:node4];
}
}
|
Перед созданием и запуском приложения мы touchesMoved:withEvent:
метод touchesMoved:withEvent:
чтобы вы могли перемещать узел магнитного поля, touchesMoved:withEvent:
пальцем.
1
2
3
4
5
|
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
[magneticFieldNode setPosition:[touch locationInNode:self]];
}
}
|
Создайте и запустите приложение, чтобы проверить влияние узла магнитного поля на сцену. Для получения дополнительной информации об имитации физики с использованием среды SpriteKit я рекомендую прочитать документацию Apple по этой теме.
2. Интеграция SceneKit
SceneKit — это высокоуровневая среда Objective-C для создания приложений и игр, использующих трехмерную графику. Он поддерживает импорт, манипулирование и рендеринг трехмерных активов. Алгоритм рендеринга требует только описания содержимого вашей сцены, анимации и действий, которые вы хотите выполнить.
Благодаря SceneKit вы теперь можете создавать и доставлять 3D-контент, используя SpriteKit. SceneKit имеет древовидную структуру и может использоваться двумя способами:
- автономная среда SceneKit
- интегрирован в SpriteKit
SceneKit имеет древовидную структуру. В автономной среде SceneKit базовым классом для древовидной структуры является экземпляр SCNNode
как показано на диаграмме ниже. Объект SCNNode
сам по себе не имеет видимого содержимого при визуализации сцены, содержащей его. Он просто определяет позицию в пространстве, которая представляет положение, вращение и масштаб узла относительно его родительского узла.
Когда вы интегрируете SceneKit в приложение на основе SpriteKit, вам нужно определить объект SK3DNode
в качестве корневого объекта для вашей сцены. Это означает, что основная иерархия SceneKit изменяется на следующее:
Обратите внимание, что не каждый дочерний узел на приведенной выше схеме является обязательным. Вы только определяете и настраиваете узлы, которые соответствуют вашим потребностям. Например, вы можете добавить узел SCNLight
для освещения сцены, даже если вы не включили узел SCNCamera
в сцену.
Шаг 1. Предварительный просмотр моделей
SpriteKit и SceneKit поддерживают несколько форматов файлов для импорта моделей. Вы можете просмотреть эти модели в режиме реального времени в Xcode. Внутри папки « Текстуры » в вашем проекте ( Ресурсы> Текстуры ), есть файл с именем ship.dae . Когда вы выбираете этот файл, вы получаете новый пользовательский интерфейс, как показано ниже.
Слева от редактора вы видите две группы:
- Объекты: эта группа содержит информацию о предопределенных анимациях, положении камеры, источниках света и материалах, определенных файлом модели. Файл, который мы открыли, содержит только информацию о геометрии модели и ее материале.
- Граф сцены: эта группа содержит информацию об исходной сетке объекта. В этом случае объект был создан как единое целое, и вы видите только одну сетку.
Шаг 2. Импорт внешней модели
Чтобы использовать SceneKit в сочетании со SpriteKit, необходимо импортировать библиотеку SceneKit из инфраструктуры SceneKit. Откройте SceneKitScene.m и включите его, как показано ниже.
1
|
#include <SceneKit/SceneKit.h>
|
Мы собираемся использовать модель, хранящуюся в ship.dae, в качестве 3D-сцены. Внутри didMoveToView:
метод создайте объект SCNScene
который загружает сцену из этого файла.
1
|
SCNScene *shipScene = [SCNScene sceneNamed:@»ship.dae»];
|
Помните древовидную иерархию, о которой я упоминал ранее? Чтобы добавить объект shipScene
объекту SKScene
, необходимо выполнить два шага:
- создать объект
SK3DNode
- определить сцену SceneKit для визуализации
В этом случае сценой для визуализации является shipScene
. Обратите внимание, что вы также определяете положение узла и его размер.
1
2
3
|
SK3DNode *sk3DNodeFist = [[SK3DNode alloc] initWithViewportSize:CGSizeMake(300, 300)];
[sk3DNodeFist setPosition:CGPointMake(200,300)];
[sk3DNodeFist setScnScene:shipScene];
|
Наконец, добавьте объект SK3DNode
в качестве дочернего узла к объекту SKScene
.
1
|
[self addChild:sk3DNodeFist];
|
Чтобы сделать окончательный результат более привлекательным, установите цвет фона сцены на зеленый, как показано ниже.
1
|
[self setBackgroundColor:[SKColor greenColor]];
|
Вот как должен выглядеть законченный didMoveToView:
метод. Создайте и запустите приложение, чтобы увидеть результат.
01
02
03
04
05
06
07
08
09
10
|
-(void)didMoveToView:(SKView *)view {
[self setBackgroundColor:[SKColor greenColor]];
SCNScene *shipScene = [SCNScene sceneNamed:@»ship.dae»];
SK3DNode *sk3DNodeFist = [[SK3DNode alloc] initWithViewportSize:CGSizeMake(300, 300)];
[sk3DNodeFist setPosition:CGPointMake(200,300)];
[sk3DNodeFist setScnScene:shipScene];
[self addChild:sk3DNodeFist];
}
|
Шаг 3: Создание пользовательской сцены
Давайте создадим более сложную сцену, которая содержит несколько объектов SCNNode
. Для этой второй сцены нам нужно создать еще SK3DNode
объект SK3DNode
.
1
2
|
SK3DNode *sk3DNode = [[SK3DNode alloc] initWithViewportSize:CGSizeMake(400, 400)];
[sk3DNode setPosition:CGPointMake(150,200)];
|
Затем мы создаем объект SCNScene
, который будет содержать дочерние узлы сцены.
1
|
SCNScene *sceneObject = [SCNScene scene];
|
Этот sceneObject
будет иметь три узла:
- Камера: этот узел используется для просмотра сцены через заданную позицию.
- Свет: этот узел позволяет вам видеть различные свойства материала трехмерного объекта. Вы обычно определяете тип света и цвет.
- 3D-объект: это импортированный или определенный объект в вашем коде. По умолчанию SceneKit позволяет вам определять несколько параметрических трехмерных объектов, то есть тора, прямоугольника, пирамиды, сферы, цилиндра, конуса, трубки, капсулы, пола, трехмерного текста или пользовательской фигуры.
Для каждого отдельного узла вы всегда выполняете три действия. Давайте возьмем узел камеры в качестве примера.
- Создайте объект
SCNCamera
и определите его свойства. - Создайте
SCNNode
которому будет назначенSCNCamera
. - Добавьте
SCNNode
как дочерний узел к объектуSCNScene
.
Давайте теперь создадим три узла, которые я упоминал ранее. Это то, что нам нужно реализовать для создания узла камеры.
1
2
3
4
5
|
SCNCamera *camera = [SCNCamera camera];
SCNNode *cameraNode = [SCNNode node];
[cameraNode setCamera:camera];
[cameraNode setPosition:SCNVector3Make(0, 0, 40)];
[sceneObject.rootNode addChildNode:cameraNode];
|
По умолчанию местоположение камеры и 3D-сцена расположены в начале координат (0,0,0)
. Используя свойство position, вы можете настроить камеру вдоль трех осей x, y и z, чтобы изменить ее положение.
Легкий узел требует немного больше работы, но следующий фрагмент кода должен быть легким для понимания.
1
2
3
4
5
6
7
8
9
|
SCNLight *spotLight = [SCNLight light];
[spotLight setType:SCNLightTypeDirectional];
[spotLight setColor:[SKColor redColor]];
SCNNode *spotLightNode = [SCNNode node];
[spotLightNode setLight:spotLight];
[spotLightNode setPosition:SCNVector3Make(0, 0, 5)];
[cameraNode addChildNode:spotLightNode];
[sceneObject.rootNode addChildNode:spotLightNode];
|
Мы также создадим объект torus, как показано в следующем фрагменте кода.
1
2
3
4
|
SCNTorus *torus= [SCNTorus torusWithRingRadius:13 pipeRadius:1.5];
SCNNode *torusNode = [SCNNode nodeWithGeometry:torus];
[torusNode setTransform:SCNMatrix4MakeRotation(M_PI / 3, 0, 1, 0)];
[sceneObject.rootNode addChildNode:torusNode];
|
Наконец, мы устанавливаем сцену, которую мы хотим визуализировать, и добавляем sk3DNode
в качестве дочернего узла экземпляра SKScene
.
1
2
|
[sk3DNode setScnScene:sceneObject];
[self addChild:sk3DNode];
|
Вот как должен выглядеть финальный didMoveToView:
метод.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
-(void)didMoveToView:(SKView *)view {
[self setBackgroundColor:[SKColor greenColor]];
SCNScene *shipScene = [SCNScene sceneNamed:@»ship.dae»];
SK3DNode *sk3DNodeFist = [[SK3DNode alloc] initWithViewportSize:CGSizeMake(300, 300)];
[sk3DNodeFist setPosition:CGPointMake(200,300)];
[sk3DNodeFist setScnScene:shipScene];
[self addChild:sk3DNodeFist];
SK3DNode *sk3DNode = [[SK3DNode alloc] initWithViewportSize:CGSizeMake(400, 400)];
[sk3DNode setPosition:CGPointMake(150,200)];
SCNScene *sceneObject = [SCNScene scene];
SCNCamera *camera = [SCNCamera camera];
SCNNode *cameraNode = [SCNNode node];
[cameraNode setCamera:camera];
[cameraNode setPosition:SCNVector3Make(0, 0, 40)];
[sceneObject.rootNode addChildNode:cameraNode];
SCNLight *spotLight = [SCNLight light];
[spotLight setType:SCNLightTypeDirectional];
[spotLight setColor:[SKColor redColor]];
SCNNode *spotLightNode = [SCNNode node];
[spotLightNode setLight:spotLight];
[spotLightNode setPosition:SCNVector3Make(0, 0, 5)];
[cameraNode addChildNode:spotLightNode];
[sceneObject.rootNode addChildNode:spotLightNode];
SCNTorus *torus= [SCNTorus torusWithRingRadius:13 pipeRadius:1.5];
SCNNode *torusNode = [SCNNode nodeWithGeometry:torus];
[torusNode setTransform:SCNMatrix4MakeRotation(M_PI / 3, 0, 1, 0)];
[sceneObject.rootNode addChildNode:torusNode];
[sk3DNode setScnScene:sceneObject];
[self addChild:sk3DNode];
}
|
Создайте и запустите приложение. Вы должны увидеть нечто похожее на следующий скриншот.
Шаг 4: Анимация сцены
Вы можете анимировать сцену, используя класс CABasicAnimation
. Вам просто нужно создать экземпляр CABasicAnimation
, вызвав animationWithKeyPath:
Анимация, которую мы создаем в следующем фрагменте кода, будет бесконечно зацикливаться и будет длиться пять секунд. Добавьте следующий фрагмент кода в метод didMoveToView:
1
2
3
4
5
6
7
|
CABasicAnimation *torusRotation = [CABasicAnimation animationWithKeyPath:@»rotation»];
torusRotation.byValue = [NSValue valueWithSCNVector4:SCNVector4Make(1, 1, 0, 4.0*M_PI)];
[torusRotation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
[torusRotation setRepeatCount:INFINITY];
[torusRotation setDuration:5.0];
[torusNode addAnimation:torusRotation forKey:nil];
|
Создайте и запустите приложение для проверки анимации.
3. Больше SpriteKit
Если вы хотите узнать больше о SpriteKit, я советую вам прочитать следующие учебные пособия по SpriteKit:
- Создайте игру на самолете с набором спрайтов
- Построить ракетное командование с помощью набора спрайтов
- iOS SDK: создайте игру с фактами
Если вы хотите узнать больше о платформе SpriteKit, то я рекомендую прочитать Руководство по программированию SpriteKit от Apple или просмотреть справочник по фреймворку .
Вывод
На этом завершается второй урок из этой серии из двух частей, посвященной новым функциям платформы SpriteKit, представленным в iOS 8. В этой части вы узнали, как использовать физическое моделирование и интегрировать SceneKit. Если у вас есть какие-либо вопросы или комментарии, не стесняйтесь оставлять комментарии в комментариях.