Создание игры для iOS. Часть 2

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

Итак, начнем с git:

Технология нужна для контролирования различных версий проекта. Например, если у вас все работало, а затем вы внесли ошибочное изменение, git позволит откатиться на предыдущие версии проекта. Другой пример использования: вы хотите добавить в команду человека, но вы не хотите интегрировать его работу в проект, пока не убедитесь, что все сделано правильно - тоже пожалуйста, git все это умеет.

Так как все это подключить к нашему проекту?

Для этого открываем Terminal, он находится в Приложениях и переходим в директорию с нашим проектом, в моем случае

cd Desktop/Grasp

Затем нам необходимо инициализировать репозиторий:

git init

Добавляем в него все существующие файлы

git add .

(Точка через пробел, это важно!)

Сохраняем все это с комментарием

git commit -m “Initialization

Проверьте себя:

 

Если хотите более подробно узнать про git и ее возможности, прочитайте эту статью: goo.gl/67SgBu

 

Итак, теперь мы можем управлять проектами прямо из Xcode во вкладке Source Control

 

Перейдем же к самому проекту. Для начала добавим изменений в наш файл Useful.swift

extension CGF {
    static func - (l: CGF, r: Double) -> CGF { return l - CGF(r) }
    static func + (l: CGF, r: Double) -> CGF { return l + CGF(r) }
    static func * (l: CGF, r: Double) -> CGF { return l * CGF(r) }
    static func / (l: CGF, r: Double) -> CGF { return l / CGF(r) }
    static func - (l: CGF, r: Int) -> CGF { return l - CGF(r) }
    static func + (l: CGF, r: Int) -> CGF { return l + CGF(r) }
    static func * (l: CGF, r: Int) -> CGF { return l * CGF(r) }
    static func / (l: CGF, r: Int) -> CGF { return l / CGF(r) }
}

 
extension Int {
    static func - (l: Int, r: CGF) -> CGF { return CGF(l) - r }
    static func + (l: Int, r: CGF) -> CGF { return CGF(l) + r }
    static func * (l: Int, r: CGF) -> CGF { return CGF(l) * r }
    static func / (l: Int, r: CGF) -> CGF { return CGF(l) / r }
}

 
extension Double {
    static func - (l: Double, r: CGF) -> CGF { return CGF(l) - r }
    static func + (l: Double, r: CGF) -> CGF { return CGF(l) + r }
    static func * (l: Double, r: CGF) -> CGF { return CGF(l) * r }
    static func / (l: Double, r: CGF) -> CGF { return CGF(l) / r }
}

Эти расширения позволяют сильно уменьшить количество кода, повышая его читабельность, например:

var d : Double = 10.0
var c : CGFloat = 7.0
var i : Int = 11

// Без расширений:

var tmp : CGFloat = (CGF(d) + CGF(i)) * CGF(i) + CGF(d)

//  С расширениями:

var tmp: CGFloat = (d + i) * i + d

Как видите, разница существенная. 

Теперь добавим файл Constants.swift рядом с файлом Useful.swift, в него мы будем записывать константы в течение всего проекта, на данный момент нам необходимы вот эти:

let MENU_HEIGHT = CGF(70.0)

А также переменная размера экрана, инициализируемая при запуске приложения:

var screen : CGSize = CGSize()

Чтобы она проинициализировалась сразу при запуске, в файле AppDelegate.swift в первой функции необходимо прописать следующу строчку:

screen = UIScreen.main.bounds.size

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

Сейчас немного порядка и иерархии:

В папке Scenes создаем файл FieldScene.swift

На том же уровне, что и папка Design, создаем папку Structure, в ней папку Field, а в ней файл Marking.swift, в котором и создаем класс разметки:

import Foundation
import UIKit
import SpriteKit

// Эти три строчки отныне пишем в каждом .swift файле

class Marking {
    var frame: (CGF, CGF) = (0, 0) // left, down
    var side: CGF = CGF()

    init() {}

    init(size: CGSize, ratio: (Int, Int)) {
// предподсчитываем стороны узлов, если бы не было адаптивной разметки
        let tmp_x = (size.width - MIN_SPACE * 2) / ratio.0
        let tmp_y = (size.height - MIN_SPACE * 2 - MENU_HEIGHT - STATUS_BAR_HEIGHT) / ratio.1

// выбираем меньшую из них, так как стороны узла соотносятся, как 1:1 и они все должны поместиться на экране
        self.side = min(tmp_x, tmp_y)
        self.frame = (
            (size.width - self.side * ratio.0) / 2,
            MENU_HEIGHT + ((size.height - STATUS_BAR_HEIGHT - MENU_HEIGHT - self.side * ratio.1) / 2)
        )
    }
}

Что ж, давайте теперь взглянем на то, что получилось - создадим макет нашего поля:

В файле FieldScene.swift пишем следующее:

class FieldScene: SKScene {
    final var ratio : (Int, Int) = (5, 9)
    var mark : Marking = Marking()

    override init(size: CGSize) {
        super.init(size: size)
        self.mark = Marking(size: size, ratio: self.ratio)
        self.backgroundColor = UIC.white

// макет статус бара let sb = SKSN(color: UIC.blue, size: CGSize(width: screen.width, height: STATUS_BAR_HEIGHT)) sb.anchorPoint = CGPoint(x: 0, y: 0) sb.position = CGPoint(x: 0, y: screen.height - STATUS_BAR_HEIGHT) self.addChild(sb) // макет самой сетки узлов for var i in 0..<ratio.1 { for var j in 0..<ratio.0 { let sn = SKSN( color: UIC.red, size: CGSize(width: self.mark.side - 5, height: self.mark.side - 5)) sn.position.x = mark.frame.0 + j * mark.side + 2.5 sn.position.y = mark.frame.1 + i * mark.side + 2.5 sn.anchorPoint = CGPoint(x: 0, y: 0) self.addChild(sn) } } // макет меню let menu = SKSN(color: UIC.darkGray, size: CGSize(width: screen.width, height: MENU_HEIGHT)) menu.position = CGPoint(x: 0, y: 0) menu.anchorPoint = CGPoint(x: 0, y: 0) self.addChild(menu) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } }

 А теперь, чтобы посмотреть на результат, нужно запустить эту сцену с помощью ViewController’a, как вы уже догадались открываем файл GameViewController.swift и пишем там вот такое заклинание:

class GameViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        if let view = self.view as! SKView? {
            let scene = FieldScene(size: UIScreen.main.bounds.size)
            view.presentScene(scene)
        }
    }
}

 Нажимаем кнопку запустить и наблюдаем, как правильно все разметилось. Кстати, удобнее всего использовать для тестов в симуляторе компактные модели, например, se/6/6s и другие  - они не занимают много места на экране

 Теперь сделаем commit, все что для этого нужно -> Source Control -> Commit, пишем комментарий, например, Blog -1, Разметка

Продолжение следует 15 ноября!  Следите за обновлениями блога

Подписаться на обновления