Pull to refresh

DreemChest: Цепная реакция

Reading time6 min
Views1.6K

О переводе


Привет всем. Я решил заняться переводом документации по игровому движку DreemChest, не знаю, делал ли это кто-то до меня, но надеюсь, что нет.
Почему я решил начать именно с перевода «Цепной реакции»? Ответ прост: это самый интересный урок с одновременно практической частью из всей документации.
Ну что ж, начнем.

Chain Reaction


В данном уроке будет представлен пример простой игры «Цепная реакция»(Название соответствует жанру). Смысл игры в том, что игроку нужно уничтожать постоянно появляющиеся объекты нажатием на них мышью, как можно быстрее.
Основа

Запустите движок и создайте новый проект. Когда он будет запущен вы увидите диалоговое окно, которое вам предложит создать новый проект или же загрузить уже созданный. Введите имя проекта и нажмите на кнопку «Greate».

image
По стандарту редактор имеет лишь одно разрешение экрана игры (320х480), но вы всегда можете добавить свое. Давайте зададим нашему проекту новое разрешение, к примеру 640х480, для этого откройте выдвижное меню (Ну честно, не знал, как правильно перевести, поправьте, если что), которое указано на изображении ниже в основной панеле инструментов и выберите опцию «Edit».
image
Теперь вы можете видеть только-что появившееся диалоговое окно. Чтобы добавить новое разрешение введите ширину и высоту, в первое и второе окно редактирование, а после нажмите на кнопку «Add». Чтобы закрыть диалоговое окно нажмите на кнопку «Close», чтобы удалить разрешение кликните по нему, тем самым выбрав его и нажмите на кнопку «Remove».
image
Теперь, когда новое разрешение добавлено, вы можете его выбрать в выдвижном меню, если вы выберите иное разрешение, границы сцены будут изменены.
image
Добавление ресурсов

Стандартный проект вмещает в себя всего лишь один htcehc с именем «root», который является единственным игровым уровнем(сценой). Давайте теперь добавим несколько спрайтов, которые в дальнейшем будем использовать в игре.
Чтобы импортировать ресурс кликнем ПКМ(Правая клавиша мыши) на панеле «Assest» и в только что появившемся меню выберем «Import Assest». Мы видим появившееся окно, через которое мы будем выбирать и добавлять наши спрайты. Давайте добавим 2 спрайта «Enemy.png»(«Enemy») и «Bullet.png»(«Bullet»).
Панель «Assest» находиться в правом нижнем углу, если вы ее не нашли потому-что ее нет, в ы всегда можете добавить ее через «View»->«Assests»
image
Панель «Assest» позволяет создавать ресурсы(script, shape, stage object и тд.), а так же импортировать уже готовые ресурсы(Спрайты, flash меню и звуки\музыку). Чтобы сделать прототип будущей игры нам понадобиться прописать игровую логику, давайте начнем с создания скрипта. ПКМ на панели «Asssest» и в только что появившемся меню выберите «Create»->«Script».
image
Прежде, чем писать скрипт давайте выберем «bullet» и «enemy» ресурсы. Загруженное нами изображение может быть перетянуто на нашу сцену, но оно не может быть вызвано через скрипт, если данный скрипт не является основным классом объекта. Чтобы мы могли создавать объект из скрипта, давайте зададим классу нашего объекта уникальное имя, для «bullet» это будет «bmpBullet», а для «enemy» «bmpEnemy», имя класса объекта мы можем всегда сменить на другое или же записать его впервые выбрав объект на панели «Assest», а после на панели «Properties» в строке «Class» ввести имя основного класса объекта.
Класс нашего ресурса может быть вызван в любом другом ресурсе, или же присоединен к другому объекту, но на данный момент нас интересует работа со скриптами.
image
Начнем писать наш скрипт. Прототип нашего скрипта будет вмещать в себя 1 класс и 8 методов.
Main — Метод вызываемый при старте игры. Каждый основной класс должен содержать этот метод.
spawnEnemies — Создает определенное количество объектов «Enemy».
spawnEnemy — Создает один объект «Enemy» на сцене с встроенным спрайтом.
shoot — Создает 4 пули на определенных координатах.
spawnBullet — Создает один объект «Bullet» на сцене с встроенным спрайтом.
onUpdate — Обновляет объекты(Координаты, состояние и тд.).
updateBullet — Позволяет объектам «Bullet» передвигаться по сцене и проверяет столкновения с объектами «Enemy».
updateEnemy — Позволяет объектам «Enemy» передвигаться по сцене.

— Declare the Main class, derived from Graphics.
— To be able to make this the starting class, it must be a child
— of the Graphics class.
class «Main»( Graphics )

— Constants
Main.Enemies = 50
Main.EnemySpeed = 100
Main.BulletSpeed = 500
Main.EnemyTag = 1

— main
— Entry point which assigns message listeners and creates enemies
function Main:main()

— Add handlers which react to clicks and updates
Stage.attachListener( TapEvent.Up, function( e ) self:shoot( e.x, e.y ) end )
Stage.attachListener( GenericEvent.Update, self )

