G.Y @zaaa read-only
Пользователь
11 августа 2014 в 22:55

Разработка → Создание игры на движке Sprite Kit (Часть 1)

С появлением iOS 7 мир узрел новый игровой движок от Apple — SpriteKit. В свете того, что он появился совсем недавно об этом движке еще мало что написано, конечно в сети можно найти несколько tutorial -ов по нему но в основном все они на Английском языке. И по этому я задалась целью написать подробный Туториал об этом замечательном движке.

Итак, что же такое SpriteKit?


SpriteKit — это 2D движок, оптимизированный для создание игр для устройств от компании Apple. В его основе лежит популярный физический движок Box 2D. Поскольку разработчики создавали его заточенным специально для устройств Apple он существенно выигрывает в скорости у остальных движков.
В SpriteKit всю роль по оптимизации и рисованию графики берет на себя OpenGl, это все происходит на низком уровне и по этому вы можете сосредоточить свои усилия на решении проблем более высокого уровня и создание больших 2D игр. Для создание игр на SpriteKit используется язык Objective-c, но с выходом iOS 8 и нового языка Swift, игры также можно создавать и на нем.
От себя хотела бы добавить, что в некотором роде на Swift писать даже легче, так что если вы только начинаете и думаете какой язык выбрать то советую выбрать Swift.

Ниже, я предоставила видео с демонстрацией игрового процесса SpriteKit, если вам стало интересно то милости прошу.






Начало




Итак, давайте начнем, откройте Xcode.
Создайте новый проект, когда вам предложат выбрать Application template выберите тип Game.



Далее после ввода данных вам предложат выбрать язык: это либо Objective-c, либо совсем новый Swift.
Можете выбрать любой, в этой статье примеры будут на обоих.
Дальше в пункте Game Tehnology выбираем SpriteKit.
Также не забудьте выбрать устройство для которого собираетесь писать, в нашем случае это Iphone.



Итак, мы создали наш проект, слева мы видим наши файлы для Objective-C это:
Objective-c

Для Swift:
Swift

Как вы уже успели заметить, в проекте со Swift файлов вдвое меньше.
Слева мы видим:

1) AppDelegate — делегат нашего проекта.
2) GameViewController — контроллер наше проекта.
3) GameScene — основная сцена нашей игры.
4) GameScene.sks — это визуальный конструктор нашей сцены, его добавили с выходом iOS 8, служит для визуального добавление некоторых элементов.


Давайте заглянем в некоторые файлы и посмотрим что у них внутри.



GameViewController




GameViewController — он отвечает за создание и инициализацию нашей сцены. Все начальные настройки служащие для отображения нашей сцены нужно проводить здесь.

В целом все что, происходит в GameViewController одинаково для обоих языков:
В самом начале вызывается метод или функция viewDidLoad.
В этом методе или функции происходит: создание и настройка нашей сцены и некоторых параметров ее отображения.

Objective-c
- (void)viewDidLoad
{
    [super viewDidLoad];

    // Configure the view.
    SKView * skView = (SKView *)self.view; // Создается указатель на объект SKView и ему присваивается текущий View.
    skView.showsFPS = YES; // Разрешить отображать частоту обновлений нашей сцены
    skView.showsNodeCount = YES; // Разрешить  показывать число Node (Объектов на нашей сцене).
    /* Sprite Kit applies additional optimizations to improve rendering performance */
    skView.ignoresSiblingOrder = YES;// Разрешить применять дополнительную оптимизацию для улучшения производительности рендеринга
    
    // Create and configure the scene.
    GameScene *scene = [GameScene unarchiveFromFile:@"GameScene"]; // Создаем и инициализируем объект нашей сцены.
    scene.scaleMode = SKSceneScaleModeAspectFill; // Присвоить свойству ScaleMode объекта Scene тип SKSceneScaleModeAspectFill.
    
    // Present the scene.
     // Передаем методу presentScene, объекта skView в качестве параметра объект нашей сцены и этим отображаем наше сцену  
    [skView presentScene:scene];
}

Swift
override func viewDidLoad() {
        super.viewDidLoad()
  // 
  if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene  //Проверяем принадлежит ли наш объект классу GameScene 
  {
      // Configure the view.
      let skView = self.view as SKView // константе  SKView присваивается текущий UIView
      skView.showsFPS = true // Разрешить отображать частоту обновлений нашей сцены
      skView.showsNodeCount = true // Разрешить  показывать число Node (Объектов на нашей сцене).
           
       /* Sprite Kit applies additional optimizations to improve rendering performance */
      skView.ignoresSiblingOrder = true // Разрешить применять дополнительную оптимизацию для улучшения производительности рендеринга
            
       /* Set the scale mode to scale to fit the window */
      scene.scaleMode = .AspectFill  // Присвоить свойству ScaleMode объекта Scene тип AspectFill.
       
      // Передаем функции presentScene, объекта skView в качестве параметра объект нашей сцены и этим отображаем наше сцену      
      skView.presentScene(scene) 
  }
    }


В самом начале, в этом методе или функции создается указатель или константа на объект типа SKView и ему присваивается текущий View.

SKView — это наследник UIView, он служит для отображение нашей сцены.

Далее идет настройка основных свойств нашего SKView:
showFPS — это свойство отображает частоту обновлений нашей сцены.
showsNodeCount — показывает число Node (Объектов на нашей сцене).
ignoressSiblingOrder — применяет дополнительную оптимизацию для улучшения производительности рендеринга.
Кроме перечисленных, у SKView есть еще много прочих полезных свойств, посмотрите и поэкспериментируйте с ними!


Далее идет создание Объекта нашей сцены — GameScene. В случае со Swift он уже был создан до конфигурации нашего View.
По умолчанию объект нашей сцены инициализируется с вызова метода или функции:

Objective-c
+ (instancetype)unarchiveFromFile:(NSString *)file {
    /* Retrieve scene file path from the application bundle */
    NSString *nodePath = [[NSBundle mainBundle] pathForResource:file ofType:@"sks"];
    /* Unarchive the file to an SKScene object */
    NSData *data = [NSData dataWithContentsOfFile:nodePath
                                          options:NSDataReadingMappedIfSafe
                                            error:nil];
    NSKeyedUnarchiver *arch = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
    [arch setClass:self forClassName:@"SKScene"];
    SKScene *scene = [arch decodeObjectForKey:NSKeyedArchiveRootObjectKey];
    [arch finishDecoding];
    
    return scene;
}

Swift
class func unarchiveFromFile(file : NSString) -> SKNode?
 {
        
        let path = NSBundle.mainBundle().pathForResource(file, ofType: "sks")
        
        var sceneData = NSData.dataWithContentsOfFile(path, options: .DataReadingMappedIfSafe, error: nil)
        var archiver = NSKeyedUnarchiver(forReadingWithData: sceneData)
        
        archiver.setClass(self.classForKeyedUnarchiver(), forClassName: "SKScene")
        let scene = archiver.decodeObjectForKey(NSKeyedArchiveRootObjectKey) as GameScene
        archiver.finishDecoding()
        return scene
    }

Что происходит при его вызове, он находит файл нашего визуального конструктора GameScene.sks затем разархивирует его, а после возвращает объект типа SKScene для последующий инициализации нашей сцены.
Обратите внимание что, у объекта нашей сцены, есть свойства:
scaleMode как можно догадаться из названия, это свойство выполняет растяжку сцены по экрану, поэкспериментируйте с этим свойством!

После того, как мы настроили наш SKView и создали объект нашей сцены, теперь можно ее отобразить. Делается это очень просто, мы вызываем функцию или метод класса SKView:
Objective-c
 - (void)presentScene:(SKScene *)scene transition:(SKTransition *)transition;

Swift
func presentScene(scene: SKScene!, transition: SKTransition!)

а затем передаем в качестве параметра объект нашей сцены, теперь скомпилируем и «вуаля» наша сцена готова!



Ниже я привела полный код GameViewController.


Objective-c
#import "GameViewController.h"
#import "GameScene.h"

@implementation SKScene (Unarchive)

+ (instancetype)unarchiveFromFile:(NSString *)file {
    /* Retrieve scene file path from the application bundle */
    NSString *nodePath = [[NSBundle mainBundle] pathForResource:file ofType:@"sks"];
    /* Unarchive the file to an SKScene object */
    NSData *data = [NSData dataWithContentsOfFile:nodePath
                                          options:NSDataReadingMappedIfSafe
                                            error:nil];
    NSKeyedUnarchiver *arch = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
    [arch setClass:self forClassName:@"SKScene"];
    SKScene *scene = [arch decodeObjectForKey:NSKeyedArchiveRootObjectKey];
    [arch finishDecoding];
    
    return scene;
}

@end

@implementation GameViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Configure the view.
    SKView * skView = (SKView *)self.view; // 
    skView.showsFPS = YES;
    skView.showsNodeCount = YES;
    /* Sprite Kit applies additional optimizations to improve rendering performance */
    skView.ignoresSiblingOrder = YES;
    
    // Create and configure the scene.
    GameScene *scene = [GameScene unarchiveFromFile:@"GameScene"];
    scene.scaleMode = SKSceneScaleModeAspectFill;
    
    // Present the scene.
    [skView presentScene:scene];
}

- (BOOL)shouldAutorotate
{
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations
{
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
        return UIInterfaceOrientationMaskAllButUpsideDown;
    } else {
        return UIInterfaceOrientationMaskAll;
    }
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Release any cached data, images, etc that aren't in use.
}

@end


Swift
import UIKit
import SpriteKit

extension SKNode {
    class func unarchiveFromFile(file : NSString) -> SKNode? {
        
        let path = NSBundle.mainBundle().pathForResource(file, ofType: "sks")
        
        var sceneData = NSData.dataWithContentsOfFile(path, options: .DataReadingMappedIfSafe, error: nil)
        var archiver = NSKeyedUnarchiver(forReadingWithData: sceneData)
        
        archiver.setClass(self.classForKeyedUnarchiver(), forClassName: "SKScene")
        let scene = archiver.decodeObjectForKey(NSKeyedArchiveRootObjectKey) as GameScene
        archiver.finishDecoding()
        return scene
    }
}

class GameViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
            // Configure the view.
            let skView = self.view as SKView
            skView.showsFPS = true
            skView.showsNodeCount = true
            
            /* Sprite Kit applies additional optimizations to improve rendering performance */
            skView.ignoresSiblingOrder = true
            
            /* Set the scale mode to scale to fit the window */
            scene.scaleMode = .AspectFill
            
            skView.presentScene(scene)
        }
    }

    override func shouldAutorotate() -> Bool {
        return true
    }

    override func supportedInterfaceOrientations() -> Int {
        if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
            return Int(UIInterfaceOrientationMask.AllButUpsideDown.toRaw())
        } else {
            return Int(UIInterfaceOrientationMask.All.toRaw())
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Release any cached data, images, etc that aren't in use.
    }
    
}




GameScene




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

Как вы уже успели заметить, по умолчанию у нас запуститься сцена с некоторыми уже добавленными объектами.
Удалите все в GameScene так, что бы она соответствовала коду ниже:

Objective-c

#import "GameScene.h"

@implementation GameScene

-(void)didMoveToView:(SKView *)view
{
    
}


@end





Swift

import SpriteKit


class GameScene: SKScene
{
    override func didMoveToView(view: SKView)
    {
        
    }
    
    
}





Теперь скомпилируем наш проект и мы увидим:



Мы видим пустой серый экран и больше ничего, кроме количества Node объектов и частоты обновлений сцены, теперь давайте остановимся и проанализируем код в GameScene.

Чтобы понять как наша сцена работает, нам сначала нужно понять ее основные методы или функции, ниже я приведу основные, остальные вы можете посмотреть и сами в .h файле.

Основные свойства:
1) sizeОпределяет размер нашей сцены.
2) scaleModeОпределяет отображение нашей сцены.
3) backgroundColorОпределяет цвет нашей сцены, по умолчанию серый (как мы и успели заметить выше).
4) anchorPointОпределяет начальную точку нашей сцены.
5) viewНаш исходный View.
6) physicsWorldЭто очень важное свойства, которое отвечает за физику сцены (Гравитация, скорость) мы подробно поговорим о нем позже.

Основные методы или функции
1) didMoveToView:Вызывается, после того как наша сцена отобразилась.
2) willMoveFromView:Вызывается, после того как наша сцена была удалена.
3) didChangeSize:Вызывается, при изменение размера нашей сцены.
4) convertPointToView:Служит для конвертирования координат
5) convertPointFromView:Служит для конвертирования координат
6) initWithSize:Вызывается при инициализации нашей сцены.

Основные события нашей сцены
События нужны для написание основной логики нашей игры, Они вызываются именно в том порядке в котором я написала!
1) Update:Здесь реализуется основная логика нашей игры.
2) didEvaluateActionsСлужит для расчетов наших Action — действий.
3) didSimulatePhysicsСлужит для расчетов физических событий.
4) didApplyConstriantsСлужит для расчетов ограничений.
5) didFinishUpdateВызывается, после того как все выше перечисленные события выполнились.

Итак, друзья, теперь когда мы видели основные методы или функции, Свойства и события нашей сцены, мы можем немного изменить наш код. Давайте попробуем изменить цвет нашей сцены, для этого обратимся к свойству backgroundColor и покрасим нашу сцену в оранжевый цвет. Как мы уже видели выше, при инициализации сцены первым должен вызваться метод или функция initWithSize:, а после того как наша сцена уже отобразилась, вызывается didMoveToView:. В нашем случае, сцена инициализируется с вызова метода или функции unarchiveFromFile и поэтому мы уже не можем повторно написать метод инициализации. И поэтому, нам остается определить наши начальные настройки в didMoveToView:.

Objective-c
#import "GameScene.h"

@implementation GameScene


-(void)didMoveToView:(SKView *)view
{
    [self SceneSetting]; // вызываем метод SceneSetting
}


-(void)SceneSetting
{
    self.backgroundColor = [SKColor orangeColor]; // изменяем цвет сцены на оранжевый
}


@end

Swift

import SpriteKit

class GameScene: SKScene
{
    override func didMoveToView(view: SKView)
    {
        SceneSetting() // вызываем функцию SceneSetting
    }
    
    
    func SceneSetting()
    {
        self.backgroundColor = SKColor.orangeColor() // изменяем цвет сцены на оранжевый
        
    }
}


Как видно из примеров выше, сначала вызывается метод или функция didMoveToView, далее в нем(ей) вызывается метод или функцию SceneSetting, а уже после изменяется цвет нашей сцены. Обратите внимание, что при изменение цвета мы не обращаемся к объекту UIColor как мы привыкли, мы обращаемся к SKColor, по сути это define UIColor и поэтому вы можете писать и так и так, ошибкой это не будет. Вы наверно спросите, для чего я вынесла настройки в отдельный метод или функцию. Я это сделала для удобство, в больших проектах порой бывает очень трудно ориентироваться, и нам будет очень удобно, если мы в самом начале все будем делать аккуратно.

Итак, что у нас получилась вы видите на изображении снизу.


На нашей сцене, еще ничего не происходит, так давайте это исправим друзья!
А иначе, что мы тут делаем!



SKNode




Ну что, друзья, как видите мы изменили цвет нашей сцены и вы наверно задались вопросом, и все? и ради этого мы зашли сюда?

Друзья, к сожаление я не могу продемонстрировать вам всю мощь, какую имеет наша сцена, для этого нам нужно изучить еще один очень важный пункт это — SKNode.

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

Давайте посмотрим на Свойство, Методы или Функции, нашего SKNode.

Свойство
1) frameОпределяет форму нашего Node.
2) positionОпределяет позицию нашего Node.
3) zPositionОпределяет положение нашего Node относительно оси Z.
4) zRotationОпределяет поворот нашего Node в углах Эйлера.
5) xScaleОпределяет масштаб нашего Node по оси x.
6) yScaleОпределяет масштаб нашего Node по оси y.
7) speedОпределяет скорость нашего Node.
8) alphaОпределяет Альфа компоненту нашего Node.
9) pausedВозвращает Yes, если наш Node не выполняет Actions — действий.
10) hiddenВозвращает Yes, если наш Node спрятан.
11) isUserInteractionEnabledВозвращает Yes, если наш Node принимает касание.
12) parentВозвращает, родительский Node.(Если возвращает nil, то он сам является родительским Node )
13) childrenВозвращает всех потомков нашего Node.
14) nameОпределяет имя нашего Node. (Очень важное свойство)
15) sceneСцена на которой в данный момент находится наш Node.
16) physicsBodyФизическое Тело Нашего Node.(Очень важное свойство о котором подробнее узнаем чуть позже)
17) userDataОпределяет место куда можно записывать полезную информацию нашего Node.
18) reachConstraintsОпределяет степень свободы в IK (Inverse Kinematics) — Action действиях.
19) constraintsОпределяет список Ограничений.


