Статьи

iOS 8: что нового в SpriteKit, часть 1

В этом руководстве представлен обзор новых функций платформы SpriteKit, представленных в iOS 8. Новые функции призваны упростить поддержку расширенных игровых эффектов и включают поддержку пользовательских шейдеров фрагментов OpenGL ES, освещения, теней, новых расширенных возможностей. физические эффекты и анимация, а также интеграция со SceneKit. В этом руководстве вы узнаете, как реализовать эти новые функции.

Прежде чем приступить к обучению , я хотел бы поблагодарить Мелоди Дешанс ( Wicked Cat ) за предоставление нам игрового искусства, использованного в этой серии.

В этом руководстве предполагается, что вы знакомы как с Spr IteKit, так и с Objective-C. Чтобы взаимодействовать с шейдером и редактором сцены без задержки ввода, я рекомендую вам загрузить и установить Xcode 6.1 или более позднюю версию. Загрузите проект Xcode с GitHub , если хотите подписаться.

Эта серия разделена на два руководства и охватывает самые важные новые функции платформы SpriteKit. В первой части мы рассмотрим шейдеры, освещение и тени. Во второй части я расскажу об интеграции физики и SceneKit.

В то время как каждая часть этой серии стоит отдельно, я рекомендую следовать шаг за шагом, чтобы правильно понять новые возможности платформы SpriteKit. Прочитав обе части, вы сможете создавать как простые, так и более сложные игры, используя новые функции платформы SpriteKit.

SpriteKit предоставляет конвейер рендеринга, который можно использовать для анимации спрайтов. Конвейер рендеринга содержит цикл рендеринга, который чередуется между определением содержимого и фреймами рендеринга. Разработчик определяет содержимое каждого фрейма и то, как он изменяется. SpriteKit использует графический процессор устройства для эффективной визуализации каждого кадра.

Платформа SpriteKit доступна как для iOS, так и для OS X, и поддерживает множество различных видов контента, включая спрайты, текст, фигуры и видео.

Новые функции SpriteKit, представленные в iOS 8:

  • Шейдеры: шейдеры настраивают способ рисования объектов на экране. Они полезны для добавления или изменения эффектов. Шейдеры основаны на фрагментном шейдере OpenGL ES. Каждый эффект применяется для каждого пикселя. Вы используете C-подобный язык программирования для программирования шейдера, и его можно развернуть как на iOS, так и на OS X. Шейдер можно применить к сцене или поддерживаемым классам, SKSpriteNode , SKShapeNode , SKEmitterNode , SKEffectNode и SKScene .
  • Освещение и тени: Освещение используется для освещения сцены или спрайта. Каждый источник света поддерживает цвет, тени и конфигурации с падением. Вы можете иметь до восьми различных источников света на спрайт.
  • Физика. Физика используется для придания реалистичности играм. SpriteKit представляет четыре новых типа физических свойств: физику на пиксель, ограничения, обратную кинематику и физические поля. Свойства для каждого пикселя обеспечивают точное представление взаимодействия объекта. Благодаря множеству предопределенных ограничений, шаблон кода может быть удален в обновлениях сцены. Обратная кинематика используется для представления соединений с использованием спрайтов (опорные точки, отношения родитель-ребенок, максимальное и минимальное вращение и т. Д.). Наконец, вы можете создавать физические поля для имитации гравитации, сопротивления и электромагнитных сил. Эти новые физические функции значительно упрощают реализацию сложных симуляций.
  • Интеграция с SceneKit: С помощью SceneKit вы можете включать 3D-контент в приложения SpriteKit и управлять ими, как обычные экземпляры SKNode . Он визуализирует 3D-контент непосредственно внутри конвейера рендеринга SpriteKit. Вы можете импортировать существующие файлы SKScene или .abc в SKScene .

Я создал проект XCode, чтобы начать нас. Это позволяет нам немедленно начать использовать новые функции SpriteKit. Однако есть несколько вещей, о которых нужно знать.

  • В проекте используется Objective-C, ориентированный только на устройства iPhone с iOS 8.1. Тем не менее, вы можете изменить целевое устройство, если хотите.
  • В разделе Ресурсы > Редактор вы найдете три файла сцены SpriteKit (.sks). В этой серии вы добавите четвертый файл сцены SpriteKit. Каждый файл сцены отвечает за определенный учебный раздел.
  • Шейдер может быть инициализирован одним из двух способов. Первый использует традиционный метод, в то время как второй использует новый метод сцены SpriteKit. Цель состоит в том, чтобы вы узнали о различиях и в будущих проектах выбрали тот, который соответствует вашим потребностям.
  • Если вы создаете экземпляр объекта SKScene с использованием файла сцены SpriteKit, вы всегда будете использовать метод unarchiveFromFile: . Однако обязательно добавьте для каждого файла сцены SKScene соответствующий класс SKScene .
  • Если вы создаете экземпляр объекта SKScene без использования файла сцены SpriteKit, вам следует использовать метод initWithSize: который вы использовали в предыдущих версиях iOS.
  • GameViewController и GameScene содержат метод с именем unarchiveFromFile: Этот метод преобразует графические объекты, определенные в сцене SpriteKit, и превращает их в объект SKScene . Метод использует ключевое слово instancetype , так как он возвращает экземпляр класса, который он вызывает, в данном случае класс SKScene .