— Rectangle which sets the window size
self.screen = Rect.new( 0, 0, Stage.getWidth(), Stage.getHeight() )

— Set enemies loose
self:spawnEnemies( Main.Enemies )
end

— spawnEnemies
function Main:spawnEnemies( count )
for i = 1, count do
self:spawnEnemy( Color.new( 0.0, 1.0, 0.0, 1.0 ) )
end
end

— spawnEnemy
function Main:spawnEnemy( color )
— Create an instance of the bmpEnemy class. It's the same identifier
— assigned to the enemy image in step 7.
local e = bmpEnemy.new()

e.relX = math.random()
e.relY = math.random()
e.dir = Vec2.randDirection()
e.color = color
e.speed = Main.EnemySpeed

— Each stage object can be given a tag. We use it to check for
— collisions between bullets and enemies.
e.tag = Main.EnemyTag

— Add the created object to the stage
self:attach( e )
end

— shoot
function Main:shoot( x, y )
local color = Color.new( 1.0, 0.0, 0.0, 1.0 )
self:spawnBullet( x, y, -1, 0, color )
self:spawnBullet( x, y, 1, 0, color )
self:spawnBullet( x, y, 0, 1, color )
self:spawnBullet( x, y, 0, -1, color )
end

— spawnBullet
— The same thing happens here as in the spawnEnemy method
function Main:spawnBullet( x, y, dx, dy, color )
local bullet = bmpBullet.new()
bullet.x = x
bullet.y = y
bullet.color = color
bullet.speed = Main.BulletSpeed
bullet.dir = Vec2.new( dx, dy )

self:attach( bullet )
end

— onUpdate
— Update message handler, called every frame.
function Main:onUpdate( e )
local i = 0
local n = self.totalChildren

— Scan the stage objects list and update them. We use objects'
— tag property in this method, to know which object to
— process: the enemy or bullet.
while i < n do
local child = self:getChild( i )

if child.tag == Main.EnemyTag then
self:updateEnemy( e.dt, child )
else
self:updateBullet( e.dt, child )
end

i = i + 1
end
end

— updateBullet
— Bullet updating method. We change its position every frame according
— to speed.
function Main:updateBullet( dt, bullet )

— We use the previously created Rect class object here, to
— determine if the bullet has flown off-screen or not.
if not self.screen:pointInside( bullet.x, bullet.y ) then
— Each stage object has a release method, which removes it from the stage
— and labels it as unneeded. After a while, memory used by this object
— will be freed.
bullet:release()
return
end

— Move the bullet
bullet.x = bullet.x + bullet.dir.x * bullet.speed * dt
bullet.y = bullet.y + bullet.dir.y * bullet.speed * dt

— Checking for collisions between a bullet and enemies is done like this:
— we sort objects relative to the bullet's location, with a radius equal to
— the bullet's size, and filter them using the tag property. The
— handler will therefore only be called for objects whose
— tag property is equal to Main.EnemyTag.
Stage.forEachInRadius( self, Main.EnemyTag, bullet.x, bullet.y, bullet.width,
function( object, distance )

— We found the appropriate object, which
— means a collision occurred. Shoot four
— more bullets.
self:shoot( object.x, object.y )

— Delete the object and bullet
object:release()
bullet:release()
end )
end

— updateEnemy
— Enemy updating method. Simply move it on the screen. Wrap it around
— to the other side of the screen if it goes out of bounds.
function Main:updateEnemy( dt, enemy )
enemy.x = enemy.x + enemy.dir.x * enemy.speed * dt
enemy.y = enemy.y + enemy.dir.y * enemy.speed * dt

local w = Stage.getWidth()
local h = Stage.getHeight()

if enemy.x < 0 then enemy.x = enemy.x + w
elseif enemy.x > w then enemy.x = enemy.x — w
end

if enemy.y < 0 then enemy.y = enemy.y + h
elseif enemy.y > h then enemy.y = enemy.y — h
end
end


Скрипт прототипа нашей игры готов. Но почему же при запуске игры ничего не происходит (Чтобы запустить игру нужно нажать кнопку «Start» на основной панели инструментов)? Это потому-что наш скрипт не выбран стандартным при запуске игры. Чтобы это пофиксить нужно открыть выпадающее меню рядом с кнопкой «Start» и выбрать наш скрипт.
image
Тестирование и экспорт

Функция запуска проекта была сделана для того, чтобы сэкономить время, которое мы тратим на компиляцию, ради того, чтобы протестировать, что же у нас вышло. Чтобы приостановить запущенную в редакторе игру нужно нажать на кнопку «Stop», которая при запуске игры заменяет кнопку «Start». Если вы редактировали проект и запустили его, но ничего не изменилось, то вы забыли сохранить его(Ctrl+S ), только после сохранения изменений они станут видны при запуске игры.
image
Давай запустим нашу игру.
image
Чтобы отделить наш проект от движка и экспортировать его на определенную платформу нужно выбрать в выпадающем меню «File» элемент «Export» («File»->«Export»). Там же вы можете настроить множество параметров экспортирования. (P.S Экспортирование происходит дольше, чем простой запуск проекта и при чем намного дольше).image
Tags:
Hubs:
+3
Comments2

Articles