Методы или Функции
1) setScaleЗадать масштаб.(равномерно по X & Y)
2) addChildДобавить потомка.(Добавить один Node на другого)
3) insertChildИзъять потомка.
4) removeChildrenInArrayУдалить потомков по списку.
5) removeAllChildrenУдалить всех потомков.
6) removeFromParentУдалить родительский Node.
7) childNodeWithNameВозвращает потомка по имени.
8) enumerateChildNodesWithNameПересчитать всех потомков по определенному имени.
9) inParentHierarchyВернет Yes, если наш Node является членом Иерархии
10) runActionВыполнить Action — действие.
11) runAction — completionВыполнить Action — действие, после завершение вызывает блок Completion.
12) runAction — withKeyВыполнить Action — действие, с заданным ключом.
13) hasActionВозвращает Yes, если наш Node выполняет Action — действие
14) actionForKeyВозвращает Action — действие, с заданным ключом.
15) removeActionForKeyУдалить Action — действие с заданным ключом.
16) removeAllActionsУдалить все Action — действие нашего Node.
17) containsPointВозвращает Yes, если наша точка лежит внутри нашего Node/
18) nodeAtPointВозвращает объект типа SKNode, находящийся в этой точки.
19) nodesAtPointВозвращает список объектов типа SKNode находящихся в этой точки.
20) convertPoint — fromNodeКонвертирует и возвращает координаты для нашей системы координат.
21) convertPoint — toNodeКонвертирует и возвращает координаты для НЕ нашей системы координат.
22) intersectsNodeВозвращает Yes, если наш Node пересекается с границей другого Node
23) calculateAccumulatedFrameВозвращает координаты границ, включая потомков.
24) locationInNodeВозвращает координаты Node, которого мы коснулись.
25) previousLocationInNodeВозвращает координаты Node, которого мы коснулись до этого.

Итак, мы почти закончили, друзья потерпите еще чуть-чуть. Как мы видим, чуть выше, SKNode не такой уж и сложный в своем строении!
Да и вообще, сам SpriteKit не сложный, просто нужно немного терпения и все!

Продолжим, от SKNode наследуются несколько основных Объектов, давайте по-быстрому на них посмотрим:


1) SKSpriteNodeЭто стандартный Спрайт.
2) SKShapeNodeЭто составной Спрайт — объект, который может принимать практически любую форму.
3) SKFieldNodeЭто поля с воздействием физических сил на другие тела.
4) SKEmitterNodeЭто специальный Node(particle), это особые частицы из которых можно создавать крутые эффекты.
5) SKLabelNodeЭто Node, который выводит текст с различными опциями.
6) SKEffectNodeЭто Node который добавляет специальные эффекты для его потомков.
7) SKLightNodeЭто Node, добавляет свет и тени к нашей Сцене, появился с выходом iOS 8.
8) SKVideoNodeЭто Node, который позволяет отображать видео в нашей сцене.
9) SKCropNodeЭто Node, который позволяет изменять текстуру объекта определенной формы.
10) SK3DNodeКак видно из название, это Node, который позволяет добавлять 3D объекты.



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

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


Визуальный обзор Node




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

Давайте найдем наш ViewController и изменим в нем эти свойство.

Objective-c
scene.scaleMode = SKSceneScaleModeResizeFill;


- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscape;
}


Swift
scene.scaleMode = .ResizeFill


override func supportedInterfaceOrientations() -> Int
{
        return Int(UIInterfaceOrientationMask.Landscape.toRaw())
}



SKSpriteNode





SKSpriteNode — это стандартный спрайт, который отображает Текстуры (Графические изображения).
Давайте посмотрим на него вблизи, на изображении ниже мы видим три объекта (Спрайта):
Синий квадрат, Спрайт с изображением дощечки, и Спрайт заднего фона.
Я специально создала 3 объекта типа SKSpriteNode, что бы вы увидели различия в их создании.



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

Весь код с описанием процесса создания находится чуть ниже, здесь я объясню некоторые моменты.

Первый спрайт имеет имя BackgroundSprite, перед его созданием, мы создаем объект типа SKTexture, и в него в качестве параметра передаем имя нашего изображения. Зачем нужен этот объект?
Текстуры, очень полезны для работы с изображениями еще до создание нами самих спрайтов, с их помощь можно экономно управлять ресурсами, один и тот же объект может быть использован несколькими спрайтами.

Далее мы задаем размер и позицию. Несколько слов о позиции, в SKSpriteNode ее мы отсчитываем от середины нашего объекта, то есть когда говорят мы сдвинули такой то спрайт на 100px, это значит мы сдвинули его центральную точку на 100px.
После того, как мы задали размер и позицию, мы изменяем свойство anchorPoint. Его изменять не обязательно, я это сделала для того, чтобы было удобнее подогнать наше изображение под весь экран. Сейчас вы все поймете!
Как вы уже знаете, anchorPoint — это точка отсчета, и как я уже писала выше, позицию нашего Спрайта определяет точка по середине, так вот anchorPoint ее изменяет. Что бы лучше понять давайте рассмотрим картинку ниже:



Как видно на изображение нарисованы декартовы координаты. По умолчанию объекты SKSpriteNode имеют anchorPoint равный (0.5, 0.5), то есть по центру. В примере я изменила это свойство и задала его равным (0, 0), если мы опять посмотрим на изображение то увидим, что это точка находится в самом нижнем левом углу, а это значит что теперь наша начальная точка уже будет не посередине, а снизу слева. И теперь если скажут, что мы сдвинули такой то спрайт на 100px, это значит мы сдвинули его самую нижнюю и самую левую точку на 100px.

Далее мы задаем имя, это тоже очень важное свойство, его в данном случае писать было не обязательно, так как у нас пока что не происходит никаких действий.
Зачем нужно имя? По нему мы будем находить, определять и различать наши объекты. Будьте осторожны с выбором имени!.

После того, как мы задали необходимые нам свойства, мы обращаемся к нашей сцене и вызываем у нее метод или функцию:
addChildДобавить потомка.(Добавить один Node на другого), который(-ая) добавляет наш объект на сцену.

Как я уже писала выше, наша сцена тоже является наследником от SKNode и поэтому мы добавляем один Node на другого.
Этот метод или функция работает так же, если вы захотите, скажем добавить один спрайт на другой.

Второй Спрайт с именем SimpleSprite, при его создании мы передаем два параметра это: Цвет и размер.
В качестве цвета мы передаем объект типа UIColor, как я уже писала выше мы можем передать и SKColor, это не будет ошибкой.
Еще один момент, это zPosition, как вы уже знаете zPosition — Определяет положение нашего Node относительно оси Z.
По умолчанию это свойство равно 0. Когда я создавала наши объекты, почему-то объект с именем SimpleSprite — второй объект, находился под остальными, видимо из-за особенностей его инициализации и поэтому я присвоила этому спрайту свойство zPosition равному 1.
Еще одно очень важное замечание: Node не находящийся на одной плоскости не могут взаимодействовать!
То есть, если у одного zPosition равен 0, а у другого 1 то они не будут контактировать!

Третий Спрайт, с именем ImageSprite, при его инициализации мы ему в качестве параметра передали имя нашей картинки.
Этот способ, конечно отличается от первого, где мы создавали объект типа SKTexture, но для обычной инициализации весьма подходит.

Objective-c
Objective-C

#import "GameScene.h"

@implementation GameScene


-(void)didMoveToView:(SKView *)view
{
    [self SceneSetting];
    [self SKSpriteNodeDemo]; // Вызываем только что созданный нами метод 
    
}


-(void)SceneSetting
{
     self.backgroundColor = [SKColor orangeColor];
 }

-(void)SKSpriteNodeDemo
{
     // Создаем указатель на объект типа SKTexture и инициализируем его. В качестве параметра передаем имя нашего изображение.
    SKTexture *Texture = [SKTexture textureWithImageNamed:@"desert_BG"];
    
    //Создаем наш SKSpriteNode и инициализируем его. В качестве параметра передаем объект типа SKTexture, который мы создали выше.
    SKSpriteNode *BackgroundSprite = [SKSpriteNode spriteNodeWithTexture:Texture]; 
    BackgroundSprite.size = CGSizeMake(640, 320); // Задаем размер.
    BackgroundSprite.position = CGPointMake(0, 0); // задаем позицию.
    BackgroundSprite.anchorPoint = CGPointMake(0, 0); //задаем начальную точку.
    BackgroundSprite.name = @"BackgroundSprite";// задаем имя.
    [self addChild:BackgroundSprite];//добавляем наш объект на нашу сцену.
    
    //Создаем наш SKSpriteNode и инициализируем его. В качестве параметров передаем цвет и размер.
    SKSpriteNode *SimpleSprite = [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:CGSizeMake(50, 50)];
    SimpleSprite.position = CGPointMake(200, 150);// задаем позицию.
    SimpleSprite.zPosition = 1;// задаем  положение нашего объекта относительно оси Z.
    SimpleSprite.name = @"SimpleSprite";// задаем имя.
    [self addChild:SimpleSprite];//добавляем наш объект на нашу сцену.

    //Создаем наш SKSpriteNode и инициализируем его. В качестве параметра передаем имя нашего изображение.
    SKSpriteNode *ImageSprite = [SKSpriteNode spriteNodeWithImageNamed:@"DerevoOpora"];
    ImageSprite.position = CGPointMake(250, 50);// задаем позицию.
    ImageSprite.size = CGSizeMake(100, 15);// Задаем размер.
    ImageSprite.name = @"ImageSprite";// задаем имя.
    [self addChild:ImageSprite];//добавляем наш объект на нашу сцену.
    
}


@end




Swift
Swift

import SpriteKit


class GameScene: SKScene
{
    override func didMoveToView(view: SKView)
    {
        SceneSetting()
        SKSpriteNodeDemo() //Вызываем только что созданную нами функцию.
    }
    
    
    func SceneSetting()
    {
        self.backgroundColor = SKColor.orangeColor()
    
    }
    
    func SKSpriteNodeDemo()
    {
        //Создаем переменную Texture и ей присваиваем объект типа SKTexture. В качестве параметра передаем имя нашего изображение
        var Texture = SKTexture(imageNamed: "desert_BG") 

        //Создаем переменную BackgroundSprite и ей присваиваем объект типа SKSpriteNode. 
        // В качестве параметра передаем объект типа SKTexture созданный нами  выше.
        var BackgroundSprite = SKSpriteNode(texture: Texture)
        BackgroundSprite.size = CGSizeMake(640, 320) //задаем размер.
        BackgroundSprite.position = CGPointMake(0, 0) //задаем позицию.
        BackgroundSprite.anchorPoint = CGPointMake(0, 0) //задаем начальную точку.
        BackgroundSprite.name = "BackgroundSprite" // задаем имя.
        self.addChild(BackgroundSprite) //добавляем наш объект на нашу сцену.
        
        //Создаем переменную SimpleSprite и ей присваиваем объект типа SKSpriteNode. 
        // В качестве параметров передаем цвет и размер.
        var SimpleSprite = SKSpriteNode(color: UIColor.blueColor(), size: CGSizeMake(50, 50))
        SimpleSprite.position = CGPointMake(200, 150) //задаем позицию.
        SimpleSprite.zPosition = 1; // задаем  положение нашего объекта относительно оси Z.
        SimpleSprite.name = "SimpleSprite" // задаем имя.
        self.addChild(SimpleSprite) //добавляем наш объект на нашу сцену.
        
        //Создаем переменную ImageSprite и ей присваиваем объект типа SKSpriteNode. 
         // В качестве параметров передаем имя нашего изображение.
        var ImageSprite = SKSpriteNode(imageNamed: "DerevoOpora")
        ImageSprite.position = CGPointMake(250, 50)  //задаем позицию.
        ImageSprite.size = CGSizeMake(100, 15) //задаем размер.
        ImageSprite.name = "ImageSprite" // задаем имя.
        self.addChild(ImageSprite) //добавляем наш объект на нашу сцену.
        
        
    }
    
    
}


Ну что же, вы увидели визуально SKSpriteNode и увидели простейшие формы его инициализации, пока что этого хватит, давайте пойдем дальше и посмотрим еще один тип Node — это SKShapeNode.


SKShapeNode





SKShapeNode — Это составной Спрайт — объект, который может принимать практически любую форму. То есть он может быть почти любой геометрической фигурой: Окружность, Квадрат, Треугольник, Эллипс.
В строение он немного сложнее, чем SKSpriteNode так как здесь вся форма составная. Но он незаменим в построении сложных форм, без него очень тяжело управиться.
Ладно довольно слов перейдем к делу!



Давайте рассмотрим метод или функцию в которой(-ом) реализованы фигуры выше, полный код вы найдете ниже.
Итак, для удобства я закомментировала предыдущий метод или функцию, так что не пугайтесь, если вдруг не увидите предыдущих объектов.

Objective-c
Objective-c

-(void)SKShapeNodeDemo
{
     //Создаем наш SKShapeNode и инициализируем его. В качестве параметра передаем радиус.
    SKShapeNode *Circle = [SKShapeNode shapeNodeWithCircleOfRadius:20]; 
    Circle.position = CGPointMake(50, 200); // задаем позицию.
    Circle.lineWidth = 10; // задаем ширину линий.
    Circle.strokeColor = [SKColor blueColor]; // задаем цвет контура.
    Circle.fillColor = [SKColor redColor]; // задаем цвет внутренности.
    Circle.name = @"Circle"; // задаем имя.
    [self addChild:Circle]; // добавляем наш объект на нашу сцену.
    
     //Создаем наш SKShapeNode и инициализируем его. В качестве параметра передаем координаты и размер прямоугольника (CGRectMake).
    SKShapeNode *Quad = [SKShapeNode shapeNodeWithRect:CGRectMake(0, 0, 50, 50)];
    Quad.position = CGPointMake(100, 200); // задаем позицию.
    Quad.lineWidth = 4; // задаем ширину линий.
    Quad.strokeColor = [SKColor whiteColor]; // задаем цвет контура.
    Quad.fillColor = [SKColor blackColor]; // задаем цвет внутренности.
    Quad.name = @"Quad"; // задаем имя.
    [self addChild:Quad]; // добавляем наш объект на нашу сцену.
    
      // Создаем наш SKShapeNode и инициализируем его. В качестве параметра передаем координаты и размер прямоугольника (CGRectMake).
     // В данном случае форма эллипса будет создана внутри прямоугольника в соответствии с его размерами.
    SKShapeNode *Ellips = [SKShapeNode shapeNodeWithEllipseInRect:CGRectMake(0, 0, 50, 90)];
    Ellips.position = CGPointMake(200, 200); // задаем позицию.
    Ellips.lineWidth = 2; // задаем ширину линий.
    Ellips.strokeColor = [SKColor greenColor]; // задаем цвет контура.
    Ellips.fillColor = [SKColor purpleColor]; // задаем цвет внутренности.
    Ellips.glowWidth = 5; // задаем эффект свечение контура.
    Ellips.name = @"Ellips"; // задаем имя.
    [self addChild:Ellips]; // добавляем наш объект на нашу сцену.
    
    
    
    // Создаем и инициализируем объект типа UIBezierPath. В качестве параметра передаем координаты и размер прямоугольника (CGRectMake),
    // а также радиус округление углов.
    UIBezierPath *RoundedRectPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 50, 50) cornerRadius:12];

    // Создаем наш SKShapeNode и инициализируем его. В качестве параметра передаем объект созданный нами выше и булева значение.
    // обратите внимание на то, что к объекту передаваемому в первом параметре добавляется свойство CGPath.
    SKShapeNode *RoundedRect = [ SKShapeNode shapeNodeWithPath:RoundedRectPath.CGPath centered:YES];
    RoundedRect.position = CGPointMake(50, 100); // задаем позицию.
    RoundedRect.lineWidth = 2;  // задаем ширину линий.
    RoundedRect.strokeColor = [SKColor blueColor]; // задаем цвет контура.
    RoundedRect.fillColor = [SKColor redColor]; // задаем цвет внутренности.
    RoundedRect.name = @"RoundedRect"; // задаем имя.
    [self addChild:RoundedRect]; // добавляем наш объект на нашу сцену.
    
   
    UIBezierPath *TrianglePath = [UIBezierPath bezierPath];  // Создаем и инициализируем объект типа UIBezierPath.
    [TrianglePath moveToPoint:CGPointMake(0, 0)]; // переходим на точку с заданными координатами.
    [TrianglePath addLineToPoint:CGPointMake(-25, -50)]; // добавляем линию к заданной точке.
    [TrianglePath addLineToPoint:CGPointMake(25, -50)]; // добавляем линию к заданной точке.
    [TrianglePath addLineToPoint:CGPointMake(0, 0)]; // добавляем линию к заданной точке.
   
    // Создаем наш SKShapeNode и инициализируем его. В качестве параметра передаем объект созданный нами выше и булева значение.
    // обратите внимание на то, что к объекту передаваемому в первом параметре добавляется свойство CGPath.
    SKShapeNode *Triangle = [SKShapeNode shapeNodeWithPath:TrianglePath.CGPath centered:YES];
    Triangle.position = CGPointMake(200, 70); // задаем позицию.
    Triangle.lineWidth = 2; // задаем ширину линий.
    Triangle.strokeColor = [SKColor blackColor]; // задаем цвет контура.
    Triangle.fillColor = [SKColor blueColor]; // задаем цвет внутренности.
    Triangle.name = @"Triangle"; // задаем имя.
    [self addChild:Triangle]; // добавляем наш объект на нашу сцену.
    
}