Загрузите проект и найдите время, чтобы просмотреть его папки, классы и ресурсы. Создайте и запустите проект на физическом устройстве или в симуляторе iOS. Если приложение работает без проблем, то пришло время начать исследовать новые функции iOS 8 SpriteKit.

В проекте Xcode добавьте новый файл сцены SpriteKit . Выберите « Файл» > « Создать» > « Файл …» и в разделе « Ресурсы » выберите « SpriteKit Scene» . Назовите его ShaderSceneEditor и нажмите « Создать» . Должен появиться серый интерфейс.

В SKNode Inspector справа вы должны увидеть два свойства: Размер и Гравитация . Установите свойство Size с учетом разрешения экрана вашего устройства и установите Gravity на 0.0 .

SKNode Inspector

Вы заметите, что размер желтого прямоугольника меняется, чтобы отразить сделанные вами изменения. Желтый прямоугольник — это интерфейс вашего виртуального устройства. Он показывает вам, как объекты отображаются на вашем устройстве.

Внутри библиотеки объектов справа выберите Color Sprite и перетащите его в желтый прямоугольник.

Библиотека объектов

Выберите цветной спрайт и откройте SKNode Inspector справа, чтобы увидеть его свойства.

SKNode Инспектор цветного спрайта

Вы можете взаимодействовать с объектом в режиме реального времени. Любые сделанные вами изменения отображаются в редакторе. Вы можете играть с Позицией , Размером , Цветом или Масштабом , но то, что вы действительно хотите, это опция Custom Shader . Однако вы заметите, что шейдеров пока нет.

Добавьте новый пустой исходный файл (« Файл» > «Создать»> « Файл …» ), выберите « Другой» > «Пустой» в разделе iOS и назовите его Shader01.fsh . Добавьте следующий код в файл, который вы только что создали.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
void main()
{
    float currTime = u_time;
     
    vec2 uv = v_tex_coord;
    vec2 circleCenter = vec2(0.5, 0.5);
    vec3 circleColor = vec3(0.8, 0.5, 0.7);
    vec3 posColor = vec3(uv, 0.5 + 0.5 * sin(currTime)) * circleColor;
     
    float illu = pow(1. — distance(uv, circleCenter), 4.) * 1.2;
    illu *= (2. + abs(0.4 + cos(currTime * -20. + 50. * distance(uv, circleCenter)) / 1.5));
     
    gl_FragColor = vec4(posColor * illu * 2., illu * 2.) * v_color_mix.a;
}

Приведенный выше кодовый блок генерирует сочетание цветов с учетом центра круга и его края. Apple показала этот шейдер в своей сессии SpriteKit во время WWDC 2014 .

Вернитесь в редактор, выберите объект цветового спрайта и в пользовательском шейдере выберите только что созданный шейдер. Теперь вы должны увидеть шейдер в действии.

Пользовательский шейдер

Программирование шейдеров с использованием Xcode и SpriteKit легко, потому что вы получаете обратную связь в реальном времени. Откройте редактор Assistant и настройте его так, чтобы он отображал как сцену SpriteKit, так и только что созданный вами шейдер.

Посмотрим, как это работает. Введите ошибку времени выполнения в шейдер, например, изменив имя переменной и сохраните изменения, чтобы увидеть результат.

Обратная связь в реальном времени

Как вы можете видеть, Xcode предоставляет быстрый и простой способ предупредить разработчика о возможных ошибках шейдеров. Преимущество заключается в том, что вам не нужно создавать или развертывать приложение на своем устройстве или в iOS Simulator, чтобы посмотреть, все ли работает нормально.

Пришло время добавить еще один шейдер и запрограммировать его вручную.

На этом этапе вы узнаете, как:

  • вызвать шейдер вручную
  • назначить шейдер объекту SpriteKit
  • создавать и отправлять свойства в шейдер

На этом шаге вы добавите пользовательский SKSpriteNode в положение касания пользователя, а затем будете использовать шейдер для изменения цвета текстуры SKSpriteNode .

Первый шаг — добавить еще один шейдер. Назовите новый шейдер shader02.fsh и добавьте следующий блок кода в файл шейдера:

1
2
3
4
void main()
{
    gl_FragColor = texture2D(myTexture,v_tex_coord) * vec4(1, 0.2, 0.2, 1);
}

