В этой статье мне хотелось бы поделиться опытом, который я получил во время разработки моей первой игры под iOS. После анонса языка Swift идея разработки под iOS не переставала покидать моя голову. Так как я уже достаточно давно на тот момент работал веб-разработчиком, а Swift оказался очень похож на Javascript, я решил приступить к осуществелению своей затеи.
И вот, имея в наличии достаточно времени, и являясь поклонником казуальных игр, я решил сделать свою игру в этом жанре. Прототип был быстро cделан на Javascript c использованием либы
Raphaeljs для комфортной работы с графикой.
Идея и правила были придуманы буквально на колене и заключаются в следующем:
- Каждый раунд игроку даются 3 полимино
- Игрок должен расположить их на поле, стремясь к максимальной упорядоченности, заключающейся в отстутсвии гэпов между фигурами
- При сборе линии, неважно горизонтальной или вертикальной, игрок получает определённое количество очков, умножающееся на коэффициент комбо
- Игра завершается в тот момент, когда из фигур, представленных на выбор, ни одна не может быть расположена на игровом поле
Реализация на JS заняла около двух дней. Еще до разработки я планировал, что с помощью IONIC или Phonegap легко все перекомпилю в приложение для IOS, но, как я и предполагал, получилось очень плохо, так как код на JS, вставленный в WebView, работал с лагами и тормозами, и я решил, в итоге, все переделать на Swift. И понеслось…
Основная трудность, с которой я столкнулся, заключалась в определении момента заверешения игры. Для её разрешения был составлен алгоритм, который последовательно пробегал по блокам, расставленным по карте, проверяя возможность постановки фигуры, начиная с этого блока.
алгоритмfunc tryFigureOnMap(figure : Figure) -> Bool {
let rect_map = figures_for_test_inited.maps[figure.type]!
let except_first_element_width = figure.w
let start_width_offset = figure.start_w_offset == nil ? 0 : figure.start_w_offset
let except_first_element_height = figure.h
var rect_figures = Array<Array<Int»()
var rect_offsets = Array<Array<Int»()
var num = Int()
var direction : Bool = except_first_element_width > except_first_element_height
for var c = 0; c < map_size; c++ {
for var r = 0; r < map_size; r++ {
num = c * map_size + r
if rectanglesArray[num].type == "default" {
var counter = 0
var array_helpers = Array<Int>()
if r < map_size - except_first_element_width && c < map_size - except_first_element_height && r >= start_width_offset {
for (index, i) in enumerate(rect_map) {
let need_num = num + i
if let q = find(clearNumbers, need_num) {
counter++
array_helpers.append(need_num)
} else {
break
}
}
if counter == rect_map.count {
return true
}
}
}
}
}
return false
}
Проблема заключалась в том, что для некоторых фигур их началом считался верхний правый угол, тогда как для остальных фигур отправной точкой считался левый верхний угол. Для решения этой проблемы в мапу этой фигуры, помимо конечного отступа, добавлялся ещё и начальный отступ, обозначающий, что начало этой фигуры учитывало её сдвиг.
Пример:
Для фигуры пентамино «L» (на картинке голубая) начальной точкой считается левый верхний угол, соответсвенно её начальный отступ равен нулю, а конечный равен 2, а для пентамино «обратная L» начальный отступ равен 2, а начальный — нулю, соответсвенно, её обход начинается с правого верхнего угла, а заканчивается левым.
Мапы фигур, использующиеся для проверки:
maps["L_inv"] = [0, 10, 20, 19, 18]
maps["L"] = [0, 10, 20, 21, 22]
А сама мапа фигуры, использовавшаяся для отрисовки, выглядела так:
self.maps.append([
"map" : [
[ "x" : 0.5, "y" : -1.5 ],
[ "x" : 0.5, "y" : -0.5 ],
[ "x" : -1.5, "y" : 0.5], [ "x" : -0.5, "y" : 0.5], [ "x" : 0.5, "y" : 0.5]
],
"color" : UIColor(rgb: 0x41CE57),
"w" : 0,
"h" : 2,
"start_w" : 2,
"type" : "bigL_inv"
])
Саму игру можно скачать в appstore, она бесплатная.
Игра.
В следующей статье я расскажу о прдвижении игры и проблемах, связанных с ним.
комментарии (1)