Swift
Swift
func SKShapeNodeDemo()
    {
        
        // Создаем переменную Circle и ей присваиваем объект типа SKShapeNode. в качестве параметра передаем радиус.
        var Circle = SKShapeNode(circleOfRadius: 20)
        Circle.position = CGPointMake(50, 200) // задаем позицию.
        Circle.lineWidth = 10 // задаем размер линий.
        Circle.strokeColor = SKColor.blueColor() // задаем цвет контура.
        Circle.fillColor = SKColor.redColor() // задаем цвет внутренности.
        Circle.name = "Circle" // задаем имя.
        self.addChild(Circle) // добавляем наш объект на нашу сцену.
        
         // Создаем переменную Quad и ей присваиваем объект типа SKShapeNode. 
         // В качестве параметра передаем координаты и размер прямоугольника (CGRectMake).
        var Quad = SKShapeNode(rect: CGRectMake(0, 0, 50, 50))
        Quad.position = CGPointMake(100, 200) // задаем позицию.
        Quad.lineWidth = 4 // задаем размер линий.
        Quad.strokeColor = SKColor.whiteColor() // задаем цвет контура.
        Quad.fillColor = SKColor.blackColor() // задаем цвет внутренности.
        Quad.name = "Quad" // задаем имя.
        self.addChild(Quad) // добавляем наш объект на нашу сцену.
        
         // Создаем переменную Ellips и ей присваиваем объект типа SKShapeNode.
        // В данном случае форма эллипса будет создана внутри прямоугольника в соответствии с его размерами.
        var Ellips = SKShapeNode(ellipseInRect: CGRectMake(0, 0, 50, 90))
        Ellips.position = CGPointMake(200, 200) // задаем позицию.
        Ellips.lineWidth = 2 // задаем размер линий.
        Ellips.strokeColor = SKColor.greenColor() // задаем цвет контура.
        Ellips.fillColor = SKColor.purpleColor() // задаем цвет внутренности.
        Ellips.glowWidth = 5 // задаем эффект свечение контура.
        Ellips.name = "Ellips" // задаем имя.
        self.addChild(Ellips) // добавляем наш объект на нашу сцену.
        
        // Создаем переменную RoundedRectPath и ей присваиваем объект типа UIBezierPath.
        // В качестве параметра передаем координаты и размер прямоугольника (CGRectMake),  а также радиус округление углов.
        var RoundedRectPath = UIBezierPath(roundedRect: CGRectMake(0, 0, 50, 50), cornerRadius: 12)
        
         // Создаем переменную RoundedRect и ей присваиваем объект типа SKShapeNode. 
        // В качестве параметра передаем объект созданный нами выше и булева значение.
       // обратите внимание на то, что к объекту передаваемому в первом параметре добавляется свойство CGPath.
        var RoundedRect = SKShapeNode(path: RoundedRectPath.CGPath, centered:true)
        RoundedRect.position = CGPointMake(50, 100) // задаем позицию.
        RoundedRect.lineWidth = 2 // задаем размер линий.
        RoundedRect.strokeColor = SKColor.blueColor() // задаем цвет контура.
        RoundedRect.fillColor = SKColor.redColor() // задаем цвет внутренности.
        RoundedRect.name = "RoundedRect" // задаем имя.
        self.addChild(RoundedRect) // добавляем наш объект на нашу сцену.
        
        
        
        
        
        var TrianglePath = UIBezierPath() // Создаем и инициализируем объект типа UIBezierPath.
        TrianglePath.moveToPoint(CGPointMake(0, 0)) // переходим на точку с заданными координатами.
        TrianglePath.addLineToPoint(CGPointMake(-25, -50)) // добавляем линию к заданной точке.
        TrianglePath.addLineToPoint(CGPointMake(25, -50)) // добавляем линию к заданной точке.
        TrianglePath.addLineToPoint(CGPointMake(0, 0)) // добавляем линию к заданной точке.
        
         // Создаем переменную Triangle и ей присваиваем объект типа SKShapeNode. 
        // В качестве параметра передаем объект созданный нами выше и булева значение.
       // обратите внимание на то, что к объекту передаваемому в первом параметре добавляется свойство CGPath.
        var Triangle = SKShapeNode(path: TrianglePath.CGPath, centered: true)
        Triangle.position = CGPointMake(200, 70) // задаем позицию.
        Triangle.lineWidth = 2 // задаем размер линий.
        Triangle.strokeColor = SKColor.blackColor() // задаем цвет контура.
        Triangle.fillColor = SKColor.blueColor() // задаем цвет внутренности.
        Triangle.name = "Triangle" // задаем имя.
        self.addChild(Triangle) // добавляем наш объект на нашу сцену.
 }


У SKShapeNode есть несколько способов инициализации, их можно разделить на две группы:
Стандартная инициализация или инициализация с помощью объекта UIBezierPath.

Рассмотрим их по отдельности!

Стандартная инициализация


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

Circle
Давайте рассмотрим наш первый объект, это Circle. Как можно заметить, при его создании мы вызываем метод shapeNodeWithCircleOfRadius или функцию circleOfRadius и в него(-нее) в качестве параметра передаем радиус.

Objective-c
//Создаем наш SKShapeNode и инициализируем его. В качестве параметра передаем радиус.
    SKShapeNode *Circle = [SKShapeNode shapeNodeWithCircleOfRadius:20]; 
    Circle.position = CGPointMake(50, 200); // задаем позицию.
    Circle.lineWidth = 10; // задаем ширину линий.
    Circle.strokeColor = [SKColor blueColor]; // задаем цвет контура.
    Circle.fillColor = [SKColor redColor]; // задаем цвет внутренности.
    Circle.name = @"Circle"; // задаем имя.
    [self addChild:Circle]; // добавляем наш объект на нашу сцену.

Swift
// Создаем переменную Circle и ей присваиваем объект типа SKShapeNode. в качестве параметра передаем радиус.
        var Circle = SKShapeNode(circleOfRadius: 20)
        Circle.position = CGPointMake(50, 200) // задаем позицию.
        Circle.lineWidth = 10 // задаем размер линий.
        Circle.strokeColor = SKColor.blueColor() // задаем цвет контура.
        Circle.fillColor = SKColor.redColor() // задаем цвет внутренности.
        Circle.name = "Circle" // задаем имя.
        self.addChild(Circle) // добавляем наш объект на нашу сцену.


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

Дальше задаем два цветовых свойство: strokeColor и fillColor.

strokeColor — Задает цвет контура (цвет линий формы).
fillColor — задает цвет внутренности формы.

С первым свойством все понятно, со вторым небольшая загвоздка.
Как наверно вы успели заметить, на изображение 5 фигур — объектов но почему же на сцене пишется 10 nodes? Дело в том, что свойство fillColor наша сцена считает тоже за объект, и поэтому она отображает 10 nodes, если вы обратите внимание я каждой фигуре задала это свойство. Его можно и не задавать, тогда число объектов уменьшится.

После того, как мы настроили свойство цвета, мы задаем имя и после добавляем наш объект на нашу сцену.


Quad
Objective-c
//Создаем наш SKShapeNode и инициализируем его. В качестве параметра передаем координаты и размер прямоугольника (CGRectMake).
    SKShapeNode *Quad = [SKShapeNode shapeNodeWithRect:CGRectMake(0, 0, 50, 50)];
    Quad.position = CGPointMake(100, 200); // задаем позицию.
    Quad.lineWidth = 4; // задаем ширину линий.
    Quad.strokeColor = [SKColor whiteColor]; // задаем цвет контура.
    Quad.fillColor = [SKColor blackColor]; // задаем цвет внутренности.
    Quad.name = @"Quad"; // задаем имя.
    [self addChild:Quad]; // добавляем наш объект на нашу сцену.

Swift
// Создаем переменную Quad и ей присваиваем объект типа SKShapeNode. 
         // В качестве параметра передаем координаты и размер прямоугольника (CGRectMake).
        var Quad = SKShapeNode(rect: CGRectMake(0, 0, 50, 50))
        Quad.position = CGPointMake(100, 200) // задаем позицию.
        Quad.lineWidth = 4 // задаем размер линий.
        Quad.strokeColor = SKColor.whiteColor() // задаем цвет контура.
        Quad.fillColor = SKColor.blackColor() // задаем цвет внутренности.
        Quad.name = "Quad" // задаем имя.
        self.addChild(Quad) // добавляем наш объект на нашу сцену.

Дальше у нас идет Спрайт с именем Quad, тут почти тоже самое, что и в предыдущим случае. Только при инициализации, мы передаем в качестве параметра функцию (CGRectMake).
CGRectMake(0, 0, 50, 50)

Я думаю большинство из вас знакомы с ней, если нет, то знайте: она возвращает координаты и размер прямоугольника.
Первые два параметра это: x — Позиция относительно оси X, y — Позиция относительно оси Y.
Остальные два это Ширина и Длина.


Ellips
Objective-c
// Создаем наш SKShapeNode и инициализируем его. В качестве параметра передаем координаты и размер прямоугольника (CGRectMake).
     // В данном случае форма эллипса будет создана внутри прямоугольника в соответствии с его размерами.
    SKShapeNode *Ellips = [SKShapeNode shapeNodeWithEllipseInRect:CGRectMake(0, 0, 50, 90)];
    Ellips.position = CGPointMake(200, 200); // задаем позицию.
    Ellips.lineWidth = 2; // задаем ширину линий.
    Ellips.strokeColor = [SKColor greenColor]; // задаем цвет контура.
    Ellips.fillColor = [SKColor purpleColor]; // задаем цвет внутренности.
    Ellips.glowWidth = 5; // задаем эффект свечение контура.
    Ellips.name = @"Ellips"; // задаем имя.
    [self addChild:Ellips]; // добавляем наш объект на нашу сцену.

Swift
// Создаем переменную Ellips и ей присваиваем объект типа SKShapeNode.
        // В данном случае форма эллипса будет создана внутри прямоугольника в соответствии с его размерами.
        var Ellips = SKShapeNode(ellipseInRect: CGRectMake(0, 0, 50, 90))
        Ellips.position = CGPointMake(200, 200) // задаем позицию.
        Ellips.lineWidth = 2 // задаем размер линий.
        Ellips.strokeColor = SKColor.greenColor() // задаем цвет контура.
        Ellips.fillColor = SKColor.purpleColor() // задаем цвет внутренности.
        Ellips.glowWidth = 5 // задаем эффект свечение контура.
        Ellips.name = "Ellips" // задаем имя.
        self.addChild(Ellips) // добавляем наш объект на нашу сцену.

Далее у нас идет объект с именем Ellips, это тоже объект из первой группы его форма уже задана и нам остается только передать параметр и этот объект будет инициализирован. Он из себя представляет эллипс, который вы можете увидеть на изображение выше. Он создается с помощь передачи параметра методу shapeNodeWithEllipseInRect или функции ellipseInRect. В качестве параметра мы передаем функцию (CGRectMake) которая возвращает координаты и размер прямоугольника, в соответствие с этими свойствами внутри этого прямоугольника и создается Эллипс.
У этого объекта есть еще одно интересное свойство, которое я добавила, это glowWidth

glowWidth — Это свойство определяет свечение контура, чем выше число, тем сильнее свечение.


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


Инициализация с помощью объекта UIBezierPath


Ко второй группе относятся объекты у которых инициализация проходит с помощью объекта UIBezierPath.
Что это значит? До сих пор мы рассматривали объекты, формы которых были известны и нам оставалось только передать параметр, но что если нам захочется например создать треугольник? Там нет такого метода инициализации! Для таких случаев нам и нужен объект типа UIBezierPath.
С помощью этого объекта, можно создать любую форму, а затем передать ее нашему SKShapeNode который после и отобразит ее.

RoundedRect
Objective-c
// Создаем и инициализируем объект типа UIBezierPath. В качестве параметра передаем координаты и размер прямоугольника (CGRectMake),
    // а также радиус округление углов.
    UIBezierPath *RoundedRectPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 50, 50) cornerRadius:12];

    // Создаем наш SKShapeNode и инициализируем его. В качестве параметра передаем объект созданный нами выше и булева значение.
    // обратите внимание на то, что к объекту передаваемому в первом параметре добавляется свойство CGPath.
    SKShapeNode *RoundedRect = [ SKShapeNode shapeNodeWithPath:RoundedRectPath.CGPath centered:YES];
    RoundedRect.position = CGPointMake(50, 100); // задаем позицию.
    RoundedRect.lineWidth = 2;  // задаем ширину линий.
    RoundedRect.strokeColor = [SKColor blueColor]; // задаем цвет контура.
    RoundedRect.fillColor = [SKColor redColor]; // задаем цвет внутренности.
    RoundedRect.name = @"RoundedRect"; // задаем имя.
    [self addChild:RoundedRect]; // добавляем наш объект на нашу сцену.

Swift
// Создаем переменную RoundedRectPath и ей присваиваем объект типа UIBezierPath.
        // В качестве параметра передаем координаты и размер прямоугольника (CGRectMake),  а также радиус округление углов.
        var RoundedRectPath = UIBezierPath(roundedRect: CGRectMake(0, 0, 50, 50), cornerRadius: 12)
        
         // Создаем переменную RoundedRect и ей присваиваем объект типа SKShapeNode. 
        // В качестве параметра передаем объект созданный нами выше и булева значение.
       // обратите внимание на то, что к объекту передаваемому в первом параметре добавляется свойство CGPath.
        var RoundedRect = SKShapeNode(path: RoundedRectPath.CGPath, centered:true)
        RoundedRect.position = CGPointMake(50, 100) // задаем позицию.
        RoundedRect.lineWidth = 2 // задаем размер линий.
        RoundedRect.strokeColor = SKColor.blueColor() // задаем цвет контура.
        RoundedRect.fillColor = SKColor.redColor() // задаем цвет внутренности.
        RoundedRect.name = "RoundedRect" // задаем имя.
        self.addChild(RoundedRect) // добавляем наш объект на нашу сцену.


Итак, давайте рассмотрим создание объекта с именем RoundedRect.
Перед его созданием, мы создаем объект типа UIBezierPath, в качестве параметра инициализации мы передаем:
функцию (CGRectMake) и радиус угла. Это нужно, чтобы создать прямоугольник (квадрат) с закругленными углами.

После того как наш UIBezierPath объект готов, теперь мы можем создать наш SKShapeNode, что мы дальше и делаем.
Мы создаем его и в качестве параметра инициализации передаем наш объект UIBezierPath, и еще один параметр centered.
Тут обратите внимание, что при передаче нашего объекта к нему добавляется свойство CGPath, это нужно для того чтобы создать мост между объектами; не ломайте над этим голову, просто знайте что его нужно добавлять!
Кроме того, здесь есть еще один параметр — это centered зачем он нужен, я объясню чуть ниже!
Итак, остальные свойство вы наверно уже поняли и без объяснений. Если да, тогда давайте перейдем к следующему объекту.



Triangle
Objective-c

    UIBezierPath *TrianglePath = [UIBezierPath bezierPath];  // Создаем и инициализируем объект типа UIBezierPath.
    [TrianglePath moveToPoint:CGPointMake(0, 0)]; // переходим на точку с заданными координатами.
    [TrianglePath addLineToPoint:CGPointMake(-25, -50)]; // добавляем линию к заданной точке.
    [TrianglePath addLineToPoint:CGPointMake(25, -50)]; // добавляем линию к заданной точке.
    [TrianglePath addLineToPoint:CGPointMake(0, 0)]; // добавляем линию к заданной точке.
   
    // Создаем наш SKShapeNode и инициализируем его. В качестве параметра передаем объект созданный нами выше и булева значение.
    // обратите внимание на то, что к объекту передаваемому в первом параметре добавляется свойство CGPath.
    SKShapeNode *Triangle = [SKShapeNode shapeNodeWithPath:TrianglePath.CGPath centered:YES];
    Triangle.position = CGPointMake(200, 70); // задаем позицию.
    Triangle.lineWidth = 2; // задаем ширину линий.
    Triangle.strokeColor = [SKColor blackColor]; // задаем цвет контура.
    Triangle.fillColor = [SKColor blueColor]; // задаем цвет внутренности.
    Triangle.name = @"Triangle"; // задаем имя.
    [self addChild:Triangle]; // добавляем наш объект на нашу сцену.

Swift

        var TrianglePath = UIBezierPath() // Создаем и инициализируем объект типа UIBezierPath.
        TrianglePath.moveToPoint(CGPointMake(0, 0)) // переходим на точку с заданными координатами.
        TrianglePath.addLineToPoint(CGPointMake(-25, -50)) // добавляем линию к заданной точке.
        TrianglePath.addLineToPoint(CGPointMake(25, -50)) // добавляем линию к заданной точке.
        TrianglePath.addLineToPoint(CGPointMake(0, 0)) // добавляем линию к заданной точке.
        
         // Создаем переменную Triangle и ей присваиваем объект типа SKShapeNode. 
        // В качестве параметра передаем объект созданный нами выше и булева значение.
       // обратите внимание на то, что к объекту передаваемому в первом параметре добавляется свойство CGPath.
        var Triangle = SKShapeNode(path: TrianglePath.CGPath, centered: true)
        Triangle.position = CGPointMake(200, 70) // задаем позицию.
        Triangle.lineWidth = 2 // задаем размер линий.
        Triangle.strokeColor = SKColor.blackColor() // задаем цвет контура.
        Triangle.fillColor = SKColor.blueColor() // задаем цвет внутренности.
        Triangle.name = "Triangle" // задаем имя.
        self.addChild(Triangle) // добавляем наш объект на нашу сцену.


Следующий объект имеет имя Triangle. Этот объект тоже использует объект типа UIBezierPath в качестве инициализации. Давайте разберем его по подробней. Итак, как и в предыдущем случае мы сначала должны создать объект типа UIBezierPath, как мы видим из кода он имеет имя TrianglePath.
Вначале мы его просто инициализируем, без каких либо параметров. А дальше начинается самое интересное! Для того, что бы создать треугольник, нам сначала нужно определить его начальную точку, что мы и делаем. Мы вызываем метод или функцию moveToPoint объекта UIBezierPath. После того как мы определили начальную точку (вершину), мы от нее рисуем линию вниз влево, это можно увидеть по координатам точек, линии добавляются при вызове метода или функции addLineToPoint. После того, как мы добавили первую линию, мы создаем еще одну, но вправо и после еще одну к вершине (начальной точке). И все наш треугольник готов. Теперь нам осталось передать наш объект с именем TrianglePath. Для этого мы создаем объект типа SKShapeNode с именем Triangle и как в предыдущий раз передаем его как параметр, и «вуаля» наш треугольник готов!