Откройте файл ShaderScene класса ShaderScene . Первым шагом является определение, коснулся ли пользователь экрана, и определение местоположения касания. Для этого нам нужно реализовать метод touchesBegan:withEvent: Внутри этого метода добавьте экземпляр SKSpriteNode в месте крана. Вы можете использовать любой спрайт, который вам нравится. Я использовал Spaceship.png , который уже включен в проект.

01
02
03
04
05
06
07
08
09
10
— (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    for (UITouch *touch in touches){
        CGPoint location = [touch locationInNode:self];
         
        // Create the node
        SKSpriteNode *space = [SKSpriteNode spriteNodeWithImageNamed:@»Spaceship.png»];
        space.position = CGPointMake(location.x, location.y);
        [self addChild:space];
    }
}

Затем мы создаем объект SKShader и инициализируем его с помощью файла shader02.fsh :

1
SKShader *shader = [SKShader shaderWithFileNamed:@»shader02.fsh»];

Возможно, вы заметили, что исходный файл шейдера ссылается на объект myTexture . Это не предопределенное свойство шейдера, но ссылка, которую ваше приложение должно передать шейдеру. Следующий фрагмент кода иллюстрирует, как это сделать.

1
shader.uniforms = @[ [SKUniform uniformWithName:@»myTexture» texture:[SKTexture textureWithImageNamed:@»Spaceship.png»]] ];

Затем мы добавляем шейдер в объект SKSpriteNode .

1
space.shader = shader;

Вот как должен выглядеть метод touchesBegan:withEvent: ::

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
— (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    for (UITouch *touch in touches){
        CGPoint location = [touch locationInNode:self];
         
        // Create the node
        SKSpriteNode *space = [SKSpriteNode spriteNodeWithImageNamed:@»Spaceship.png»];
        space.position = CGPointMake(location.x, location.y);
        [self addChild:space];
         
        SKShader *shader = [SKShader shaderWithFileNamed:@»shader02.fsh»];
         
        shader.uniforms = @[ [SKUniform uniformWithName:@»myTexture» texture:[SKTexture textureWithImageNamed:@»Spaceship.png»]] ];
         
        space.shader = shader;
    }
}

Создайте и запустите свой проект. Нажмите кнопку Shaders (initWithSize) и коснитесь экрана. Каждый раз, когда вы нажимаете на экран, спрайт космического корабля добавляется с измененной текстурой.

Пример шейдеров с использованием кнопки initWithSize

Используя эту опцию, вы видите, что первый шейдер не представлен на экране. Это происходит потому, что этот шейдер был создан и настроен в редакторе сцен SpriteKit. Чтобы увидеть это, вам нужно инициализировать класс ShaderScene используя метод ShaderScene unarchiveFromFile: .

В GameScene.m вы должны увидеть раздел, который обнаруживает и анализирует нажатия пользователя в touchesBegan:withEvent: Во втором предложении if мы инициализируем экземпляр ShaderScene как показано ниже.

1
2
3
4
if ([node.name isEqualToString:@»buttonShaderCoder»]) {
    ShaderScene *scene = [ShaderScene unarchiveFromFile:@»ShaderSceneEditor»];
    [self.scene.view presentScene:scene];
}

Создайте и запустите свой проект снова, нажмите кнопку Shaders (initWithCoder) и коснитесь экрана. Оба шейдера теперь активны в одной сцене SpriteKit.

Пример шейдеров с помощью кнопки initWithCoder

Освещение и тени — это два свойства, которые играют вместе. Цель этого раздела — добавить несколько легких узлов и спрайтов и поиграть с их свойствами.

Откройте LightingSceneEditor.sks и просмотрите объекты внутри библиотеки мультимедиа справа. В библиотеке мультимедиа вы можете увидеть ресурсы, включенные в проект.

Выберите и перетащите background.jpg к желтому прямоугольнику. Если вы не изменили разрешение сцены по умолчанию, изображение должно поместиться внутри прямоугольника.

Когда вы выберете спрайт, вы заметите, что он имеет несколько свойств, таких как Положение , Размер , Положение Z , Маска освещения, Маска литья тени , Определение физики и многие другие.

SKSpriteNode Свойства

Не стесняйтесь играть с этими свойствами. Однако сейчас важно, чтобы вы оставили свойства по умолчанию. Перетащите объект Light из библиотеки объектов справа на фоновый спрайт. Положение света не важно, но есть и другие свойства света.

Вы можете настроить цвет , тень и цвет окружающей среды, чтобы настроить свет и тень. Z Position — высота узла относительно его родительского узла. Установите его в 1 . Маска освещения определяет, к каким категориям относится этот свет. При визуализации сцены свойство categoryBitMask источника света сравнивается со свойствами lightingBitMask , shadowCastBitMask и shadowCastBitMask каждого узла спрайта. Если значения совпадают, этот спрайт взаимодействует со светом. Это позволяет вам определять и использовать несколько источников света, которые взаимодействуют с одним или несколькими объектами.

