С появлением iOS 7 мир узрел новый игровой движок от Apple — SpriteKit. В свете того, что он появился совсем недавно об этом движке еще мало что написано, конечно в сети можно найти несколько tutorial -ов по нему но в основном все они на Английском языке. И по этому я задалась целью написать подробный Туториал об этом замечательном движке.
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 это:
Для Swift:
Как вы уже успели заметить, в проекте со Swift файлов вдвое меньше.
Слева мы видим:
Давайте заглянем в некоторые файлы и посмотрим что у них внутри.
GameViewController — он отвечает за создание и инициализацию нашей сцены. Все начальные настройки служащие для отображения нашей сцены нужно проводить здесь.
В целом все что, происходит в GameViewController одинаково для обоих языков:
В самом начале вызывается метод или функция viewDidLoad.
В этом методе или функции происходит: создание и настройка нашей сцены и некоторых параметров ее отображения.
В самом начале, в этом методе или функции создается указатель или константа на объект типа SKView и ему присваивается текущий View.
SKView — это наследник UIView, он служит для отображение нашей сцены.
Далее идет настройка основных свойств нашего SKView:
Далее идет создание Объекта нашей сцены — GameScene. В случае со Swift он уже был создан до конфигурации нашего View.
По умолчанию объект нашей сцены инициализируется с вызова метода или функции:
Objective-c
Swift
Что происходит при его вызове, он находит файл нашего визуального конструктора GameScene.sks затем разархивирует его, а после возвращает объект типа SKScene для последующий инициализации нашей сцены.
Обратите внимание что, у объекта нашей сцены, есть свойства:
scaleMode как можно догадаться из названия, это свойство выполняет растяжку сцены по экрану, поэкспериментируйте с этим свойством!
После того, как мы настроили наш SKView и создали объект нашей сцены, теперь можно ее отобразить. Делается это очень просто, мы вызываем функцию или метод класса SKView:
Ниже я привела полный код GameViewController.
Ну что же, после того как мы настроили нашу сцену, она готова к боевым действиям и тут друзья мои начинается все самое интересное!
Как вы уже успели заметить, по умолчанию у нас запуститься сцена с некоторыми уже добавленными объектами.
Удалите все в GameScene так, что бы она соответствовала коду ниже:
Теперь скомпилируем наш проект и мы увидим:
Мы видим пустой серый экран и больше ничего, кроме количества Node объектов и частоты обновлений сцены, теперь давайте остановимся и проанализируем код в GameScene.
Чтобы понять как наша сцена работает, нам сначала нужно понять ее основные методы или функции, ниже я приведу основные, остальные вы можете посмотреть и сами в .h файле.
Основные свойства:
Основные методы или функции
Основные события нашей сцены
Итак, друзья, теперь когда мы видели основные методы или функции, Свойства и события нашей сцены, мы можем немного изменить наш код. Давайте попробуем изменить цвет нашей сцены, для этого обратимся к свойству backgroundColor и покрасим нашу сцену в оранжевый цвет. Как мы уже видели выше, при инициализации сцены первым должен вызваться метод или функция initWithSize:, а после того как наша сцена уже отобразилась, вызывается didMoveToView:. В нашем случае, сцена инициализируется с вызова метода или функции unarchiveFromFile и поэтому мы уже не можем повторно написать метод инициализации. И поэтому, нам остается определить наши начальные настройки в didMoveToView:.
Objective-c
Swift
Как видно из примеров выше, сначала вызывается метод или функция didMoveToView, далее в нем(ей) вызывается метод или функцию SceneSetting, а уже после изменяется цвет нашей сцены. Обратите внимание, что при изменение цвета мы не обращаемся к объекту UIColor как мы привыкли, мы обращаемся к SKColor, по сути это define UIColor и поэтому вы можете писать и так и так, ошибкой это не будет. Вы наверно спросите, для чего я вынесла настройки в отдельный метод или функцию. Я это сделала для удобство, в больших проектах порой бывает очень трудно ориентироваться, и нам будет очень удобно, если мы в самом начале все будем делать аккуратно.
Итак, что у нас получилась вы видите на изображении снизу.
На нашей сцене, еще ничего не происходит, так давайте это исправим друзья!
А иначе, что мы тут делаем!
Ну что, друзья, как видите мы изменили цвет нашей сцены и вы наверно задались вопросом, и все? и ради этого мы зашли сюда?
Друзья, к сожаление я не могу продемонстрировать вам всю мощь, какую имеет наша сцена, для этого нам нужно изучить еще один очень важный пункт это — SKNode.
SKNode — это важнейший элемент. В SpriteKit он считается основным, от него наследуются все остальные элементы.
Даже наша сцена по сути является его наследником и обладает всеми его свойствами.
Давайте посмотрим на Свойство, Методы или Функции, нашего SKNode.
Свойство
Методы или Функции
Итак, мы почти закончили, друзья потерпите еще чуть-чуть. Как мы видим, чуть выше, 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.
Перед тем как приступить к обзору, мы заблокируем ориентацию и изменим свойство нашей сцены scaleMode, для чего это нужно?
Для удобства, мне будет удобнее показывать вам весь процесс на перевернутом экране, да и вам не надоест без конца переворачивать экран.
Давайте найдем наш ViewController и изменим в нем эти свойство.
Objective-c
Swift
SKSpriteNode — это стандартный спрайт, который отображает Текстуры (Графические изображения).
Давайте посмотрим на него вблизи, на изображении ниже мы видим три объекта (Спрайта):
Синий квадрат, Спрайт с изображением дощечки, и Спрайт заднего фона.
Я специально создала 3 объекта типа SKSpriteNode, что бы вы увидели различия в их создании.
Для начала откройте Xcode и в нашем проекте создайте новую папку и назовите ее SpriteKitImage (Можете назвать как хотите)
Далее скачайте отсюда архив с изображениями, после распакуйте его и добавьте эти изображения в нашу только что созданную папку.
Весь код с описанием процесса создания находится чуть ниже, здесь я объясню некоторые моменты.
Первый спрайт имеет имя BackgroundSprite, перед его созданием, мы создаем объект типа SKTexture, и в него в качестве параметра передаем имя нашего изображения. Зачем нужен этот объект?
Текстуры, очень полезны для работы с изображениями еще до создание нами самих спрайтов, с их помощь можно экономно управлять ресурсами, один и тот же объект может быть использован несколькими спрайтами.
Далее мы задаем размер и позицию. Несколько слов о позиции, в SKSpriteNode ее мы отсчитываем от середины нашего объекта, то есть когда говорят мы сдвинули такой то спрайт на 100px, это значит мы сдвинули его центральную точку на 100px.
После того, как мы задали размер и позицию, мы изменяем свойство anchorPoint. Его изменять не обязательно, я это сделала для того, чтобы было удобнее подогнать наше изображение под весь экран. Сейчас вы все поймете!
Как вы уже знаете, anchorPoint — это точка отсчета, и как я уже писала выше, позицию нашего Спрайта определяет точка по середине, так вот anchorPoint ее изменяет. Что бы лучше понять давайте рассмотрим картинку ниже:
Как видно на изображение нарисованы декартовы координаты. По умолчанию объекты SKSpriteNode имеют anchorPoint равный (0.5, 0.5), то есть по центру. В примере я изменила это свойство и задала его равным (0, 0), если мы опять посмотрим на изображение то увидим, что это точка находится в самом нижнем левом углу, а это значит что теперь наша начальная точка уже будет не посередине, а снизу слева. И теперь если скажут, что мы сдвинули такой то спрайт на 100px, это значит мы сдвинули его самую нижнюю и самую левую точку на 100px.
Далее мы задаем имя, это тоже очень важное свойство, его в данном случае писать было не обязательно, так как у нас пока что не происходит никаких действий.
Зачем нужно имя? По нему мы будем находить, определять и различать наши объекты. Будьте осторожны с выбором имени!.
После того, как мы задали необходимые нам свойства, мы обращаемся к нашей сцене и вызываем у нее метод или функцию:
Как я уже писала выше, наша сцена тоже является наследником от SKNode и поэтому мы добавляем один Node на другого.
Этот метод или функция работает так же, если вы захотите, скажем добавить один спрайт на другой.
Второй Спрайт с именем SimpleSprite, при его создании мы передаем два параметра это: Цвет и размер.
В качестве цвета мы передаем объект типа UIColor, как я уже писала выше мы можем передать и SKColor, это не будет ошибкой.
Еще один момент, это zPosition, как вы уже знаете zPosition — Определяет положение нашего Node относительно оси Z.
По умолчанию это свойство равно 0. Когда я создавала наши объекты, почему-то объект с именем SimpleSprite — второй объект, находился под остальными, видимо из-за особенностей его инициализации и поэтому я присвоила этому спрайту свойство zPosition равному 1.
Еще одно очень важное замечание: Node не находящийся на одной плоскости не могут взаимодействовать!
То есть, если у одного zPosition равен 0, а у другого 1 то они не будут контактировать!
Третий Спрайт, с именем ImageSprite, при его инициализации мы ему в качестве параметра передали имя нашей картинки.
Этот способ, конечно отличается от первого, где мы создавали объект типа SKTexture, но для обычной инициализации весьма подходит.
Objective-c
Swift
Ну что же, вы увидели визуально SKSpriteNode и увидели простейшие формы его инициализации, пока что этого хватит, давайте пойдем дальше и посмотрим еще один тип Node — это SKShapeNode.
SKShapeNode — Это составной Спрайт — объект, который может принимать практически любую форму. То есть он может быть почти любой геометрической фигурой: Окружность, Квадрат, Треугольник, Эллипс.
В строение он немного сложнее, чем SKSpriteNode так как здесь вся форма составная. Но он незаменим в построении сложных форм, без него очень тяжело управиться.
Ладно довольно слов перейдем к делу!
Давайте рассмотрим метод или функцию в которой(-ом) реализованы фигуры выше, полный код вы найдете ниже.
Итак, для удобства я закомментировала предыдущий метод или функцию, так что не пугайтесь, если вдруг не увидите предыдущих объектов.
Objective-c
Swift
У SKShapeNode есть несколько способов инициализации, их можно разделить на две группы:
Стандартная инициализация или инициализация с помощью объекта UIBezierPath.
Рассмотрим их по отдельности!
Стандартная инициализация
• В первую группу попадают объекты с простой инициализацией. Что это значит? Это например объекты при инициализации которых форма уже создана, и вам остается только задать ее параметры. Сейчас вы все поймете!
Ну что же, вы увидели некоторые методы или функции простой инициализации, из первой группы. Все конечно я перечислить не смогу, да и думаю вам будет интересней самим разобраться.
Инициализация с помощью объекта UIBezierPath
• Ко второй группе относятся объекты у которых инициализация проходит с помощью объекта UIBezierPath.
Что это значит? До сих пор мы рассматривали объекты, формы которых были известны и нам оставалось только передать параметр, но что если нам захочется например создать треугольник? Там нет такого метода инициализации! Для таких случаев нам и нужен объект типа UIBezierPath.
С помощью этого объекта, можно создать любую форму, а затем передать ее нашему SKShapeNode который после и отобразит ее.
•В интернете полно информации об объекте типа UIBezierPath, советую найти и почитать!
Я обещала объяснить для чего нужен параметр centered. Я не сделала этого раньше, только для того, чтобы вы поняли базовое строение объектов типа SKShapeNode. Так вот, параметр centered, если он принимает Положительное значение, тогда позиция объекта типа SKShapeNode будет считаться с середины. Помните, когда я вам объясняла про позицию объектов типа SKSpriteNode, я вам сказала, что их позиция отсчитывается с середины. Так вот, если параметр centered положителен, то и позиция данного объекта будет рассчитываться с середины.
Отсюда возникает вполне уместный вопрос, как тогда рассчитывается позиция простых объектов типа SKShapeNode, ведь не каждый же объект создается с параметром инициализации centered?
Давайте возьмем в качестве примера объект, который мы рассматривали раньше с именем Quad. Мы рассмотрели его инициализацию, которая начинается с передачи в качестве параметра функции с именем (CGRectMake). Как я уже писала раньше эта функция возвращает позицию и размер.
В ней первые два параметра определяют ее origin позицию (x, y), а остальные ширину и длину соответственно.
Если с шириной и длиной понятно, то с origin немного мутно. Дело в том, что объекты типа SKShapeNode используют систему исчисление позиции немного иначе, чем объекты типа SKSpriteNode у которых отсчет позиции начинается с середины. Давайте посмотрим на изображение выше: итак, при инициализации нашего объекта с именем Quad мы передали ему в качестве параметра функцию CGRectMake(0, 0, 50, 50). Как мы видим на изображении origin равен (0, 0) из изображение видно что отсчет позиции начинается с верхнего левого угла.
Теперь давайте изменим наш origin и передадим нашу прежнею функцию, но уже с другими координатами.
И что мы видим? Наш квадрат при инициализации имеет начальную точку отсчета позиции с середины.
Другими словами, наш объект теперь имеет такую же систему отсчета, как и объекты SKSpriteNode, у которых отсчет позиции начинается с середины.
• Выходит то, что origin играет роль якоря немного похожего на тот, что мы видели раньше у объектов типа SKSpriteNode.
У вас может возникнуть вопрос, почему координаты origin я указала равными (-25, -25)?
• Дело в том, что размер нашего квадрата равен (50, 50), а это значит, что его средняя точка равна (50/2, 50/2), то есть половина ширины и длины!
На первом изображении мы видим, что у объектов типа SKShapeNode начальная точка равна (0, 0), поэтому его позиция определяется с верхнего левого угла,
но если мы сдвинем его на (-25, -25), то его начальная точка станет посередине и отсчет позиции будет начинаться по середине.
• Теперь если скажут, что мы сдвинули такой то спрайт на 100px, это значит мы сдвинули его среднюю точку на 100px.
Ну что же, я думаю вам понравился SKShapeNode. Как видите в нем нет ничего трудного, но если вы не поняли какие-то моменты, то это не страшно, далее во время демонстрации физики вы все поймете. Небольшой совет: что бы лучше понять этот Спрайт -объект, изучите получше UIBezierPath и все время практикуйтесь!
Objective-c
Swift
SKLabelNode — Это Спрайт, который позволяет выводить текст на нашей сцене. Причем текст можно выводить с параметрами:
Размер шрифта, цвет шрифта, имя шрифта.
Настраивать выравнивание шрифта как по вертикали, так и по горизонтали. Впрочем вы сейчас все увидите сами.
Objective-c
Swift
На изображении выше мы видим 2 спрайта. Давайте для начала разберем их способы создания.
Первый Спрайт с именем First. При его инициализации, в качестве параметра мы передаем имя Шрифта. Спрайт типа SKLabelNode поддерживает почти все основные шрифты. В данном случае я передаю шрифт с именем Chalkduster. Далее мы настраиваем все основные свойства:
После настройки этих свойств, мы добавляем наш объект на нашу сцену. Результат вы можете увидеть на изображении выше.
Второй объект имеет имя Second. При его инициализации мы в качестве параметра передаем текст который хотим отобразить, а после настраиваем все остальные свойства. Его основные свойства вы уже знаете, так как они почти идентичны предыдущему Спрайту, поэтому не будем терять время и пойдем дальше.
Objective-c
Swift
Как видите SKLabelNode очень прост в использование, я бы даже сказала очень прост!
Ну что же друзья! Вот мы и дошли до почти что самой главной части статьи, это — Физика. До этого мы учились создавать объекты — Спрайты. Мы изучили нашу сцену, посмотрели как визуально выглядят наши объекты и это ХОРОШО! Но без физики, это всего навсего изображение! Физика придает «жизнь» нашим Спрайтам и в этой главе я бы хотела по подробнее о ней вам рассказать. И начнем мы с SKPhysicsBody
SKPhysicsBody — Это по сути тело нашего объекта. Именно оно отвечает за все основные физические характеристики наших объектов, именно оно придает им физическую форму, именно оно отвечает за такие характеристики как: Трение, упругость, сопротивление, массу, скорость, гравитацию.
Давайте поподробнее познакомимся с ним и начнем конечно с его свойств, методов или функций.
Свойство
Методы или функции инициализации
Методы или функции
Итак, выше вы видите все методы или функции и свойства объекта SKPhysicsBody. Как видите их у него немного.
Сразу скажу, некоторые пункты выше могут вам показаться: непонятными или сложными для понимания. Не волнуйтесь, если чего-то не поняли. Дальше мы все несколько раз рассмотрим и поэкспериментируем со всем несколько раз!
Ладно, давайте продолжим, но перед тем как приступать к реализации, мы должны кое-что сделать!
Кроме того, нужно еще добавить одну строчку в метод или функцию SceneSetting
Физику тел можно разделить на 3 категории:
1) Динамические — Тела, которые могут изменять свою позицию.
2) Статические — Тела, которые не могут изменять свою позицию.
3) EDGE — Своеобразные границы.
Динамические
Динамические тела лучше всего использовать тогда, когда вы хотите что то двигать на сцене или сталкивать. Это могут быть: снаряды, летательные объекты, все возможные анимированные персонажи. Они имеют массу и объем, они могут быть затронутыми силами гравитации, могут принимать основные физические свойства.
Статические
Статические тела. У них все тоже самое, как и у динамических, главное отличие в том, что они не могут двигаться! Однако с ними по прежнему могут сталкиваться и взаимодействовать другие объекты. Лучше всего их использовать, например для каких то опор или стен. Все то, что занимает много места.
EDGE
EDGE — это по сути не Физическое тело, это некие границы с которыми и происходит все взаимодействие. Они не имеет массы или объема, и не могут двигаться!
EDGE используется для предоставления полой части внутри объекта или для каких-нибудь невидимых границ.
Давайте посмотрим на изображение выше. Мы видим пять объектов. Я специально выбрала разные типы объектов, чтобы вы увидели разницу между ними.
Ну что же, давайте рассмотрим их по подробнее!
Objective-c
Swift
RectanglePhysics
Первый Объект имеет имя RectanglePhysics. Вы уже знаете, что делают его основные свойства, поэтому я не буду останавливаться на них и перейду непосредственно к новым. Как можно заметить, в самом начале мы обращаемся к свойству physicsBody нашего объекта и присваиваем ему объект типа SKPhysicsBody. Это нужно для того, чтобы придать физическое тело нашему Спрайту.
Если вы внимательно изучили методы или функции SKPhysicsBody, о которых я писала выше, то вы можете увидеть, что объект который мы передаем в качестве свойства, инициализируется с вызова метода bodyWithRectangleOfSize или функции rectangleOfSize и при его инициализации мы передаем размер нашего Спрайта, и уже по нему и строится наше физическое тело.
Тут есть один важный момент, о котором стоит упомянуть!
Любые касание или соприкосновение происходят не с самим спрайтом, а с его физическим телом!
После установке нашего физического тела, мы устанавливаем еще одно свойство, это dynamic.
Как я писала выше, оно отвечает за динамичность объектов. Здесь мы ему присваиваем отрицательное значение, это значит что теперь наш объект не сможет двигаться, что нам идеально подходит в качестве опорной поверхности!
CirclePhysics
TexturePhysics
TrianglePhysics
LabelPhysics
Сравнение Некоторых Физических Свойств
И так друзья, мы с вами научились создавать физические тела для наших объектов и теперь пришло время посмотреть на физические свойства. На видео ниже, мы видим сравнение нескольких физических свойств. Как мы видим в самом начале падают два шарика одинакового размера и с одинаковой высоты. При падение один из них отскакивает, а другой нет. Так же мы видим два квадрата тоже одинакового размера. Они тоже падают с одинаковой высоты, но уже на наклонную поверхность. Один из них скользит и падает, а другой наоборот сразу останавливается. Все это демонстрация некоторых физических свойств. Давайте лучше перейдем непосредственно к коду!
И так давайте посмотрим на наш код!
Objective-c
Swift
В самом начале я создаю два объекта типа SKShapeNode, с именами Opora1 и Opora2. На видео, это наклоненные объекты с зеленым и красным цветом соответственно. В их создании нет ничего необычного кроме свойства zRotation о котором я писала выше, но до сих пор мы его не использовали. Как мы помним:
Свойство zRotation принимает свои значение в радианах! И поэтому, что бы повернуть объект на определенный угол нам этот угол надо сначала перевести в радианы. Делается это очень просто:
Objective-c
Swift
Как видите, в повороте объектов нет ничего сложного!
Далее я создаю еще один объект с именем Opora3, он тот что желтого цвета в самом низу.В его создании тоже нет ничего необычного, так что мы можем двигаться дальше. А далее, у нас идут еще два объекта — окружности с именами Circle1 и Circle2. По своему строению они очень схожи между собой, но есть различия в физических свойствах. Их физическая форма абсолютна идентична, а вот свойство различаются:
Свойство с именем restitution как мы помним определяет:
Так вот, в объекте с именем Circle1 я задала его значение равным «0», а в другом объекте с именем Circle2 оно установлено на значение «1». Изменение значение этого свойства, влияет на поведение объекта при столкновение с другими объектами. Как мы можем наблюдать на видео, один из двух шаров при падение отскакивает, а другой напротив лежит неподвижно. Все это результат действие этого свойства.
Еще один пример мы можем наблюдать в двух других объектах с именами Quad1 и Quad2. Они имеют квадратную форму и идентичны во всем, кроме физического свойства с именем friction.
У одного объекта его значение равно «1», у другого «0.1» и как результат: один квадрат почти не скользит по поверхности, а другой напротив проскользив всю поверхность падает вниз.
Полный код нашего проекта
Objective-c
Swift
Как видите физические характеристики играют огромную роль, с их помощью объекты обретают форму и меняют свои свойства. Эти характеристики определяют: как тело движется, как на него влияют силы в симуляции и как оно реагирует на столкновения с другими телами. Каждый раз, когда сцена рассчитывает новый кадр анимации, она имитирует эффекты сил и столкновений спрайтов с физическими телами. 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, который оказал мне честь находиться среди вас!
Итак, что же такое 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
Swift
а затем передаем в качестве параметра объект нашей сцены, теперь скомпилируем и «вуаля» наша сцена готова! |
Ниже я привела полный код 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
Swift
Видите, форма уже готова и нам остается просто передать параметр по которому и будет создан наш объект, в данном случае это радиус. Что происходит дальше, а далее мы задаем позицию нашего объекта, я думаю с этим проблем не будет. После мы задаем свойство lineWidth, оно отвечает за ширину контура (Линий), чем больше число, тем шире контур. Дальше задаем два цветовых свойство: strokeColor и fillColor. • strokeColor — Задает цвет контура (цвет линий формы). • fillColor — задает цвет внутренности формы. С первым свойством все понятно, со вторым небольшая загвоздка.
После того, как мы настроили свойство цвета, мы задаем имя и после добавляем наш объект на нашу сцену. |
Quad
Objective-c
Swift
//Создаем наш 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).
Я думаю большинство из вас знакомы с ней, если нет, то знайте: она возвращает координаты и размер прямоугольника. Первые два параметра это: x — Позиция относительно оси X, y — Позиция относительно оси Y. Остальные два это Ширина и Длина. |
Ellips
Objective-c
Swift
// Создаем наш 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
Swift
// Создаем и инициализируем объект типа 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
Swift
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
Swift
Оно показывает физическое тело, если таковое существует у объекта. Это очень удобно, мы видим физическое тело и можем легче с ним работать! |
Кроме того, нужно еще добавить одну строчку в метод или функцию SceneSetting
Это нужно сделать для того, чтобы настроить силу гравитацию нашей сцены. Как она работает я вам расскажу чуть позже. Objective-c
Swift
|
Физику тел можно разделить на 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
В этой формуле первое число 10, оно и есть угол на который мы совершаем поворот. Если вы например хотите повернуть скажем на 60 градусов, в таком случае вам придется написать так:
А далее мы присваиваем значение это переменной к свойству zRotation:
|
Swift
Мы создаем let переменную с именем RotateAngle
Тут все тоже самое что и в Objective-c, кроме того что нужно нашу переменную перевести в тип float
|
Как видите, в повороте объектов нет ничего сложного!
Далее я создаю еще один объект с именем 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, который оказал мне честь находиться среди вас!