В интернете полно информации об объекте типа UIBezierPath, советую найти и почитать!


Я обещала объяснить для чего нужен параметр centered. Я не сделала этого раньше, только для того, чтобы вы поняли базовое строение объектов типа SKShapeNode. Так вот, параметр centered, если он принимает Положительное значение, тогда позиция объекта типа SKShapeNode будет считаться с середины. Помните, когда я вам объясняла про позицию объектов типа SKSpriteNode, я вам сказала, что их позиция отсчитывается с середины. Так вот, если параметр centered положителен, то и позиция данного объекта будет рассчитываться с середины.

Отсюда возникает вполне уместный вопрос, как тогда рассчитывается позиция простых объектов типа SKShapeNode, ведь не каждый же объект создается с параметром инициализации centered?



Давайте возьмем в качестве примера объект, который мы рассматривали раньше с именем Quad. Мы рассмотрели его инициализацию, которая начинается с передачи в качестве параметра функции с именем (CGRectMake). Как я уже писала раньше эта функция возвращает позицию и размер.

CGRectMake(0, 0, 50, 50).

В ней первые два параметра определяют ее origin позицию (x, y), а остальные ширину и длину соответственно.
Если с шириной и длиной понятно, то с origin немного мутно. Дело в том, что объекты типа SKShapeNode используют систему исчисление позиции немного иначе, чем объекты типа SKSpriteNode у которых отсчет позиции начинается с середины. Давайте посмотрим на изображение выше: итак, при инициализации нашего объекта с именем Quad мы передали ему в качестве параметра функцию CGRectMake(0, 0, 50, 50). Как мы видим на изображении origin равен (0, 0) из изображение видно что отсчет позиции начинается с верхнего левого угла.
Теперь давайте изменим наш origin и передадим нашу прежнею функцию, но уже с другими координатами.

CGRectMake(-25, -25, 50, 50).




И что мы видим? Наш квадрат при инициализации имеет начальную точку отсчета позиции с середины.
Другими словами, наш объект теперь имеет такую же систему отсчета, как и объекты SKSpriteNode, у которых отсчет позиции начинается с середины.

• Выходит то, что origin играет роль якоря немного похожего на тот, что мы видели раньше у объектов типа SKSpriteNode.

У вас может возникнуть вопрос, почему координаты origin я указала равными (-25, -25)?

• Дело в том, что размер нашего квадрата равен (50, 50), а это значит, что его средняя точка равна (50/2, 50/2), то есть половина ширины и длины!

На первом изображении мы видим, что у объектов типа SKShapeNode начальная точка равна (0, 0), поэтому его позиция определяется с верхнего левого угла,
но если мы сдвинем его на (-25, -25), то его начальная точка станет посередине и отсчет позиции будет начинаться по середине.

• Теперь если скажут, что мы сдвинули такой то спрайт на 100px, это значит мы сдвинули его среднюю точку на 100px.

Ну что же, я думаю вам понравился SKShapeNode. Как видите в нем нет ничего трудного, но если вы не поняли какие-то моменты, то это не страшно, далее во время демонстрации физики вы все поймете. Небольшой совет: что бы лучше понять этот Спрайт -объект, изучите получше UIBezierPath и все время практикуйтесь!

Objective-c
Objective-c

#import "GameScene.h"

@implementation GameScene


-(void)didMoveToView:(SKView *)view
{
    [self SceneSetting];
    //[self SKSpriteNodeDemo];
    [self SKShapeNodeDemo];
    
}


-(void)SceneSetting
{
    
  self.backgroundColor = [SKColor orangeColor];
    
}

-(void)SKSpriteNodeDemo
{
    
    SKTexture *Texture = [SKTexture textureWithImageNamed:@"desert_BG"];
    
    
    SKSpriteNode *BackgroundSprite = [SKSpriteNode spriteNodeWithTexture:Texture];
    BackgroundSprite.size = CGSizeMake(640, 320);
    BackgroundSprite.position = CGPointMake(0, 0);
    BackgroundSprite.anchorPoint = CGPointMake(0, 0);
    BackgroundSprite.name = @"BackgroundSprite";
    [self addChild:BackgroundSprite];
    
    
    
    SKSpriteNode *SimpleSprite = [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:CGSizeMake(50, 50)];
    SimpleSprite.position = CGPointMake(200, 150);
    SimpleSprite.zPosition = 1;
    SimpleSprite.name = @"SimpleSprite";
    [self addChild:SimpleSprite];

    
    SKSpriteNode *ImageSprite = [SKSpriteNode spriteNodeWithImageNamed:@"DerevoOpora"];
    ImageSprite.position = CGPointMake(250, 50);
    ImageSprite.size = CGSizeMake(100, 15);
    ImageSprite.name = @"ImageSprite";
    [self addChild:ImageSprite];
    
}


-(void)SKShapeNodeDemo
{
    SKShapeNode *Circle = [SKShapeNode shapeNodeWithCircleOfRadius:20];
    Circle.position = CGPointMake(50, 200);
    Circle.lineWidth = 10;
    Circle.strokeColor = [SKColor blueColor];
    Circle.fillColor = [SKColor redColor];
    Circle.name = @"Circle";
    [self addChild:Circle];
    
    SKShapeNode *Quad = [SKShapeNode shapeNodeWithRect:CGRectMake(0, 0, 50, 50)];
    Quad.position = CGPointMake(100, 200);
    Quad.lineWidth = 4;
    Quad.strokeColor = [SKColor whiteColor];
    Quad.fillColor = [SKColor blackColor];
    Quad.name = @"Quad";
    [self addChild:Quad];
    
    
    SKShapeNode *Ellips = [SKShapeNode shapeNodeWithEllipseInRect:CGRectMake(0, 0, 50, 90)];
    Ellips.position = CGPointMake(200, 200);
    Ellips.lineWidth = 2;
    Ellips.strokeColor = [SKColor greenColor];
    Ellips.fillColor = [SKColor purpleColor];
    Ellips.glowWidth = 5;
    Ellips.name = @"Ellips";
    [self addChild:Ellips];
    
    
    
    
    UIBezierPath *RoundedRectPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 50, 50) cornerRadius:12];
    
    SKShapeNode *RoundedRect = [ SKShapeNode shapeNodeWithPath:RoundedRectPath.CGPath centered:YES];
    RoundedRect.position = CGPointMake(50, 100);
    RoundedRect.lineWidth = 2;
    RoundedRect.strokeColor = [SKColor blueColor];
    RoundedRect.fillColor = [SKColor redColor];
    RoundedRect.name = @"RoundedRect";
    [self addChild:RoundedRect];
    
    
    
    UIBezierPath *TrianglePath = [UIBezierPath bezierPath];
    [TrianglePath moveToPoint:CGPointMake(0, 0)];
    [TrianglePath addLineToPoint:CGPointMake(-25, -50)];
    [TrianglePath addLineToPoint:CGPointMake(25, -50)];
    [TrianglePath addLineToPoint:CGPointMake(0, 0)];
   
    
    SKShapeNode *Triangle = [SKShapeNode shapeNodeWithPath:TrianglePath.CGPath centered:YES];
    Triangle.position = CGPointMake(200, 70);
    Triangle.lineWidth = 2;
    Triangle.strokeColor = [SKColor blackColor];
    Triangle.fillColor = [SKColor blueColor];
    Triangle.name = @"Triangle";
    [self addChild:Triangle];
    
    
}

@end



Swift
Swift

import SpriteKit


class GameScene: SKScene
{
    override func didMoveToView(view: SKView)
    {
        SceneSetting()
        //SKSpriteNodeDemo()
        SKShapeNodeDemo()
        
    }
    
    
    func SceneSetting()
    {
        self.backgroundColor = SKColor.orangeColor()
    
    }
    
   
    
    
    func SKSpriteNodeDemo()
    {
        
        var Texture = SKTexture(imageNamed: "desert_BG")
        
        var BackgroundSprite = SKSpriteNode(texture: Texture)
        BackgroundSprite.size = CGSizeMake(640, 320)
        BackgroundSprite.position = CGPointMake(0, 0)
        BackgroundSprite.anchorPoint = CGPointMake(0, 0)
        BackgroundSprite.name = "BackgroundSprite"
        self.addChild(BackgroundSprite)
        
        
        var SimpleSprite = SKSpriteNode(color: UIColor.blueColor(), size: CGSizeMake(50, 50))
        SimpleSprite.position = CGPointMake(200, 150)
        SimpleSprite.zPosition = 1;
        SimpleSprite.name = "SimpleSprite"
        self.addChild(SimpleSprite)
        
        
        var ImageSprite = SKSpriteNode(imageNamed: "DerevoOpora")
        ImageSprite.position = CGPointMake(250, 50)
        ImageSprite.size = CGSizeMake(100, 15)
        ImageSprite.name = "ImageSprite"
        self.addChild(ImageSprite)
        
        
    }
    
    
    func SKShapeNodeDemo()
    {
        
        var Circle = SKShapeNode(circleOfRadius: 20)
        Circle.position = CGPointMake(50, 200)
        Circle.lineWidth = 10
        Circle.strokeColor = SKColor.blueColor()
        Circle.fillColor = SKColor.redColor()
        Circle.name = "Circle"
        self.addChild(Circle)
        
        
        var Quad = SKShapeNode(rect: CGRectMake(0, 0, 50, 50))
        Quad.position = CGPointMake(100, 200)
        Quad.lineWidth = 4
        Quad.strokeColor = SKColor.whiteColor()
        Quad.fillColor = SKColor.blackColor()
        Quad.name = "Quad"
        self.addChild(Quad)
        
        
        var Ellips = SKShapeNode(ellipseInRect: CGRectMake(0, 0, 50, 90))
        Ellips.position = CGPointMake(200, 200)
        Ellips.lineWidth = 2
        Ellips.strokeColor = SKColor.greenColor()
        Ellips.fillColor = SKColor.purpleColor()
        Ellips.glowWidth = 5
        Ellips.name = "Ellips"
        self.addChild(Ellips)
        
        
        var RoundedRectPath = UIBezierPath(roundedRect: CGRectMake(0, 0, 50, 50), cornerRadius: 12)
        
        var RoundedRect = SKShapeNode(path: RoundedRectPath.CGPath, centered:true)
        RoundedRect.position = CGPointMake(50, 100)
        RoundedRect.lineWidth = 2
        RoundedRect.strokeColor = SKColor.blueColor()
        RoundedRect.fillColor = SKColor.redColor()
        RoundedRect.name = "RoundedRect"
        self.addChild(RoundedRect)
        
        
        
        
        
        var TrianglePath = UIBezierPath()
        TrianglePath.moveToPoint(CGPointMake(0, 0))
        TrianglePath.addLineToPoint(CGPointMake(-25, -50))
        TrianglePath.addLineToPoint(CGPointMake(25, -50))
        TrianglePath.addLineToPoint(CGPointMake(0, 0))
        
        
        var Triangle = SKShapeNode(path: TrianglePath.CGPath, centered: true)
        Triangle.position = CGPointMake(200, 70)
        Triangle.lineWidth = 2
        Triangle.strokeColor = SKColor.blackColor()
        Triangle.fillColor = SKColor.blueColor()
        Triangle.name = "Triangle"
        self.addChild(Triangle)
        
        
        
    }
    
    
}





SKLabelNode




SKLabelNode — Это Спрайт, который позволяет выводить текст на нашей сцене. Причем текст можно выводить с параметрами:
Размер шрифта, цвет шрифта, имя шрифта.
Настраивать выравнивание шрифта как по вертикали, так и по горизонтали. Впрочем вы сейчас все увидите сами.




Objective-c
Objective C
-(void)SKLabelNodeDemo
{
    // Создаем наш SKLabelNode и инициализируем его. В качестве параметра передаем имя шрифта.
    SKLabelNode *First = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
    First.position = CGPointMake(280, 200); // задаем позицию.
    First.fontSize = 25; // задаем размер шрифта.
    First.fontColor = [SKColor whiteColor]; // задаем цвет шрифта.
    First.color = [SKColor blueColor]; // задаем цвет (Нужен для сочетание с colorBlendFactor).
    First.colorBlendFactor = 0.5; // задаем colorBlendFactor (0.0 - 1.0)
    First.text = @"Habra Habr!"; // задаем текст.
    First.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeCenter; // задаем способ выравнивание текста.
    First.name = @"First"; // задаем имя спрайта
    [self addChild:First]; // добавляем наш спрайт на нашу сцену.
    
    
    // Создаем наш SKLabelNode и инициализируем его. В качестве параметра передаем текст.
    SKLabelNode *Second = [SKLabelNode labelNodeWithText:@"Романов-Кошкин-Захарьин-Голштейн-Готторпский"];
    Second.fontName = @"Chalkboard SE Bold"; // задаем имя шрифта.
    Second.fontColor = [SKColor blackColor]; // задаем цвет шрифта.
    Second.position = CGPointMake(280, 50); // задаем позицию.
    Second.fontSize = 20;  // задаем размер шрифта.
    Second.name = @"Second"; // задаем имя спрайта
    [self addChild:Second]; // добавляем наш спрайт на нашу сцену.
    
    
    
}



Swift
Swift
func SKLabelNodeDemo()
    {
        // Создаем переменную First и ей присваиваем объект типа SKLabelNode. В качестве параметра передаем имя шрифта.
        var First = SKLabelNode(fontNamed: "Chalkduster")
        First.position = CGPointMake(280, 200)  // задаем позицию.
        First.fontSize = 25; // задаем размер шрифта.
        First.fontColor = SKColor.whiteColor() // задаем цвет шрифта.
        First.color = SKColor.blueColor() // задаем цвет (Нужен для сочетание с colorBlendFactor).
        First.colorBlendFactor = 0.5 // задаем colorBlendFactor (0.0 - 1.0)
        First.text = "Habra Habr!" // задаем текст.
        First.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Center  // задаем способ выравнивание текста.
        First.name = "First" // задаем имя спрайта
        self.addChild(First) // добавляем наш спрайт на нашу сцену.
        
        
        // Создаем переменную Second и ей присваиваем объект типа SKLabelNode. В качестве параметра передаем текст.
        var Second = SKLabelNode(text: "Романов-Кошкин-Захарьин-Голштейн-Готторпский")
        Second.fontName = "Chalkboard SE Bold"  // задаем имя шрифта.
        Second.fontColor = SKColor.blackColor() // задаем цвет шрифта.
        Second.position = CGPointMake(280, 50) // задаем позицию.
        Second.fontSize = 20 // задаем размер шрифта.
        Second.name = "Second" // задаем имя спрайта
        self.addChild(Second) // добавляем наш спрайт на нашу сцену.
        
        
        
    }

На изображении выше мы видим 2 спрайта. Давайте для начала разберем их способы создания.

Первый Спрайт с именем First. При его инициализации, в качестве параметра мы передаем имя Шрифта. Спрайт типа SKLabelNode поддерживает почти все основные шрифты. В данном случае я передаю шрифт с именем Chalkduster. Далее мы настраиваем все основные свойства:
fontSize — Задает размер шрифта. Любое положительное число.
fontColor — Задает цвет шрифта.
color — задаем цвет (Нужен для сочетание с colorBlendFactor).
colorBlendFactor — Смешивает цвет шрифта. Он берет свойство color и смешивает цвета. Интенсивность смеси зависит от числа в пределах (0.0 — 1.0).
text — Задает текст который мы хотим отобразить.
horizontalAlignmentMode — Задает выравнивание текста по горизонтали. Есть похожее свойство, которое задает выравнивание по вертикали.

После настройки этих свойств, мы добавляем наш объект на нашу сцену. Результат вы можете увидеть на изображении выше.

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

Objective-c
Objective-c

#import "GameScene.h"

@implementation GameScene


-(void)didMoveToView:(SKView *)view
{
      [self SceneSetting];
    //[self SKSpriteNodeDemo];
    //[self SKShapeNodeDemo];
      [self SKLabelNodeDemo];

    
}


-(void)SceneSetting
{
    
  self.backgroundColor = [SKColor orangeColor];
   
}




-(void)SKSpriteNodeDemo
{
    
    SKTexture *Texture = [SKTexture textureWithImageNamed:@"desert_BG"];
    
    
    SKSpriteNode *BackgroundSprite = [SKSpriteNode spriteNodeWithTexture:Texture];
    BackgroundSprite.size = CGSizeMake(640, 320);
    BackgroundSprite.position = CGPointMake(0, 0);
    BackgroundSprite.anchorPoint = CGPointMake(0, 0);
    BackgroundSprite.name = @"BackgroundSprite";
    [self addChild:BackgroundSprite];
    
    
    
    SKSpriteNode *SimpleSprite = [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:CGSizeMake(50, 50)];
    SimpleSprite.position = CGPointMake(200, 150);
    SimpleSprite.zPosition = 1;
    SimpleSprite.name = @"SimpleSprite";
    [self addChild:SimpleSprite];

    
    SKSpriteNode *ImageSprite = [SKSpriteNode spriteNodeWithImageNamed:@"DerevoOpora"];
    ImageSprite.position = CGPointMake(250, 50);
    ImageSprite.size = CGSizeMake(100, 15);
    ImageSprite.name = @"ImageSprite";
    [self addChild:ImageSprite];
    
}