Вы, наверное, заметили, что фон не изменился после добавления света. Это происходит из-за того, что маска освещения и фона различна. Вам нужно установить маску освещения фона на ту, что у источника света, которая в нашем примере равна 1 .

Обновите фон в Инспекторе SKNode и нажмите Enter. Эффект этого изменения является немедленным. Свет теперь освещает фон в зависимости от его положения. Вы можете изменить положение источника света, чтобы видеть взаимодействие между фоном и узлами источника света в режиме реального времени.

Чтобы повысить реалистичность фона или подчеркнуть одну из его особенностей, поиграйте со свойствами плавности и контрастности . Поиграйте со значениями, чтобы увидеть изменения в реальном времени.

Пришло время добавить несколько объектов, которые взаимодействуют с узлом света. В библиотеке мультимедиа найдите спрайты croquette -o.png и croquette-x.png и добавьте их в сцену.

Каждый спрайт должен быть настроен индивидуально. Выберите каждый спрайт и установите маску освещения, маску тени и Положение Z до 1 . Осветительная маска обеспечивает воздействие на спрайт светового узла, в то время как маска отбрасывания теней создает тень в реальном времени на основе положения светового узла. Наконец, установите для параметра « Тип тела» ( определение физики ) значение « Нет» . Сделайте это для обоих спрайтов.

Физика Определение

Вы должны были заметить, что даже после настройки свойств освещения и тени вы не можете видеть взаимодействие между светом и узлами. Для этого вам нужно собрать и запустить проект на физическом устройстве или в симуляторе.

Результат освещения

Вы уже знаете, как добавить источники света, используя редактор сцен. Давайте посмотрим, как добавить источник света без использования редактора сцены.

Откройте LightingScene.m и внутри didMoveToView: метод мы создаем объект SKLightNode объект SKLightNode .

Для объекта SKSpriteNode мы используем спрайт Wicked-Cat.png . Положение узла не так важно, но значения zPosition , shadowCastBitMask и lightingBitMask являются. Поскольку SpriteKit анализирует данные последовательно, вам нужно установить zPosition узла в 1 чтобы этот спрайт был виден поверх фонового спрайта. Мы устанавливаем shadowCastBitMask и lightingBitMask в 1 .

Вот как выглядит метод didMoveToView: :

1
2
3
4
5
6
7
8
9
— (void)didMoveToView:(SKView *)view {
    SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:@»Wicked-Cat.png»];
    [sprite setPosition:CGPointMake(self.frame.size.width/2, self.frame.size.height/2)];
    [sprite setScale:0.6];
    [sprite setZPosition:1];
    [sprite setShadowCastBitMask:1];
    [sprite setLightingBitMask:1];
    [self addChild:sprite];
}

Далее давайте добавим объект SKLightNode . Вы должны обратить особое внимание на свойство categoryBitMask . Если вы установите его на 1 , этот свет будет взаимодействовать с каждым спрайтом. Назовите его light и установите zPosition на 1 .

Полный фрагмент SKLightNode должен выглядеть следующим образом:

01
02
03
04
05
06
07
08
09
10
SKLightNode* light = [[SKLightNode alloc] init];
[light setName:@»light»];
[light setPosition:CGPointMake(100, 100)];
[light setCategoryBitMask:1];
[light setFalloff:1.5];
[light setZPosition:1];
[light setAmbientColor:[UIColor whiteColor]];
[light setLightColor:[[UIColor alloc] initWithRed:1.0 green:0.0 blue:0.0 alpha:.5]];
[light setShadowColor:[[UIColor alloc] initWithRed:0.9 green:0.25 blue:0.0 alpha:.5]];
[self addChild:light];

На данный момент у вас есть второй свет. Но давайте добавим немного взаимодействия с пользователем. Для этого вам нужно добавить метод touchesMoved:withEvent: и изменить положение источника света с учетом местоположения касания.

1
2
3
4
5
6
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    for (UITouch *touch in touches) {
        CGPoint location = [touch locationInNode:self];
        [self childNodeWithName:@»light»].position = CGPointMake(location.x, location.y);
    }
}

В заключение,   соберите и запустите ваше приложение. Нажмите кнопку « Освещение» , и вы увидите нечто похожее на скриншот ниже:

Полный пример освещения

На этом мы завершаем первое руководство из нашей серии из двух частей, посвященное новым функциям платформы SpriteKit, представленным в iOS 8. В этой части вы научились создавать собственные шейдеры и световые эффекты с помощью редактора сцен SpriteKit и с помощью кода. Если у вас есть какие-либо вопросы или комментарии, как всегда, не стесняйтесь оставлять комментарии в комментариях.