Глава II в серията от уроци за това как да създадете игра от нулата с TypeScript и приложни програмни интерфейси на браузъра
Добре дошъл обратно! Това е поредицата от статии, в които обсъждаме как да създадем проста походова игра с TypeScript и собствени API на браузъра! Глава II е посветена на изграждането на игрови цикъл за тази игра, други глави са достъпни тук:
- "Въведение"
- Глава I. Система от компоненти на обекти
- Глава II. Цикъл на играта (Част 1, Част 2)
- Глава III. Решетка за рисуване (Част 1, Част 2, Част 3, Част 4, Част 5)
- Глава IV. Кораби (Част 1, Част 2, Част 3, Част 4)
- Глава V. Система за въвеждане (Част 1, Част 2, Част 3)
- Глава VI. Намиране на пътя и движение
- Глава VII. Държавна машина
- Глава VIII. Система за атака: здраве и щети
- Глава IX. Печелене и загуба на играта
- Глава X. Вражески AI
„Последния път“ завършваме с въпроса: как можем да стартираме Game Loop, без да усложняваме конструктора. Един от подходите, които можем да предприемем, е да го направим „буден“.
Чувствайте се свободни да превключите към клона
game-loop-1
на хранилище. Той съдържа работния резултат от предишните публикации и е чудесна отправна точка за тази.
Съдържание
- В
- Существо се пробужда
- Стартиране на цикъла
- Вложен обект
- Тестване на игровия обект
- Заключение
В
Ако си спомняте, постигнахме значителен напредък при настройването на обекта game
. Ние дори подготвихме неговия Update
метод, който рекурсивно актуализира всички компоненти на Game
. Това обаче не е от голяма полза, тъй като никой не прави първоначално повикване, за да започне цикъла!
Също така установихме, че е възможно да стартираме цикъла с помощта на конструктор:
По-добър подход би бил да се осигури специален метод за инициализация. Този метод може да стартира цикъла и да направи много други настройки, докато конструкторът остава слаб. Можем да наричаме този метод както желаем, например Init
или Awake
. Ще използвам най-новото, за да имитирам Unity3d
API.
Существо се пробужда
Всички обекти и компоненти вече ще станат „събудени“. Тоест: те ще имат публичния Awake
метод.
Имайте предвид, че този метод на жизнения цикъл няма силна връзка с конструктор. Един обект може да бъде конструиран само един, докато
Awake
може да бъде изпълнен многократно за продължителността на живота на обекта. Може да „заспи“ и след това да се събуди отново. Един от типичните примери е повторно използване на обекти, за да се избегнат разходите за разпределение на паметта за създаване на обекта (да се чете: изпълняващ конструктор).
Изкушаващо е просто да добавите нов метод към абстрахиране на Entity
и интерфейс IComponent
. Но точно както Update
, Awake
може да бъде част от други елементи на нашата игра, не само ECS. По-разумно е да създадете специален IAwake
интерфейс и след това да го внедрите.
Интерфейсът е удивително прост. Дори не очакваме да бъдат предадени конкретни данни:
Остава само да го внедрим с IComponent
:
и Entity
:
Имайте предвид, че този обект събужда всичките си компоненти веднага щом се събуди. Така е, тъй като
Update,
е поведение по подразбиране. Отделни субекти са свободни да го разширят или променят, ако е необходимо.
Освен това, тъй като така или иначе сме в този квартал, нека да направим малко домакинство. Ще се присъединя към Awake and Update под един помощен модул и ще го нарека „жизнен цикъл“. Ако имаме нужда от още подобни събития, можем да ги добавим тук:
Сега можем да изтрием остарелите update.h.ts
и awake.h.ts
. Освен това поддържайте необходимите файлове за варели, за да реекспортирате правилно този модул:
И след това актуализирайте потребителите на тези интерфейси:
Ах! Но счупихме тестовете! Това е така, защото не изпълняваме обещанието: „всеки обект и компонент трябва да има Awake
метод“. И присмехулниците явно го нямат. Нека поправим това много бързо:
И определено трябва да тестваме Awake
. Ще използвам същия подход като този, който използвахме, докато тествахме Update
: първо шпионирам съответните методи, добавям фалшиви компоненти към фалшив Entity, изпълнявам метода Awake на обекта и ще очаквам тези на Component да бъдат извикани също:
Ако стартирате npm start
в този момент, вашият код трябва да се компилира без грешки. Ако стартирате тестове от npm t
, всички те също трябва да са успешни:
Стартиране на цикъла
С всичко това на място можем да се възползваме от нов метод на жизнения цикъл в обекта Game:
Веднага щом играта и всички нейни компоненти се събудят, започваме цикъла на играта:
Едно малко подобрение: искам да се уверя, че цикълът на играта не започва, преди всички компоненти и дъщерни обекти да се събудят. Правя го, като забавям актуализацията до следващия кадър:
Вложен обект
Казах ли „дъщерни обекти?“. Точно така: Играта е root Entity, но не е единствената. Това е много удобен начин да имате обекти, организирани в йерархията. Освен всичко друго, това ни позволява да актуализираме всички тези деца от играта, като извикаме Update
на всяко едно от тях.
Ще започнем да добавяме дъщерни обекти в следващата глава, но засега нека просто да настроим етап и да се уверим, че те ще бъдат актуализирани.
Добавям публично свойство, което съдържа масив от всички дъщерни обекти:
Като следим всички дъщерни обекти, можем лесно да извикаме всички методи на жизнения цикъл на тях. Освен това някои от тях (или дори всички!) може да имат свои деца и да извикат Awake/Update и на тях.
Първо, трябва да събудим всички деца и да направим това, преди да започнем цикъла:
И след това ги актуализирайте на всяка итерация:
И сега най-накрая имаме напълно функциониращ Game Loop, който повтаря всеки кадър и актуализира всички обекти и всички компоненти.
Последно докосване: нека стартираме този двигател, като инстанцираме и събудим самата игра:
Страхотно! Ако стартирате кода си, като изпълните npm start
, той трябва да се компилира без проблеми.
Тестване на игровия обект
Все още нямаме визуализации, които да докажат, че сме успели в мисията си, така че тестът на модула е единствената надежда.
За щастие, тестването на обекта Game в този момент е лесно. Има пет неща, които трябва да тестваме:
И за да направим това, трябва да направим няколко приготовления. Първо, нека настроим фалшиви деца и компоненти:
Създадох и инстанцирах компоненти, точно както направих за теста за Entity в предишната глава. Също така създадох празни обекти, инстанцирах ги и ги прикачих към играта.
Използваме requestAnimationFrame в играта. Това е асинхронно обратно извикване и трябва да му се подиграваме правилно. Един от начините да направите това е да го замените с jest.fn
и да се уверите, че извиква обратно извикване веднага:
Това ще ми позволи да тествам дали цикълът за актуализиране работи правилно:
Тук просто шпионирам game.Update
, събуждам играта и очаквам game.Update
наистина да бъде изпълнена.
Тестването на останалите четири сценария е доста подобно на тестването на Entity, което направихме в предишната глава:
Започвам, като шпионирам Awake
или Update
на всяко дете/компонент и очаквам те да бъдат извикани съответно след game.Awake
или game.Update
.
Защо да тестваме Awake/Update на компоненти? Вече тествахме същото нещо върху абстрактно предприятие. Защо да се повтаря?
Причината е, че можем да заменим тази функционалност в Awake/Update на играта. Не забравяйте, че абстрактният Entity предоставя само поведение по подразбиране и ако отменим метода (както направихме), тогава трябва да сме сигурни, че не губим нищо.
Ако стартирате тестовете си с npm t
, всички те трябва да са успешни:
Можете да намерите пълния изходен код на тази публикация в клона
game-loop-2
на хранилище.
Заключение
Трябва да се гордеете със себе си, постигнахте МНОГО: научихте за Game Loop и как се играе в един отбор с Entity и Components, как да изпълнявате код на всеки кадър, открихте методите на жизнения цикъл на Entity и как да ги използвате с Game Loop и, разбира се, да изградите основния Game Entity и да го покриете с тестове! Удивителен напредък!
„Следващия път“ най-накрая ще нарисуваме нещо на екрана и ще видим красотата на компонентите в действие.
Ако имате коментари, предложения, въпроси или други отзиви, не се колебайте да ми изпратите лично съобщение или да оставите коментар по-долу! Благодаря ви за четенето и ще се видим следващия път!
Това е глава II от поредицата от уроци „Създаване на игра с TypeScript“. Други глави са достъпни тук:
- "Въведение"
- Глава I. Система от компоненти на обекти
- Глава II. Цикъл на играта (Част 1, Част 2)
- Глава III. Решетка за рисуване (Част 1, Част 2, Част 3, Част 4, Част 5)
- Глава IV. Кораби (Част 1, Част 2, Част 3, Част 4)
- Глава V. Система за въвеждане (Част 1, Част 2, Част 3)
- Глава VI. Намиране на пътя и движение
- Глава VII. Държавна машина
- Глава VIII. Система за атака: здраве и щети
- Глава IX. Печелене и загуба на играта
- Глава X. Вражески AI
Кодиране на ниво нагоре
Благодарим ви, че сте част от нашата общност! Абонирайте се за нашия канал в YouTube или се присъединете към курса за интервю за кодиране Skilled.dev.
Въпроси за интервю за кодиране | Skilled.dev
Курсът за овладяване на интервюто за кодиранеskilled.dev