-(void)SKShapeNodeDemo
{
    SKShapeNode *Circle = [SKShapeNode shapeNodeWithCircleOfRadius:20];
    Circle.position = CGPointMake(50, 200);
    Circle.lineWidth = 10;
    Circle.strokeColor = [SKColor blueColor];
    Circle.fillColor = [SKColor redColor];
    Circle.name = @"Circle";
    [self addChild:Circle];
    
    SKShapeNode *Quad = [SKShapeNode shapeNodeWithRect:CGRectMake(0, 0, 50, 50)];
    Quad.position = CGPointMake(100, 200);
    Quad.lineWidth = 4;
    Quad.strokeColor = [SKColor whiteColor];
    Quad.fillColor = [SKColor blackColor];
    Quad.name = @"Quad";
    [self addChild:Quad];
    
    
    
    SKShapeNode *Ellips = [SKShapeNode shapeNodeWithEllipseInRect:CGRectMake(0, 0, 50, 90)];
    Ellips.position = CGPointMake(200, 200);
    Ellips.lineWidth = 2;
    Ellips.strokeColor = [SKColor greenColor];
    Ellips.fillColor = [SKColor purpleColor];
    Ellips.glowWidth = 5;
    Ellips.name = @"Ellips";
    [self addChild:Ellips];
    
    
    
    
    UIBezierPath *RoundedRectPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 50, 50) cornerRadius:12];
    
    SKShapeNode *RoundedRect = [ SKShapeNode shapeNodeWithPath:RoundedRectPath.CGPath centered:YES];
    RoundedRect.position = CGPointMake(50, 100);
    RoundedRect.lineWidth = 2;
    RoundedRect.strokeColor = [SKColor blueColor];
    RoundedRect.fillColor = [SKColor redColor];
    RoundedRect.name = @"RoundedRect";
    [self addChild:RoundedRect];
    
    
    
    
   
    
    
    UIBezierPath *TrianglePath = [UIBezierPath bezierPath];
    [TrianglePath moveToPoint:CGPointMake(0,0)];
    [TrianglePath addLineToPoint:CGPointMake(-25, -50)];
    [TrianglePath addLineToPoint:CGPointMake(25, -50)];
    [TrianglePath addLineToPoint:CGPointMake(0, 0)];
    
    SKShapeNode *Triangle = [SKShapeNode shapeNodeWithPath:TrianglePath.CGPath centered:YES];
    Triangle.position = CGPointMake(200, 70);
    Triangle.lineWidth = 2;
    Triangle.strokeColor = [SKColor blackColor];
    Triangle.fillColor = [SKColor blueColor];
    Triangle.name = @"Triangle";
    [self addChild:Triangle];
    
    
}


-(void)SKLabelNodeDemo
{
    SKLabelNode *First = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
    First.position = CGPointMake(280, 200);
    First.fontSize = 25;
    First.fontColor = [SKColor whiteColor];
    First.color = [SKColor blueColor];
    First.colorBlendFactor = 0.5;
    First.text = @"Habra Habr!";
    First.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeCenter;
    [self addChild:First];
    
    
    
    SKLabelNode *Second = [SKLabelNode labelNodeWithText:@"Романов-Кошкин-Захарьин-Голштейн-Готторпский"];
    Second.fontName = @"Chalkboard SE Bold";
    Second.fontColor = [SKColor blackColor];
    Second.position = CGPointMake(280, 50);
    Second.fontSize = 20;
    [self addChild:Second];
    
    
    
}

@end



Swift
Swift

import SpriteKit


class GameScene: SKScene
{
    override func didMoveToView(view: SKView)
    {
        SceneSetting()
        //SKSpriteNodeDemo()
        //SKShapeNodeDemo()
         SKLabelNodeDemo()
    }
    
    
    func SceneSetting()
    {
        self.backgroundColor = SKColor.orangeColor()
    
    }
    
   
    
    
    func SKSpriteNodeDemo()
    {
        
        var Texture = SKTexture(imageNamed: "desert_BG")
        
        var BackgroundSprite = SKSpriteNode(texture: Texture)
        BackgroundSprite.size = CGSizeMake(640, 320)
        BackgroundSprite.position = CGPointMake(0, 0)
        BackgroundSprite.anchorPoint = CGPointMake(0, 0)
        BackgroundSprite.name = "BackgroundSprite"
        self.addChild(BackgroundSprite)
        
        
        var SimpleSprite = SKSpriteNode(color: UIColor.blueColor(), size: CGSizeMake(50, 50))
        SimpleSprite.position = CGPointMake(200, 150)
        SimpleSprite.zPosition = 1;
        SimpleSprite.name = "SimpleSprite"
        self.addChild(SimpleSprite)
        
        
        var ImageSprite = SKSpriteNode(imageNamed: "DerevoOpora")
        ImageSprite.position = CGPointMake(250, 50)
        ImageSprite.size = CGSizeMake(100, 15)
        ImageSprite.name = "ImageSprite"
        self.addChild(ImageSprite)
        
        
    }
    
    
    func SKShapeNodeDemo()
    {
        
        var Circle = SKShapeNode(circleOfRadius: 20)
        Circle.position = CGPointMake(50, 200)
        Circle.lineWidth = 10
        Circle.strokeColor = SKColor.blueColor()
        Circle.fillColor = SKColor.redColor()
        Circle.name = "Circle"
        self.addChild(Circle)
        
        
        var Quad = SKShapeNode(rect: CGRectMake(0, 0, 50, 50))
        Quad.position = CGPointMake(100, 200)
        Quad.lineWidth = 4
        Quad.strokeColor = SKColor.whiteColor()
        Quad.fillColor = SKColor.blackColor()
        Quad.name = "Quad"
        self.addChild(Quad)
        
        
        var Ellips = SKShapeNode(ellipseInRect: CGRectMake(0, 0, 50, 90))
        Ellips.position = CGPointMake(200, 200)
        Ellips.lineWidth = 2
        Ellips.strokeColor = SKColor.greenColor()
        Ellips.fillColor = SKColor.purpleColor()
        Ellips.glowWidth = 5
        Ellips.name = "Ellips"
        self.addChild(Ellips)
        
        
        var RoundedRectPath = UIBezierPath(roundedRect: CGRectMake(0, 0, 50, 50), cornerRadius: 12)
        
        var RoundedRect = SKShapeNode(path: RoundedRectPath.CGPath, centered:true)
        RoundedRect.position = CGPointMake(50, 100)
        RoundedRect.lineWidth = 2
        RoundedRect.strokeColor = SKColor.blueColor()
        RoundedRect.fillColor = SKColor.redColor()
        RoundedRect.name = "RoundedRect"
        self.addChild(RoundedRect)
        
        
        
        
        
        var TrianglePath = UIBezierPath()
        TrianglePath.moveToPoint(CGPointMake(0, 0))
        TrianglePath.addLineToPoint(CGPointMake(-25, -50))
        TrianglePath.addLineToPoint(CGPointMake(25, -50))
        TrianglePath.addLineToPoint(CGPointMake(0, 0))
        
        
        var Triangle = SKShapeNode(path: TrianglePath.CGPath, centered: true)
        Triangle.position = CGPointMake(200, 70)
        Triangle.lineWidth = 2
        Triangle.strokeColor = SKColor.blackColor()
        Triangle.fillColor = SKColor.blueColor()
        Triangle.name = "Triangle"
        self.addChild(Triangle)
        
        
        
    }
    
    
    func SKLabelNodeDemo()
    {
        var First = SKLabelNode(fontNamed: "Chalkduster")
        First.position = CGPointMake(280, 200)
        First.fontSize = 25;
        First.fontColor = SKColor.whiteColor()
        First.color = SKColor.blueColor()
        First.colorBlendFactor = 0.5
        First.text = "Habra Habr!"
        First.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Center
        self.addChild(First)
        
        
        
        var Second = SKLabelNode(text: "Романов-Кошкин-Захарьин-Голштейн-Готторпский")
        Second.fontName = "Chalkboard SE Bold"
        Second.fontColor = SKColor.blackColor()
        Second.position = CGPointMake(280, 50)
        Second.fontSize = 20
        self.addChild(Second)
        
        
        
    }
    
    
}



Как видите SKLabelNode очень прост в использование, я бы даже сказала очень прост!
Друзья Мы изучили 3 основных Спрайта. Теперь пришло время прерваться и посмотреть физику наших тел. Если мы продолжим и дальше изучать виды Спрайтов, я боюсь вы заскучаете, а так вы увидите основные физические свойства в действие, такие как: (Гравитация, Скорость, Трение, Скольжение и остальные).
Ну что начнем?



Физика в действии!




Ну что же друзья! Вот мы и дошли до почти что самой главной части статьи, это — Физика. До этого мы учились создавать объекты — Спрайты. Мы изучили нашу сцену, посмотрели как визуально выглядят наши объекты и это ХОРОШО! Но без физики, это всего навсего изображение! Физика придает «жизнь» нашим Спрайтам и в этой главе я бы хотела по подробнее о ней вам рассказать. И начнем мы с SKPhysicsBody

SKPhysicsBody


SKPhysicsBody — Это по сути тело нашего объекта. Именно оно отвечает за все основные физические характеристики наших объектов, именно оно придает им физическую форму, именно оно отвечает за такие характеристики как: Трение, упругость, сопротивление, массу, скорость, гравитацию.

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

Свойство
1) dynamicЕсли No, то наш объект не может двигаться становится статическим.
2) usesPreciseCollisionDetectionПо умолчанию стоит NO. Если YES, то будет использоваться более точный алгоритм обнаружение столкновение, но при этом будет потреблять больше ресурсов, используйте это свойство если точно знаете, что хотите сделать.
3) allowsRotationПо умолчанию стоит NO. Если YES но наш объект не будет вращаться!
4) pinnedПо умолчанию NO, если YES то тело будет прикреплено к родительскому элементу, оно не сможет двигаться, но сможет вращаться.
5) restingВозвращает YES, если тело находится в покое.
6) frictionОпределяет шероховатость, поверхности тела. Оно используется для вычисления силы трения при контакте с телом.
7) chargeОпределяет электрический заряд. В последствии может быть взаимодействовать с электрическим магнитным полем.
8) restitutionОпределяет сколько энергии теряет тело при столкновением (как сильно отскочит тело, при столкновении)
(принимает значения в пределах 0.1 — 1.0). По умолчанию 0.2.

9) linearDampingИспользуются для расчета имитации силы трения среды при линейном движении.
(принимает значения в пределах 0.1 — 1.0). По умолчанию 0.1.

10) angularDampingИспользуются для расчета имитации силы трения среды при угловом движении.
(принимает значения в пределах 0.1 — 1.0). По умолчанию 0.1.

11) densityОпределяет плотность. По умолчанию 0.1.
12) massОпределяет массу.
13) areaОпределяет площадь.
14) affectedByGravityПо умолчанию YES, если NO то тело будет игнорировать Гравитацию.
15) fieldBitMaskБитовая маска,
16) categoryBitMaskБитовая маска, определяет Категорию.
17) collisionBitMaskБитовая маска, определяет Столкновение.
18) contactTestBitMaskБитовая маска,
19) jointsВозвращает массив всех физических соединений, относящихся к этому телу. (Joint — соединения, об этом чуть позже)
20) nodeВозвращает Node которому принадлежит данное физическое тело.
21) velocityОпределяет линейную скорость.
22) angularVelocityОпределяет угловую скорость.


Методы или функции инициализации
1) bodyWithCircleOfRadius — rСоздать физическое тело с данным радиусом.
2) bodyWithCircleOfRadius — r — centerСоздать физическое тело с данным радиусом, с центром в точке.
3) bodyWithRectangleOfSize — sСоздать физическое тело прямоугольный формы.
4) bodyWithRectangleOfSize — s — centerСоздать физическое тело прямоугольный формы, с центром в точке.
5) bodyWithPolygonFromPath — pathСоздать физическое тело многоугольной формы.
6) bodyWithEdgeFromPoint — p1 — p2Создать физическое тело, линию с начальной и конечной точкой.
7) bodyWithEdgeChainFromPath — pathСоздать физическое тело, цепочку — линий.
8) bodyWithEdgeLoopFromPath — pathСоздать физическое тело, замкнутый объект соединенный линиями.
9) bodyWithEdgeLoopFromRect — rectСоздать физическое тело, замкнутый объект прямоугольной формы соединенный линиями.
10) bodyWithTexture — texture — sizeСоздает физическое тело использую содержимые текстуры.
11) bodyWithTexture — texture — alphaThreshold — sizeСоздает физическое тело использую содержимые текстуры, использую параметр alphaThreshold.
12) bodyWithBodies — bodiesСоздать комбинированное физическое тело состоящие из отдельных тел.


Методы или функции
1) applyForce — forceПрименить силу к центру тяжести этого объекта.
2) applyForce — force — pointПрименить силу к определенной точке данного тела. (Точка — второй параметр)
3) applyTorque — torqueПрименить крутящий момент к данному телу.
4) applyImpulse — impulseПрименить импульс к центру тяжести данного объекта.
5) applyImpulse — impulse — pointПрименить импульс к определенной точке данного тела. (Точка — второй параметр)
6) applyAngularImpulse — impulseПрименить угловой импульс к данному телу.
7) allContactedBodiesВозвращает массив физических тел, находящихся в контакте с данным телом.

Итак, выше вы видите все методы или функции и свойства объекта SKPhysicsBody. Как видите их у него немного.
Сразу скажу, некоторые пункты выше могут вам показаться: непонятными или сложными для понимания. Не волнуйтесь, если чего-то не поняли. Дальше мы все несколько раз рассмотрим и поэкспериментируем со всем несколько раз!

Ладно, давайте продолжим, но перед тем как приступать к реализации, мы должны кое-что сделать!
Давайте найдем наш ViewController и добавим к нашему SKView это свойство:

Objective-c
skView.showsPhysics = YES;

Swift
skView.showsPhysics = true


Оно показывает физическое тело, если таковое существует у объекта. Это очень удобно, мы видим физическое тело и можем легче с ним работать!

Кроме того, нужно еще добавить одну строчку в метод или функцию SceneSetting
Это нужно сделать для того, чтобы настроить силу гравитацию нашей сцены. Как она работает я вам расскажу чуть позже.
Objective-c
 self.physicsWorld.gravity = CGVectorMake(0, -1);

Swift
 self.physicsWorld.gravity = CGVectorMake(0, -1)


Физику тел можно разделить на 3 категории:
1) Динамические — Тела, которые могут изменять свою позицию.
2) Статические — Тела, которые не могут изменять свою позицию.
3) EDGE — Своеобразные границы.

Динамические
Динамические тела лучше всего использовать тогда, когда вы хотите что то двигать на сцене или сталкивать. Это могут быть: снаряды, летательные объекты, все возможные анимированные персонажи. Они имеют массу и объем, они могут быть затронутыми силами гравитации, могут принимать основные физические свойства.

Статические
Статические тела. У них все тоже самое, как и у динамических, главное отличие в том, что они не могут двигаться! Однако с ними по прежнему могут сталкиваться и взаимодействовать другие объекты. Лучше всего их использовать, например для каких то опор или стен. Все то, что занимает много места.

EDGE
EDGE — это по сути не Физическое тело, это некие границы с которыми и происходит все взаимодействие. Они не имеет массы или объема, и не могут двигаться!
EDGE используется для предоставления полой части внутри объекта или для каких-нибудь невидимых границ.



Давайте посмотрим на изображение выше. Мы видим пять объектов. Я специально выбрала разные типы объектов, чтобы вы увидели разницу между ними.
Ну что же, давайте рассмотрим их по подробнее!

Objective-c
Objective-c
-(void)CreatePhysics

{
    //Создаем наш SKShapeNode и инициализируем его. В качестве параметра передаем координаты и размер прямоугольника (CGRectMake).
    SKShapeNode *RectanglePhysics = [SKShapeNode shapeNodeWithRect:CGRectMake(-580/2, -10, 580, 20)];
    RectanglePhysics.position = CGPointMake(280, 40); // Задаем позицию.
    RectanglePhysics.fillColor = [SKColor whiteColor]; // задаем цвет внутренности.
    RectanglePhysics.name = @"Rectangle"; // задаем имя.
    RectanglePhysics.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:RectanglePhysics.frame.size]; // Задаем физическое тело.
    RectanglePhysics.physicsBody.dynamic = NO; // Делаем его Статичным.
    [self addChild:RectanglePhysics]; // добавляем наш объект на нашу сцену.
    
    
    // Создаем наш SKShapeNode и инициализируем его. В качестве параметра передаем радиус.
    SKShapeNode *CirclePhysics = [SKShapeNode shapeNodeWithCircleOfRadius:40];
    CirclePhysics.position = CGPointMake(100, 160); // Задаем позицию.
    CirclePhysics.strokeColor = [SKColor greenColor]; // задаем цвет контура.
    CirclePhysics.lineWidth = 5; // задаем ширину линий.
    CirclePhysics.name = @"Circle"; // задаем имя.
    CirclePhysics.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:40]; // Задаем физическое тело.
    CirclePhysics.physicsBody.dynamic = YES; // Делаем его Динамичным.
    [self addChild:CirclePhysics]; // добавляем наш объект на нашу сцену.
    
    
    
    
    // Создаем объект типа SKTexture и инициализируем его. В качестве параметра передаем имя изображение.
    SKTexture *Texture = [SKTexture textureWithImageNamed:@"DerevoOpora"];

    // Создаем наш SKSpriteNode и инициализируем его. В качестве параметра передаем объект типа SKTexture.
    SKSpriteNode *TexturePhysics = [SKSpriteNode spriteNodeWithTexture:Texture];
    TexturePhysics.position = CGPointMake(200, 180); // Задаем позицию.
    TexturePhysics.size = CGSizeMake(100, 30); // Задаем размер.
    TexturePhysics.name = @"TexturePhysics"; // задаем имя.
    TexturePhysics.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:TexturePhysics.frame.size]; // Задаем физическое тело.
    TexturePhysics.physicsBody.dynamic = YES; // // Делаем его Динамичным.
    [self addChild: TexturePhysics]; // добавляем наш объект на нашу сцену.
    
    
    
    
    UIBezierPath *TrianglePath = [UIBezierPath bezierPath]; // Создаем и инициализируем объект типа UIBezierPath.
    [TrianglePath moveToPoint:CGPointMake(0,0)]; // переходим на точку с заданными координатами.
    [TrianglePath addLineToPoint:CGPointMake(-50, -100)]; //  добавляем линию к заданной точке.
    [TrianglePath addLineToPoint:CGPointMake(50, -100)]; //  добавляем линию к заданной точке.
    [TrianglePath addLineToPoint:CGPointMake(0, 0)]; //  добавляем линию к заданной точке.
    
    
    
    // Создаем наш SKShapeNode и инициализируем его. В качестве параметра передаем объект созданный нами выше.
    // обратите внимание на то, что к объекту передаваемому в  параметре добавляется свойство CGPath.
    SKShapeNode *TrianglePhysics = [SKShapeNode shapeNodeWithPath:TrianglePath.CGPath ];
    TrianglePhysics.position = CGPointMake(400, 190); // задаем позицию.
    TrianglePhysics.lineWidth = 2; // задаем ширину линий.
    TrianglePhysics.strokeColor = [SKColor blackColor]; // задаем цвет контура.
    TrianglePhysics.fillColor = [SKColor blueColor]; //  задаем цвет внутренности.
    TrianglePhysics.name = @"Triangle"; // задаем имя.
    TrianglePhysics.physicsBody = [SKPhysicsBody bodyWithPolygonFromPath:TrianglePath.CGPath]; // Задаем физическое тело.
    TrianglePhysics.physicsBody.dynamic = YES;  // Делаем его Динамичным.
    [self addChild:TrianglePhysics]; // добавляем наш объект на нашу сцену.
    
    
    
    //Создаем наш SKLabelNode и инициализируем его. В качестве параметра передаем текст.
    SKLabelNode *LabelPhysics = [SKLabelNode labelNodeWithText:@"Xcode"]; 
    LabelPhysics.position = CGPointMake(500, 200); // задаем позицию.
    LabelPhysics.fontSize = 22; // задаем размер шрифта.
    LabelPhysics.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:CGRectMake(-25, -25, 50, 50)]; // Задаем физическое тело.
    LabelPhysics.name = @"Label"; // задаем имя спрайта.
    [self addChild:LabelPhysics]; // добавляем наш объект на нашу сцену.
    
    
    
}


Swift
Swift
func CreatePhysics()
    {
        // Создаем переменную RectanglePhysics и ей присваиваем объект типа SKShapeNode. 
        // В качестве параметра передаем координаты и размер прямоугольника (CGRectMake).
        var RectanglePhysics = SKShapeNode(rect: CGRectMake(-580/2, -10, 580, 20))
        RectanglePhysics.position = CGPointMake(280, 40) // задаем позицию.
        RectanglePhysics.fillColor = SKColor.whiteColor() // задаем цвет внутренности.
        RectanglePhysics.name = "Rectangle"  // задаем имя.
        RectanglePhysics.physicsBody = SKPhysicsBody(rectangleOfSize: RectanglePhysics.frame.size) // Задаем физическое тело.
        RectanglePhysics.physicsBody.dynamic = false // Делаем его статичным.
        self.addChild(RectanglePhysics) // добавляем наш объект на нашу сцену.
        
        //Создаем переменную CirclePhysics и ей присваиваем объект типа SKShapeNode.
        // В качестве параметра передаем радиус.
        var CirclePhysics = SKShapeNode(circleOfRadius: 40)
        CirclePhysics.position = CGPointMake(100, 160) // задаем позицию.
        CirclePhysics.strokeColor = SKColor.greenColor() // задаем цвет контура.
        CirclePhysics.lineWidth = 5; // задаем размер линий.
        CirclePhysics.name = "Circle" // задаем имя.
        CirclePhysics.physicsBody = SKPhysicsBody(circleOfRadius: 40) // Задаем физическое тело.
        CirclePhysics.physicsBody.dynamic = true // Делаем его динамичным.
        self.addChild(CirclePhysics) // добавляем наш объект на нашу сцену.
        
        
        
        
        // Создаем переменную Texture и ей присваиваем объект типа SKTexture. В качестве параметра передаем имя нашего изображение
        let Texture = SKTexture(imageNamed: "DerevoOpora")
        
        // Создаем переменную TexturePhysics и ей присваиваем объект типа SKSpriteNode. 
       // В качестве параметра передаем объект типа SKTexture созданный нами  выше.
        var TexturePhysics = SKSpriteNode(texture: Texture)
        TexturePhysics.position = CGPointMake(200, 180) // задаем позицию.
        TexturePhysics.size = CGSizeMake(100, 30) // Задаем размер.
        TexturePhysics.name = "TexturePhysics" // задаем имя.
        TexturePhysics.physicsBody = SKPhysicsBody(rectangleOfSize: TexturePhysics.frame.size) // Задаем физическое тело.
        TexturePhysics.physicsBody.dynamic = true // Делаем его динамичным.
        self.addChild(TexturePhysics) // добавляем наш объект на нашу сцену.
        
        
        
        var TrianglePath = UIBezierPath() // Создаем и инициализируем объект типа UIBezierPath.
        TrianglePath.moveToPoint(CGPointMake(0, 0)) // переходим на точку с заданными координатами.
        TrianglePath.addLineToPoint(CGPointMake(-50, -100)) // добавляем линию к заданной точке.
        TrianglePath.addLineToPoint(CGPointMake(50, -100)) // добавляем линию к заданной точке.
        TrianglePath.addLineToPoint(CGPointMake(0, 0)) // добавляем линию к заданной точке.
        
        // Создаем переменную TrianglePhysics и ей присваиваем объект типа SKShapeNode.
       // В качестве параметра передаем объект созданный нами выше
      // обратите внимание на то, что к объекту передаваемому в первом параметре добавляется свойство CGPath.
        var TrianglePhysics = SKShapeNode(path: TrianglePath.CGPath)
        TrianglePhysics.position = CGPointMake(400, 190) // задаем позицию.
        TrianglePhysics.lineWidth = 2 // задаем размер линий.
        TrianglePhysics.strokeColor = SKColor.blackColor() // задаем цвет контура.
        TrianglePhysics.fillColor = SKColor.blueColor() // задаем цвет внутренности.
        TrianglePhysics.name = "Triangle" // задаем имя.
        TrianglePhysics.physicsBody = SKPhysicsBody(polygonFromPath: TrianglePath.CGPath) // Задаем физическое тело.
        TrianglePhysics.physicsBody.dynamic = true // Делаем его динамичным.
        self.addChild(TrianglePhysics) // добавляем наш объект на нашу сцену.
        
        // Создаем переменную LabelPhysics и ей присваиваем объект типа SKLabelNode. В качестве параметра передаем текст.
        var LabelPhysics = SKLabelNode(text: "Xcode")
        LabelPhysics.position = CGPointMake(500, 200) // задаем позицию.
        LabelPhysics.fontSize = 22; //  задаем размер шрифта.
        LabelPhysics.physicsBody = SKPhysicsBody(edgeLoopFromRect: CGRectMake(-25, -25, 50, 50)) // Задаем физическое тело.
        LabelPhysics.name = "Label"  // задаем имя.
        self.addChild(LabelPhysics) // добавляем наш объект на нашу сцену.
        
    }



RectanglePhysics

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

Если вы внимательно изучили методы или функции SKPhysicsBody, о которых я писала выше, то вы можете увидеть, что объект который мы передаем в качестве свойства, инициализируется с вызова метода bodyWithRectangleOfSize или функции rectangleOfSize и при его инициализации мы передаем размер нашего Спрайта, и уже по нему и строится наше физическое тело.

Тут есть один важный момент, о котором стоит упомянуть!
Любые касание или соприкосновение происходят не с самим спрайтом, а с его физическим телом!
Если вы укажите размер тела меньше самого Спрайта, в таком случае при соприкосновение объекта часть не вошедшая в физическое тело будет проникать в другой Спрайт, а если вы укажите размер тела больше размера Спрайта, то в таком случае будет казаться, что соприкасается не сама оболочка Спрайта, а некая невидимая граница. На изображение ниже я привела пример для этих случаев!


После установке нашего физического тела, мы устанавливаем еще одно свойство, это dynamic.
Как я писала выше, оно отвечает за динамичность объектов. Здесь мы ему присваиваем отрицательное значение, это значит что теперь наш объект не сможет двигаться, что нам идеально подходит в качестве опорной поверхности!


CirclePhysics
Следующий объект имеет имя CirclePhysics. В нем мы так же сначала устанавливаем физическое тело. Делаем мы это очень просто: инициализируем объект типа SKPhysicsBody с методом bodyWithCircleOfRadius или функцией circleOfRadius и в качестве параметра передаем радиус по которому и будет построено физическое тело. Далее в свойство dynamic мы передаем положительное значение, это значит, что теперь наш Спрайт будет динамичным. Этого можно не делать, по умолчанию оно положительно, мне просто хотелось вам подробно это показать!

Еще один момент. Я выбрала округлое физическое тело, поскольку наш Спрайт сам является окружностью и мне кажется это логичным.
Но вы можете в качестве физического тела для окружности, выбрать например: Прямоугольную форму, как мы выбирали до этого, или любую другую форму! Но в таком случае, окружность будет иметь физические свойства уже той формы, которую мы выбрали!



TexturePhysics
Следующий Спрайт имеет имя TexturePhysics. Тут все то же самое, как и в первом примере. Мы устанавливаем физическое тело прямоугольной формы, но в отличии от первого примера, мы устанавливаем свойство dynamic в положительном значение, и тем самым делаем его динамичным!

TrianglePhysics
Далее, у нас на очереди составной объект с именем TrianglePhysics. Как мы помним, этот объект имеет треугольную форму созданную с помощью объекта UIBezierPath и поэтому нам нужно выбрать для него соответствующую физическую форму. Делается это очень просто, мы как и в предыдущих примерах инициализируем объект SKPhysicsBody. Далее происходит вызов функции polygonFromPath или метода bodyWithPolygonFromPath. Что он(-а) делает? Они в качестве параметра принимают объект нашей формы UIBezierPath с именем TrianglePath и уже на его основе строится наше тело.
Все довольно просто!



LabelPhysics
И последний спрайт имеет имя LabelPhysics. При создание его физического тела, мы как и в прошлый раз инициализируем объект типа SKPhysicsBody, но уже с другим методом bodyWithEdgeLoopFromRect или функцией edgeLoopFromRect инициализации. Что они делают? Так вот, этот метод или функция принимает в качестве параметра инициализации функцию с именем (CGRectMake) и с помощью нее строит физическую границу прямоугольной формы (EDGE). Изображение этой границы вы можете увидеть на рисунке чуть выше. Пусть вас не смущают некие окружности вокруг вершин данного прямоугольника, их создает свойство showsPhysics, которое мы добавили в самом начале этого заголовка. Если его отключить, то все они исчезнут! Физические тела типа EDGE, я о них уже писала, они не могут двигаться и не имеют массу. Они нужны скажем для физического барьера. Например вы ни хотите, чтоб ваш Спрайт вылетал за пределы сцены. Если вы установите эти границы на концах вашей сцены, тогда ваш объект не сможет ее покинуть; он будет отталкиваться от EDGE.



Сравнение Некоторых Физических Свойств

И так друзья, мы с вами научились создавать физические тела для наших объектов и теперь пришло время посмотреть на физические свойства. На видео ниже, мы видим сравнение нескольких физических свойств. Как мы видим в самом начале падают два шарика одинакового размера и с одинаковой высоты. При падение один из них отскакивает, а другой нет. Так же мы видим два квадрата тоже одинакового размера. Они тоже падают с одинаковой высоты, но уже на наклонную поверхность. Один из них скользит и падает, а другой наоборот сразу останавливается. Все это демонстрация некоторых физических свойств. Давайте лучше перейдем непосредственно к коду!



И так давайте посмотрим на наш код!

Objective-c
Objective-c
-(void)PhysicsProperties
{
    
    float RotateAngle = 10 * (2 * M_PI)/360;
    
    
    SKShapeNode *Opora1 = [SKShapeNode shapeNodeWithRect:CGRectMake(-150/2, -10, 150, 20)];
    Opora1.position = CGPointMake(100, 200);
    Opora1.strokeColor = [SKColor greenColor];
    Opora1.fillColor = [SKColor greenColor];
    Opora1.name = @"Opora1";
    Opora1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:Opora1.frame.size];
    Opora1.physicsBody.dynamic = NO;
    Opora1.zRotation = -RotateAngle;
    [self addChild:Opora1];
    
    
    SKShapeNode *Opora2 = [SKShapeNode shapeNodeWithRect:CGRectMake(-150/2, -10, 150, 20)];
    Opora2.position = CGPointMake(468, 200);
    Opora2.strokeColor = [SKColor redColor];
    Opora2.fillColor = [SKColor redColor];
    Opora2.name = @"Opora2";
    Opora2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:Opora2.frame.size];
    Opora2.physicsBody.dynamic = NO;
    Opora2.zRotation = RotateAngle;
    [self addChild:Opora2];
    
    
    
    SKShapeNode *Opora3 = [SKShapeNode shapeNodeWithRect:CGRectMake(-568/2, -10, 568, 20)];
    Opora3.position = CGPointMake(568/2, 10);
    Opora3.strokeColor = [SKColor yellowColor];
    Opora3.fillColor = [SKColor yellowColor];
    Opora3.name = @"Opora3";
    Opora3.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:Opora3.frame.size];
    Opora3.physicsBody.dynamic = NO;
    [self addChild:Opora3];
    
    
    
    SKShapeNode *Circle1 = [SKShapeNode shapeNodeWithCircleOfRadius:15];
    Circle1.position = CGPointMake(250, 280);
    Circle1.strokeColor = [SKColor whiteColor];
    Circle1.fillColor = [SKColor blackColor];
    Circle1.name = @"Circle1";
    Circle1.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:15];
    Circle1.physicsBody.restitution = 0;
    [self addChild:Circle1];
    
    
    SKShapeNode *Circle2 = [SKShapeNode shapeNodeWithCircleOfRadius:15];
    Circle2.position = CGPointMake(310, 280);
    Circle2.strokeColor = [SKColor whiteColor];
    Circle2.fillColor = [SKColor purpleColor];
    Circle2.name = @"Circle2";
    Circle2.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:15];
    Circle2.physicsBody.restitution = 0.7;
    [self addChild:Circle2];
    
    
    
    
    SKShapeNode *Quad1 = [SKShapeNode shapeNodeWithRect:CGRectMake(-30/2, -30/2, 30, 30)];
    Quad1.position = CGPointMake(50, 320);
    Quad1.strokeColor = [SKColor whiteColor];
    Quad1.fillColor = [SKColor whiteColor];
    Quad1.name = @"Quad1";
    Quad1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:Quad1.frame.size];
    Quad1.physicsBody.friction = 1;
    [self addChild:Quad1];
    
    
    
    SKShapeNode *Quad2 = [SKShapeNode shapeNodeWithRect:CGRectMake(-30/2, -30/2, 30, 30)];
    Quad2.position = CGPointMake(518, 320);
    Quad2.strokeColor = [SKColor blackColor];
    Quad2.fillColor = [SKColor blackColor];
    Quad2.name = @"Quad2";
    Quad2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:Quad2.frame.size];
    Quad2.physicsBody.friction = 0.1;
    [self addChild:Quad2];
    
    
}

Swift
Swift
  func PhysicsProperties()
    {
        
        
        let RotateAngle  = 10 * (2 * M_PI)/360
        
        var Opora1 = SKShapeNode(rect: CGRectMake(-150/2, -10, 150, 20))
        Opora1.position = CGPointMake(100, 200)
        Opora1.strokeColor = SKColor.greenColor()
        Opora1.fillColor = SKColor.greenColor()
        Opora1.name = "Opora1"
        Opora1.physicsBody = SKPhysicsBody(rectangleOfSize: Opora1.frame.size)
        Opora1.physicsBody.dynamic = false
        Opora1.zRotation = Float(-RotateAngle)
        self.addChild(Opora1)
        
        
        var Opora2 = SKShapeNode(rect: CGRectMake(-150/2, -10, 150, 20))
        Opora2.position = CGPointMake(468, 200)
        Opora2.strokeColor = SKColor.redColor()
        Opora2.fillColor = SKColor.redColor()
        Opora2.name = "Opora2"
        Opora2.physicsBody = SKPhysicsBody(rectangleOfSize: Opora2.frame.size)
        Opora2.physicsBody.dynamic = false
        Opora2.zRotation  = Float(RotateAngle)
        self.addChild(Opora2)
        
        var Opora3 = SKShapeNode(rect:CGRectMake (-568/2, -10, 568, 20))
        Opora3.position = CGPointMake(568/2, 10)
        Opora3.strokeColor = SKColor.yellowColor()
        Opora3.fillColor = SKColor.yellowColor()
        Opora3.name = "Opora3"
        Opora3.physicsBody = SKPhysicsBody(rectangleOfSize: Opora3.frame.size)
        Opora3.physicsBody.dynamic = false
        self.addChild(Opora3)
        
        
        var Circle1 = SKShapeNode(circleOfRadius: 15)
        Circle1.position = CGPointMake(250, 280)
        Circle1.strokeColor = SKColor.whiteColor()
        Circle1.fillColor = SKColor.blackColor()
        Circle1.name = "Circle1"
        Circle1.physicsBody = SKPhysicsBody(circleOfRadius: 15)
        Circle1.physicsBody.restitution = 0
        self.addChild(Circle1)
        
        var Circle2 = SKShapeNode(circleOfRadius: 15)
        Circle2.position = CGPointMake(310, 280)
        Circle2.strokeColor = SKColor.whiteColor()
        Circle2.fillColor = SKColor.purpleColor()
        Circle2.name = "Circle2"
        Circle2.physicsBody = SKPhysicsBody(circleOfRadius: 15)
        Circle2.physicsBody.restitution = 0.7
        self.addChild(Circle2)
        
        
        var Quad1 = SKShapeNode(rect: CGRectMake (-30/2, -30/2, 30, 30))
        Quad1.position = CGPointMake(50, 320)
        Quad1.strokeColor = SKColor.whiteColor()
        Quad1.fillColor = SKColor.whiteColor()
        Quad1.name = "Quad1"
        Quad1.physicsBody = SKPhysicsBody(rectangleOfSize: Quad1.frame.size)
        Quad1.physicsBody.friction = 1
        self.addChild(Quad1)
        
        
        var Quad2 = SKShapeNode(rect: CGRectMake (-30/2, -30/2, 30, 30))
        Quad2.position = CGPointMake(518, 320)
        Quad2.strokeColor = SKColor.blackColor()
        Quad2.fillColor = SKColor.blackColor()
        Quad2.name = "Quad2"
        Quad2.physicsBody = SKPhysicsBody(rectangleOfSize: Quad2.frame.size)
        Quad2.physicsBody.friction = 0.1
        self.addChild(Quad2)
        }


В самом начале я создаю два объекта типа SKShapeNode, с именами Opora1 и Opora2. На видео, это наклоненные объекты с зеленым и красным цветом соответственно. В их создании нет ничего необычного кроме свойства zRotation о котором я писала выше, но до сих пор мы его не использовали. Как мы помним:
zRotation — Определяет поворот нашего Node в углах Эйлера.

Свойство zRotation принимает свои значение в радианах! И поэтому, что бы повернуть объект на определенный угол нам этот угол надо сначала перевести в радианы. Делается это очень просто:

Objective-c
Мы создаем переменную типа float с именем RotateAngle
float RotateAngle = 10 * (2 * M_PI)/360;

В этой формуле первое число 10, оно и есть угол на который мы совершаем поворот. Если вы например хотите повернуть скажем на 60 градусов, в таком случае вам придется написать так:

float RotateAngle = 60 * (2 * M_PI)/360;

А далее мы присваиваем значение это переменной к свойству zRotation:
Opora1.zRotation = -RotateAngle;


Swift
Мы создаем let переменную с именем RotateAngle
let RotateAngle  = 10 * (2 * M_PI)/360

Тут все тоже самое что и в Objective-c, кроме того что нужно нашу переменную перевести в тип float
Opora1.zRotation = Float(-RotateAngle)

Как видите, в повороте объектов нет ничего сложного!

Далее я создаю еще один объект с именем Opora3, он тот что желтого цвета в самом низу.В его создании тоже нет ничего необычного, так что мы можем двигаться дальше. А далее, у нас идут еще два объекта — окружности с именами Circle1 и Circle2. По своему строению они очень схожи между собой, но есть различия в физических свойствах. Их физическая форма абсолютна идентична, а вот свойство различаются:

Свойство с именем restitution как мы помним определяет:
restitutionОпределяет сколько энергии теряет тело при столкновением (как сильно отскочит тело, при столкновении)
(принимает значения в пределах 0.1 — 1.0). По умолчанию 0.2.

Так вот, в объекте с именем Circle1 я задала его значение равным «0», а в другом объекте с именем Circle2 оно установлено на значение «1». Изменение значение этого свойства, влияет на поведение объекта при столкновение с другими объектами. Как мы можем наблюдать на видео, один из двух шаров при падение отскакивает, а другой напротив лежит неподвижно. Все это результат действие этого свойства.

Еще один пример мы можем наблюдать в двух других объектах с именами Quad1 и Quad2. Они имеют квадратную форму и идентичны во всем, кроме физического свойства с именем friction.
frictionОпределяет шероховатость, поверхности тела. Оно используется для вычисления силы трения при контакте с телом.

У одного объекта его значение равно «1», у другого «0.1» и как результат: один квадрат почти не скользит по поверхности, а другой напротив проскользив всю поверхность падает вниз.

Полный код нашего проекта
Objective-c
Objective-c

#import "GameScene.h"

@implementation GameScene


-(void)didMoveToView:(SKView *)view
{
      [self SceneSetting];
    //[self SKSpriteNodeDemo];
    //[self SKShapeNodeDemo];
    //[self SKLabelNodeDemo];
    //[self CreatePhysics];
      [self PhysicsProperties];
}


-(void)SceneSetting
{
    
  self.backgroundColor = [SKColor orangeColor];
  self.physicsWorld.gravity = CGVectorMake(0, -1);
    
}

-(void)PhysicsProperties
{
    
    float RotateAngle = 10 * (2 * M_PI)/360;
    
    
    SKShapeNode *Opora1 = [SKShapeNode shapeNodeWithRect:CGRectMake(-150/2, -10, 150, 20)];
    Opora1.position = CGPointMake(100, 200);
    Opora1.strokeColor = [SKColor greenColor];
    Opora1.fillColor = [SKColor greenColor];
    Opora1.name = @"Opora1";
    Opora1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:Opora1.frame.size];
    Opora1.physicsBody.dynamic = NO;
    Opora1.zRotation = -RotateAngle;
    [self addChild:Opora1];
    
    
    SKShapeNode *Opora2 = [SKShapeNode shapeNodeWithRect:CGRectMake(-150/2, -10, 150, 20)];
    Opora2.position = CGPointMake(468, 200);
    Opora2.strokeColor = [SKColor redColor];
    Opora2.fillColor = [SKColor redColor];
    Opora2.name = @"Opora2";
    Opora2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:Opora2.frame.size];
    Opora2.physicsBody.dynamic = NO;
    Opora2.zRotation = RotateAngle;
    [self addChild:Opora2];
    
    
    
    SKShapeNode *Opora3 = [SKShapeNode shapeNodeWithRect:CGRectMake(-568/2, -10, 568, 20)];
    Opora3.position = CGPointMake(568/2, 10);
    Opora3.strokeColor = [SKColor yellowColor];
    Opora3.fillColor = [SKColor yellowColor];
    Opora3.name = @"Opora3";
    Opora3.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:Opora3.frame.size];
    Opora3.physicsBody.dynamic = NO;
    [self addChild:Opora3];
    
    
    
    SKShapeNode *Circle1 = [SKShapeNode shapeNodeWithCircleOfRadius:15];
    Circle1.position = CGPointMake(250, 280);
    Circle1.strokeColor = [SKColor whiteColor];
    Circle1.fillColor = [SKColor blackColor];
    Circle1.name = @"Circle1";
    Circle1.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:15];
    Circle1.physicsBody.restitution = 0;
    [self addChild:Circle1];
    
    
    SKShapeNode *Circle2 = [SKShapeNode shapeNodeWithCircleOfRadius:15];
    Circle2.position = CGPointMake(310, 280);
    Circle2.strokeColor = [SKColor whiteColor];
    Circle2.fillColor = [SKColor purpleColor];
    Circle2.name = @"Circle2";
    Circle2.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:15];
    Circle2.physicsBody.restitution = 0.7;
    [self addChild:Circle2];
    
    
    
    
    SKShapeNode *Quad1 = [SKShapeNode shapeNodeWithRect:CGRectMake(-30/2, -30/2, 30, 30)];
    Quad1.position = CGPointMake(50, 320);
    Quad1.strokeColor = [SKColor whiteColor];
    Quad1.fillColor = [SKColor whiteColor];
    Quad1.name = @"Quad1";
    Quad1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:Quad1.frame.size];
    Quad1.physicsBody.friction = 1;
    [self addChild:Quad1];
    
    
    
    SKShapeNode *Quad2 = [SKShapeNode shapeNodeWithRect:CGRectMake(-30/2, -30/2, 30, 30)];
    Quad2.position = CGPointMake(518, 320);
    Quad2.strokeColor = [SKColor blackColor];
    Quad2.fillColor = [SKColor blackColor];
    Quad2.name = @"Quad2";
    Quad2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:Quad2.frame.size];
    Quad2.physicsBody.friction = 0.1;
    [self addChild:Quad2];
    
    
}

-(void)CreatePhysics

{
    
    SKShapeNode *RectanglePhysics = [SKShapeNode shapeNodeWithRect:CGRectMake(-580/2, -10, 580, 20)];
    RectanglePhysics.position = CGPointMake(280, 40);
    RectanglePhysics.fillColor = [SKColor whiteColor];
    RectanglePhysics.name = @"Rectangle";
    RectanglePhysics.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:RectanglePhysics.frame.size];
    RectanglePhysics.physicsBody.dynamic = NO;
    [self addChild:RectanglePhysics];
    
    
    
    SKShapeNode *CirclePhysics = [SKShapeNode shapeNodeWithCircleOfRadius:40];
    CirclePhysics.position = CGPointMake(100, 160);
    CirclePhysics.strokeColor = [SKColor greenColor];
    CirclePhysics.lineWidth = 5;
    CirclePhysics.name = @"Circle";
    CirclePhysics.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:40];
    CirclePhysics.physicsBody.dynamic = YES;
    [self addChild:CirclePhysics];
    
    
    
    
    
    SKTexture *Texture = [SKTexture textureWithImageNamed:@"DerevoOpora"];
    
    SKSpriteNode *TexturePhysics = [SKSpriteNode spriteNodeWithTexture:Texture];
    TexturePhysics.position = CGPointMake(200, 180);
    TexturePhysics.size = CGSizeMake(100, 30);
    TexturePhysics.name = @"TexturePhysics";
    TexturePhysics.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:TexturePhysics.frame.size];
    TexturePhysics.physicsBody.dynamic = YES;
    [self addChild: TexturePhysics];
    
    
    
    
    UIBezierPath *TrianglePath = [UIBezierPath bezierPath];
    [TrianglePath moveToPoint:CGPointMake(0,0)];
    [TrianglePath addLineToPoint:CGPointMake(-50, -100)];
    [TrianglePath addLineToPoint:CGPointMake(50, -100)];
    [TrianglePath addLineToPoint:CGPointMake(0, 0)];
    
    
    
    
    
    SKShapeNode *TrianglePhysics = [SKShapeNode shapeNodeWithPath:TrianglePath.CGPath ];
    TrianglePhysics.position = CGPointMake(400, 190);
    TrianglePhysics.lineWidth = 2;
    TrianglePhysics.strokeColor = [SKColor blackColor];
    TrianglePhysics.fillColor = [SKColor blueColor];
    TrianglePhysics.name = @"Triangle";
    TrianglePhysics.physicsBody = [SKPhysicsBody bodyWithPolygonFromPath:TrianglePath.CGPath];
    TrianglePhysics.physicsBody.dynamic = YES;
    [self addChild:TrianglePhysics];
    
    
    
    
    SKLabelNode *LabelPhysics = [SKLabelNode labelNodeWithText:@"Xcode"];
    LabelPhysics.position = CGPointMake(500, 200);
    LabelPhysics.fontSize = 22;
    LabelPhysics.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:CGRectMake(-25, -25, 50, 50)];
    LabelPhysics.name = @"Label";
    [self addChild:LabelPhysics];
    
    
    
}


-(void)SKSpriteNodeDemo
{
    
    SKTexture *Texture = [SKTexture textureWithImageNamed:@"desert_BG"];
    
    
    SKSpriteNode *BackgroundSprite = [SKSpriteNode spriteNodeWithTexture:Texture];
    BackgroundSprite.size = CGSizeMake(640, 320);
    BackgroundSprite.position = CGPointMake(0, 0);
    BackgroundSprite.anchorPoint = CGPointMake(0, 0);
    BackgroundSprite.name = @"BackgroundSprite";
    [self addChild:BackgroundSprite];
    
    
    
    SKSpriteNode *SimpleSprite = [SKSpriteNode spriteNodeWithColor:[UIColor blueColor] size:CGSizeMake(50, 50)];
    SimpleSprite.position = CGPointMake(200, 150);
    SimpleSprite.zPosition = 1;
    SimpleSprite.name = @"SimpleSprite";
    [self addChild:SimpleSprite];

    
    SKSpriteNode *ImageSprite = [SKSpriteNode spriteNodeWithImageNamed:@"DerevoOpora"];
    ImageSprite.position = CGPointMake(250, 50);
    ImageSprite.size = CGSizeMake(100, 15);
    ImageSprite.name = @"ImageSprite";
    [self addChild:ImageSprite];
    
}


-(void)SKShapeNodeDemo
{
    SKShapeNode *Circle = [SKShapeNode shapeNodeWithCircleOfRadius:20];
    Circle.position = CGPointMake(50, 200);
    Circle.lineWidth = 10;
    Circle.strokeColor = [SKColor blueColor];
    Circle.fillColor = [SKColor redColor];
    Circle.name = @"Circle";
    [self addChild:Circle];
    
    SKShapeNode *Quad = [SKShapeNode shapeNodeWithRect:CGRectMake(0, 0, 50, 50)];
    Quad.position = CGPointMake(100, 200);
    Quad.lineWidth = 4;
    Quad.strokeColor = [SKColor whiteColor];
    Quad.fillColor = [SKColor blackColor];
    Quad.name = @"Quad";
    [self addChild:Quad];
    
    
    
    SKShapeNode *Ellips = [SKShapeNode shapeNodeWithEllipseInRect:CGRectMake(0, 0, 50, 90)];
    Ellips.position = CGPointMake(200, 200);
    Ellips.lineWidth = 2;
    Ellips.strokeColor = [SKColor greenColor];
    Ellips.fillColor = [SKColor purpleColor];
    Ellips.glowWidth = 5;
    Ellips.name = @"Ellips";
    [self addChild:Ellips];
    
    
    
    
    UIBezierPath *RoundedRectPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 50, 50) cornerRadius:12];
    
    SKShapeNode *RoundedRect = [ SKShapeNode shapeNodeWithPath:RoundedRectPath.CGPath centered:YES];
    RoundedRect.position = CGPointMake(50, 100);
    RoundedRect.lineWidth = 2;
    RoundedRect.strokeColor = [SKColor blueColor];
    RoundedRect.fillColor = [SKColor redColor];
    RoundedRect.name = @"RoundedRect";
    [self addChild:RoundedRect];
    
    
    
    
   
    
    
    UIBezierPath *TrianglePath = [UIBezierPath bezierPath];
    [TrianglePath moveToPoint:CGPointMake(0,0)];
    [TrianglePath addLineToPoint:CGPointMake(-25, -50)];
    [TrianglePath addLineToPoint:CGPointMake(25, -50)];
    [TrianglePath addLineToPoint:CGPointMake(0, 0)];
    
    SKShapeNode *Triangle = [SKShapeNode shapeNodeWithPath:TrianglePath.CGPath centered:YES];
    Triangle.position = CGPointMake(200, 70);
    Triangle.lineWidth = 2;
    Triangle.strokeColor = [SKColor blackColor];
    Triangle.fillColor = [SKColor blueColor];
    Triangle.name = @"Triangle";
    [self addChild:Triangle];
    
    
}


-(void)SKLabelNodeDemo
{
    SKLabelNode *First = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
    First.position = CGPointMake(280, 200);
    First.fontSize = 25;
    First.fontColor = [SKColor whiteColor];
    First.color = [SKColor blueColor];
    First.colorBlendFactor = 0.5;
    First.text = @"Habra Habr!";
    First.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeCenter;
    [self addChild:First];
    
    
    
    SKLabelNode *Second = [SKLabelNode labelNodeWithText:@"Романов-Кошкин-Захарьин-Голштейн-Готторпский"];
    Second.fontName = @"Chalkboard SE Bold";
    Second.fontColor = [SKColor blackColor];
    Second.position = CGPointMake(280, 50);
    Second.fontSize = 20;
    [self addChild:Second];
    
    
    
}

@end




Swift
Swift

import SpriteKit


class GameScene: SKScene
{
    override func didMoveToView(view: SKView)
    {
          SceneSetting()
        //SKSpriteNodeDemo()
        //SKShapeNodeDemo()
        //SKLabelNodeDemo()
        //CreatePhysics()
          PhysicsProperties()
    }
    
    
    func SceneSetting()
    {
        self.backgroundColor = SKColor.orangeColor()
        self.physicsWorld.gravity = CGVectorMake(0, -1);
        
    }
    
    
    func PhysicsProperties()
    {
        
        
        let RotateAngle  = 10 * (2 * M_PI)/360
        
        var Opora1 = SKShapeNode(rect: CGRectMake(-150/2, -10, 150, 20))
        Opora1.position = CGPointMake(100, 200)
        Opora1.strokeColor = SKColor.greenColor()
        Opora1.fillColor = SKColor.greenColor()
        Opora1.name = "Opora1"
        Opora1.physicsBody = SKPhysicsBody(rectangleOfSize: Opora1.frame.size)
        Opora1.physicsBody.dynamic = false
        Opora1.zRotation = Float(-RotateAngle)
        self.addChild(Opora1)
        
        
        var Opora2 = SKShapeNode(rect: CGRectMake(-150/2, -10, 150, 20))
        Opora2.position = CGPointMake(468, 200)
        Opora2.strokeColor = SKColor.redColor()
        Opora2.fillColor = SKColor.redColor()
        Opora2.name = "Opora2"
        Opora2.physicsBody = SKPhysicsBody(rectangleOfSize: Opora2.frame.size)
        Opora2.physicsBody.dynamic = false
        Opora2.zRotation  = Float(RotateAngle)
        self.addChild(Opora2)
        
        var Opora3 = SKShapeNode(rect:CGRectMake (-568/2, -10, 568, 20))
        Opora3.position = CGPointMake(568/2, 10)
        Opora3.strokeColor = SKColor.yellowColor()
        Opora3.fillColor = SKColor.yellowColor()
        Opora3.name = "Opora3"
        Opora3.physicsBody = SKPhysicsBody(rectangleOfSize: Opora3.frame.size)
        Opora3.physicsBody.dynamic = false
        self.addChild(Opora3)
        
        
        var Circle1 = SKShapeNode(circleOfRadius: 15)
        Circle1.position = CGPointMake(250, 280)
        Circle1.strokeColor = SKColor.whiteColor()
        Circle1.fillColor = SKColor.blackColor()
        Circle1.name = "Circle1"
        Circle1.physicsBody = SKPhysicsBody(circleOfRadius: 15)
        Circle1.physicsBody.restitution = 0
        self.addChild(Circle1)
        
        var Circle2 = SKShapeNode(circleOfRadius: 15)
        Circle2.position = CGPointMake(310, 280)
        Circle2.strokeColor = SKColor.whiteColor()
        Circle2.fillColor = SKColor.purpleColor()
        Circle2.name = "Circle2"
        Circle2.physicsBody = SKPhysicsBody(circleOfRadius: 15)
        Circle2.physicsBody.restitution = 0.7
        self.addChild(Circle2)
        
        
        var Quad1 = SKShapeNode(rect: CGRectMake (-30/2, -30/2, 30, 30))
        Quad1.position = CGPointMake(50, 320)
        Quad1.strokeColor = SKColor.whiteColor()
        Quad1.fillColor = SKColor.whiteColor()
        Quad1.name = "Quad1"
        Quad1.physicsBody = SKPhysicsBody(rectangleOfSize: Quad1.frame.size)
        Quad1.physicsBody.friction = 1
        self.addChild(Quad1)
        
        
        var Quad2 = SKShapeNode(rect: CGRectMake (-30/2, -30/2, 30, 30))
        Quad2.position = CGPointMake(518, 320)
        Quad2.strokeColor = SKColor.blackColor()
        Quad2.fillColor = SKColor.blackColor()
        Quad2.name = "Quad2"
        Quad2.physicsBody = SKPhysicsBody(rectangleOfSize: Quad2.frame.size)
        Quad2.physicsBody.friction = 0.1
        self.addChild(Quad2)
        
        
        
        
    }
    
    func CreatePhysics()
    {
        var RectanglePhysics = SKShapeNode(rect: CGRectMake(-580/2, -10, 580, 20))
        RectanglePhysics.position = CGPointMake(280, 40)
        RectanglePhysics.fillColor = SKColor.whiteColor()
        RectanglePhysics.name = "Rectangle"
        RectanglePhysics.physicsBody = SKPhysicsBody(rectangleOfSize: RectanglePhysics.frame.size)
        RectanglePhysics.physicsBody.dynamic = false
        self.addChild(RectanglePhysics)
        
        
        var CirclePhysics = SKShapeNode(circleOfRadius: 40)
        CirclePhysics.position = CGPointMake(100, 160)
        CirclePhysics.strokeColor = SKColor.greenColor()
        CirclePhysics.lineWidth = 5;
        CirclePhysics.name = "Circle"
        CirclePhysics.physicsBody = SKPhysicsBody(circleOfRadius: 40)
        CirclePhysics.physicsBody.dynamic = true
        self.addChild(CirclePhysics)
        
        
        
        
        
        let Texture = SKTexture(imageNamed: "DerevoOpora")
        
        var TexturePhysics = SKSpriteNode(texture: Texture)
        TexturePhysics.position = CGPointMake(200, 180)
        TexturePhysics.size = CGSizeMake(100, 30)
        TexturePhysics.name = "TexturePhysics"
        TexturePhysics.physicsBody = SKPhysicsBody(rectangleOfSize: TexturePhysics.frame.size)
        TexturePhysics.physicsBody.dynamic = true
        self.addChild(TexturePhysics)
        
        
        
        var TrianglePath = UIBezierPath()
        TrianglePath.moveToPoint(CGPointMake(0, 0))
        TrianglePath.addLineToPoint(CGPointMake(-50, -100))
        TrianglePath.addLineToPoint(CGPointMake(50, -100))
        TrianglePath.addLineToPoint(CGPointMake(0, 0))
        
        
        
        var TrianglePhysics = SKShapeNode(path: TrianglePath.CGPath)
        TrianglePhysics.position = CGPointMake(400, 190)
        TrianglePhysics.lineWidth = 2
        TrianglePhysics.strokeColor = SKColor.blackColor()
        TrianglePhysics.fillColor = SKColor.blueColor()
        TrianglePhysics.name = "Triangle"
        TrianglePhysics.physicsBody = SKPhysicsBody(polygonFromPath: TrianglePath.CGPath)
        TrianglePhysics.physicsBody.dynamic = true
        self.addChild(TrianglePhysics)
        
        
        var LabelPhysics = SKLabelNode(text: "Xcode")
        LabelPhysics.position = CGPointMake(500, 200)
        LabelPhysics.fontSize = 22;
        LabelPhysics.physicsBody = SKPhysicsBody(edgeLoopFromRect: CGRectMake(-25, -25, 50, 50))
        LabelPhysics.name = "Label"
        self.addChild(LabelPhysics)
        
    }
    
    
    func SKSpriteNodeDemo()
    {
        
        var Texture = SKTexture(imageNamed: "desert_BG")
        
        var BackgroundSprite = SKSpriteNode(texture: Texture)
        BackgroundSprite.size = CGSizeMake(640, 320)
        BackgroundSprite.position = CGPointMake(0, 0)
        BackgroundSprite.anchorPoint = CGPointMake(0, 0)
        BackgroundSprite.name = "BackgroundSprite"
        self.addChild(BackgroundSprite)
        
        
        var SimpleSprite = SKSpriteNode(color: UIColor.blueColor(), size: CGSizeMake(50, 50))
        SimpleSprite.position = CGPointMake(200, 150)
        SimpleSprite.zPosition = 1;
        SimpleSprite.name = "SimpleSprite"
        self.addChild(SimpleSprite)
        
        
        var ImageSprite = SKSpriteNode(imageNamed: "DerevoOpora")
        ImageSprite.position = CGPointMake(250, 50)
        ImageSprite.size = CGSizeMake(100, 15)
        ImageSprite.name = "ImageSprite"
        self.addChild(ImageSprite)
        
        
    }
    
    
    func SKShapeNodeDemo()
    {
        
        var Circle = SKShapeNode(circleOfRadius: 20)
        Circle.position = CGPointMake(50, 200)
        Circle.lineWidth = 10
        Circle.strokeColor = SKColor.blueColor()
        Circle.fillColor = SKColor.redColor()
        Circle.name = "Circle"
        self.addChild(Circle)
        
        
        var Quad = SKShapeNode(rect: CGRectMake(0, 0, 50, 50))
        Quad.position = CGPointMake(100, 200)
        Quad.lineWidth = 4
        Quad.strokeColor = SKColor.whiteColor()
        Quad.fillColor = SKColor.blackColor()
        Quad.name = "Quad"
        self.addChild(Quad)
        
        
        var Ellips = SKShapeNode(ellipseInRect: CGRectMake(0, 0, 50, 90))
        Ellips.position = CGPointMake(200, 200)
        Ellips.lineWidth = 2
        Ellips.strokeColor = SKColor.greenColor()
        Ellips.fillColor = SKColor.purpleColor()
        Ellips.glowWidth = 5
        Ellips.name = "Ellips"
        self.addChild(Ellips)
        
        
        var RoundedRectPath = UIBezierPath(roundedRect: CGRectMake(0, 0, 50, 50), cornerRadius: 12)
        
        var RoundedRect = SKShapeNode(path: RoundedRectPath.CGPath, centered:true)
        RoundedRect.position = CGPointMake(50, 100)
        RoundedRect.lineWidth = 2
        RoundedRect.strokeColor = SKColor.blueColor()
        RoundedRect.fillColor = SKColor.redColor()
        RoundedRect.name = "RoundedRect"
        self.addChild(RoundedRect)
        
        
        
        
        
        var TrianglePath = UIBezierPath()
        TrianglePath.moveToPoint(CGPointMake(0, 0))
        TrianglePath.addLineToPoint(CGPointMake(-25, -50))
        TrianglePath.addLineToPoint(CGPointMake(25, -50))
        TrianglePath.addLineToPoint(CGPointMake(0, 0))
        
        
        var Triangle = SKShapeNode(path: TrianglePath.CGPath, centered: true)
        Triangle.position = CGPointMake(200, 70)
        Triangle.lineWidth = 2
        Triangle.strokeColor = SKColor.blackColor()
        Triangle.fillColor = SKColor.blueColor()
        Triangle.name = "Triangle"
        self.addChild(Triangle)
        
        
        
    }
    
    
    func SKLabelNodeDemo()
    {
        var First = SKLabelNode(fontNamed: "Chalkduster")
        First.position = CGPointMake(280, 200)
        First.fontSize = 25;
        First.fontColor = SKColor.whiteColor()
        First.color = SKColor.blueColor()
        First.colorBlendFactor = 0.5
        First.text = "Habra Habr!"
        First.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Center
        self.addChild(First)
        
        
        
        var Second = SKLabelNode(text: "Романов-Кошкин-Захарьин-Голштейн-Готторпский")
        Second.fontName = "Chalkboard SE Bold"
        Second.fontColor = SKColor.blackColor()
        Second.position = CGPointMake(280, 50)
        Second.fontSize = 20
        self.addChild(Second)
        
        
        
    }
    
    
}




Как видите физические характеристики играют огромную роль, с их помощью объекты обретают форму и меняют свои свойства. Эти характеристики определяют: как тело движется, как на него влияют силы в симуляции и как оно реагирует на столкновения с другими телами. Каждый раз, когда сцена рассчитывает новый кадр анимации, она имитирует эффекты сил и столкновений спрайтов с физическими телами. SpriteKit вычисляет окончательную позицию, ориентацию и скорость для каждого физического тела. Затем, сцена обновляет положение каждого соответствующего спрайта.


Ну что друзья, здесь я бы хотела остановиться и дать вам разобраться во всем, что я написала выше. Как вы могли заметить, SpriteKit очень мощный движок. Специалисты из Apple постарались на славу. Конечно в нем пока что нет таких возможностей, которые присутствуют в cocos2d, но все же SpriteKit намного моложе его и думаю у него все еще впереди!

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



Немного изображений


Игра называется: Soul Shift: Next Generation


Для тех кто только-только учится создавать приложения, есть очень хорошие видео уроки по языкам Objective-c и Swift. Их создает парень по имени Алексей. Он есть на habrahabr: ezeki. В каждом видео он очень подробно разбирает основные аспекты языка и наглядно это демонстрирует. Эти уроки будут очень полезны как новичкам так и тем кто уже свободно программирует под iOS.

Objective-c

Swift



P.S. Друзья! я думаю вы не будете судить меня строго за мои грамматические ошибки, ибо это мой второй язык, который я усердно изучаю.

P.P.S. В заключении хочу поблагодарить пользователя AbyssMoon, который оказал мне честь находиться среди вас!
G.Y @zaaa
карма
16,0
рейтинг 0,0
Пользователь
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (15)

  • +3
    Спасибо. И не слушайте тех, кто говорит, что подобные материалы на русском не нужны, мол хватает мануала. Пусть читают, раз хватает. Многим приятнее читать на русском, даже если могут это делать и на других языках.
  • +1
    Спасибо за замечательную статью!

    Правда, полный исходный код лучше разместить на github — в статье уже есть всё необходимое. А вот возможность скачать сразу весь код (да ещё и с проектом) и поиграть с ним очень полезно было бы.
  • +2
    Это, конечно, хорошо, что появляются новые технологии и языки, но мне кажется не совсем правильным привязываться к непортируемым функциям конкретных ОС, ещё и используемым лишь в новейшей версии. Это выгодно компаниям, но не выгодно пользователям и, в конечном счёте, программистам. В последнее время я замечаю, что в связи с увеличившимся парком платформ основные компоненты пишут на C++ (лично я его не люблю, но считаю меньшим злом, чем поддержку параллельных веток), а системнозависимые на чём Бог послал. Так и Swift — я не понял, в чём его смысл — похож на Objective C, но лишён элегантного синтаксиса и напоминает Java Script. Нас что, считают такими глупыми, что мы уже отличный от Явы язык освоить не сможем? Что касается GameKit — мы в своё время от него отказались из-за ограниченности его возможностей и опять же жёсткой привязки в версии iOS, так как геймер не обязан покупвть последний iphone и загружать новейшую версию лишь затем, что пограть в простейшую игру. PS: у Вас очень хороший русский язык.
    • +3
      Ну видимо, swift для тех, кто не считает, что синтаксис objective c элегантен. И таких людей очень много. Эппл хочет получить в своих рядах тех разработчиков, которые не против писать под iOS но смущаются именно синтаксиса ObjC.

      А касательно функции конкретных ОС, то уровень поддержки spritekit очень даже высок на данный момент (проникновение iOS 7 позволяет). Не работает только на совсем старых девайсах, но на них разработчики и так особо не ориентируются.

      Непортируемость это, конечно, минус. Но с другой стороны, это нативное средство для инди разработчиков, которые хотят разрабатывать и тестировать только под iOS, не сталкиваясь с проблемами фрагментации, других маркетов и т. д. Для крутого проекта лучше, конечно, выбрать что-то кроссплатформенное, но для небольших игрушек SpriteKit отлично справляется. Хотя, есть в нем, конечно, непонятные ограничения. Надеюсь, его обновят и оставят совместимым с ios 7.
  • +1
    Самая-самая большая проблема SpriteKit в невозможности «дешево» портировать код на Android. Откинем WP, W8, Tizen и прочие мелкие рынки, но буквально выбрав кросс-платформенный движок мы удвоим или даже утроим доход, по сравнению с «чистой» iOS и Obj-C/Swift. Конечно, если продукт станет успешным на iOS, можно портировать и на другие платформы, хоть с нуля написать, но по критичности аудитории и ее привередливости правильно бы выходить на iOS с идеально отлаженным и на 100% готовым проектом, перед этим погоняв его хорошенько на Android, а лучше еще и на чем-то не прибыльном, но показательном, вроде BlackBerry. Особенно важно, что на Android апдейт доходит до пользователей в течение пары часов, а на iOS — через неделю с гаком после его создания.
    • +1
      А есть хорошие кроссплатформенные движки, которые имеют приличную документацию, комьюнити и поддержку и при этом позволяют публиковать игры в маркетах сравнительно недорого? Платить тысячи баксов за Юнити, например, будет накладненько тем, кто делает всякие Солитеры, 3 в ряд и подобное.
      • 0
        Cocos2d, Corona, частично MonoGame, а вообще по большому счету даже если писать на чистом OpenGL ES и едином языке (C++, C#, JS), то работать будет на куче платформ с не очень большой головной болью. Вроде как и на дешевых лицензиях Unity можно многое. Конечно, на iOS все очень красиво и удачно реализовано, после нее тот же WP с недо-XNA будет казаться адом, но все же кросс-платформенность того стоит.
        • 0
          Глянул на сайте Unity, iOS + android будет стоить 4500 (про версия + 1500 за каждую платформу). Да, бонусом идут все остальные платформы, но для простеньких игрушек не подойдет точно, разве что вагонами их клепать.

          А остальные движки… не знаю, как по мне, то spritekit идеален для обучения именно тому, как вообще делать игры. Быстро и удобно создал несколько простых игрушек, разобрался с построением механики, взаимодействия с художниками, платежными системами и прочим. А потом уже как следюущий этап, изучаешь кроссплатформенные языки.

          Естественно, это путь для IOS / Mac разработчика. Если до этого был опыт разработки на С++ или C# или чем-то еще, то стоит поискать инструмент на привычном ЯП.
      • 0
        Даже если говорить не об игрушках, то при разговоре о кроссплатформе всегда надо перезакладывать и времени и бюджета и вообще. Если ты инди и представления не имеешь о том даже — взлетит твоя идея или нет, то если честно «запустили через 3 месяца и не взлетела» выглядит значительно предпочтительнее, чем «запустили через полгода-год и провалилась».
        Если у тебя в мыслях изначально есть кроссплатформа, то я бы рекомендовал просто писать код максимально разделенным на «модули»-«слои», так чтобы замена рендера с UIKit на SpriteKit или Cocos2d решалась за короткий промежуток времени. Так же как и замена физического движка.
        Благо, Objective-C дает нам категории и тайпалиасы — соответственно можно делать вид, что разработчик работает с чем-то вообще непривязанным к реализации.

        P.S. Восхитительная статья по спрайткиту. Некоторые мои знакомые интересовались стартовыми материалами, теперь я знаю, какую ссылку им скинуть. Спасибо за труд!
  • +1
    * У вас на видео ошибка в слове Checking (на видео Cheking) *
  • 0
    Спасибо за статью!
  • 0
    Спасибо за статью.
    После прочтения возник вопрос. Можно ли сделать из спрайта кнопку? Или только отслеживать через -touchesBegan?
  • 0
    А вы таки выложили исходники игры на гитхаб или нет?
  • 0
    Спасибо!
  • 0
    Статья очень помогла.
    Кстати, недавно наткнулся на инфу, которая вдруг раскрыла, что же за элемент проекта SpriteKit под таинственным именем «GameScene.sks»
    Оказывается это что-то вроде аналога сториборда, но для спрайткита — визуальный редактор сцены!
    Для заинтригованных ссылка тут

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