Jak stworzyć prostą grę w JavaScript? (kontynuacja - krok 2)

Załadowaliśmy grafikę, teraz możemy ją wyświetlać wtedy, kiedy tylko chcemy.
Jednak grafika to tylko wygląd, a potrzebna jest pewna logika gry. Nie chcemy mieć statycznych obrazków, a raczej obiekty, które coś robią, ruszają się w jakiś sposób, odpowiadają na zdarzenia.

Dlatego w tym kroku stworzymy tzw. pętlę gry (game loop), czyli odpalaną 60 razy na sekundę funkcję JavaScript, która zajmie się poruszaniem i wyświetlaniem Jednostek.

Jednostką (ang. Entity) zaś nazywamy tutaj każdy animowany i biorący w rozgrywce obiekt gry - w tym wypadku będzie to gracz (rakieta) oraz statki ufo. Każda taka jednostka będzie osobnym obiektem i będzie miała metodę draw(), metodę move() oraz parę właściwości, takie jak pozycja na ekranie (x,y) oraz prędkość pozioma i pionowa (vx, vy).



Ponieważ w JavaScript nie ma klas, będziemy działać na tzw. prototypach.

Utworzymy teraz prototyp, z którego będziemy tworzyć jednostki. Nazwiemy go EntityPrototype i zaopatrzymy go w metody draw() i move() oraz ustawimy domyślne wartości dla właściwości x, y, vx, vy.

var EntityPrototype = {
draw: function(context) {
context.drawImage(this.img, this.x, this.y);
},
move: function() {
this.x += this.vx;
this.y += this.vy;
},
x: 0, y:0, vx:0, vy:0
};
view raw gistfile1.js hosted with ❤ by GitHub


pojawia się tutaj magiczny kontekst (context). Jest on potrzebny po to, żeby rysować po Canvasie. Do tego jeszcze wrócimy, ale na razie ważne jest tylko tyle, żeby zauważyć, że obiekt kontekstu będzie przekazywany jako pierwszy parametr metody draw() (o tym musimy myśleć, ponieważ będziemy musieli jakoś go tej metodzie przekazywać...)>

Metoda move() zaś porusza obiekt, dodając do wartości x, wartość prędkości poziomej (vx), a do wartości y dodaje wartość prędkości poziomej (vy).

przechodzimy dalej...


Gdzieś będziemy musieli również zapisywać te jednostki, więc utwórz na początku skryptu pustą tablicę entities. Utwórz również zmienne (na razie same zmienne, bez wartości) canvas i ctx. Będą nam potrzebne do wyświetlania grafiki.
var entities = [];
var canvas, ctx;
view raw gistfile1.js hosted with ❤ by GitHub


Jakoś też musimy tworzyć te jednostki. Na razie to zrobiliśmy sobie prototyp jednostki, zrobiliśmy tablicę jednostek, ale żadnej jednostki jeszcze nie utworzyliśmy. Potrzebujemy więc funkcji createEntity, która będzie się zajmować tworzeniem jednostek.

function createEntity(entityName, properties) {
var entity = Object.create(EntityPrototype);
entity.img = images[entityName];
for (var propertyName in properties)
entity[propertyName] = properties[propertyName];
entities.push(entity);
return entity;
};
view raw gistfile1.js hosted with ❤ by GitHub

Co tu się dzieje po kolei:

1. najpierw tworzymy jednostkę za pomocą funkcji Object.create. Przekazujemy tej funkcji zmienną EntityPrototype, żeby pokazać, że na podstawie tego właśnie prototypu ma być utworzona jednostka.

2. przypisujemy właściwy obrazek
entity.img = images[entityName]

3. w pętli for..in - kopiujemy dodatkowe właściwości i przypisujemy je do tworzonego obiektu

4. dodajemy jednostkę do globalnej tablicy jednostek
entities.push(entity);

5. na końcu zwracamy tworzoną jednostkę (return entity;)

powracamy do grafiki...


Zanim będziemy mogli na serio wyświetlać jednostki, musimy zainicjalizować obiekty graficzne. Stwórzmy funkcję initCanvas
function initCanvas() {
canvas = document.getElementById('canvas');
ctx = canvas.getContext('2d');
};
view raw gistfile1.js hosted with ❤ by GitHub

inicjalizujemy tutaj te zmienne globalne, które dodaliśmy wcześniej w tej części.

Funkcję tę jednak musimy gdzieś wywoływać. Dodaj tę linijkę na początku funkcji initialize:

initCanvas();
view raw gistfile1.js hosted with ❤ by GitHub


Teraz będzie zabawa...


Dodaj na końcu funkcji initialize te 3 linijki.
createEntity('player', {x:300,y:280})
createEntity('ufo', {x:0, y:20, vx:1, vy:0.1})
createEntity('ufo', {x:120, y:80, vx:1.1, vy:0})
createEntity('ufo', {x:40, y:130, vx:1.05, vy:0})
view raw gistfile1.js hosted with ❤ by GitHub

Odpal stronę.


Nic się nie wyświetla :(

Aha. No tak. Zapomnieliśmy dodać wywołania metody draw(). Zrobimy to teraz.
Dodaj na końcu funkcji initialize coś takiego:

entities.forEach(function (entity) {
entity.draw(ctx);
});
view raw gistfile1.js hosted with ❤ by GitHub


Odpal jeszcze raz stronę. Powinny się wyświetlić trzy ufa i jedna rakieta ;)

Ale zaraz, chwileczkę. Przecież miały się animować. No nic. Skasuj w takim razie to, co żeś wkleił.

skasuj:

entities.forEach(function (entity) {
entity.draw(ctx);
});


Zrobimy to w pętli. Tak jak obiecywałem. 60 razy na sekundę.
Wklej na końcu funkcji initialize:
setInterval(gameLoop, 1000/60);
view raw gistfile1.js hosted with ❤ by GitHub


Oraz wklej gdzieś w skrypcie definicję naszej funkcji gameLoop:
function gameLoop() {
ctx.clearRect(0,0,canvas.width, canvas.height);
entities.forEach(function (entity) {
entity.move();
});
entities.forEach(function (entity) {
entity.draw(ctx);
});
}
view raw gistfile1.js hosted with ❤ by GitHub

Zauważ, że najpierw czyścimy ekran, zanim zaczniemy rysować.

No a teraz odpal. Jeśli dobrze odpalisz, zobaczysz animację.

Jeśli nic się nie dzieje, włącz konsolę błędów i zobacz czy przeglądarka nie zgłasza jakiegoś błędu. Zobacz też czy dobrze zrobiłeś wszystko w tym kroku. Możesz też w końcu ściągnąć gotowy plik *.zip, w którym jest cały kod programu na tym etapie.

W kolejnych częściach zajmiemy się dodaniem inputów, czyli obsługą klawiatury. Dodamy też możliwość strzelania i niszczenia statków.

Komentarze

Popularne posty z tego bloga

Absurdy Rekrutacji 2023

Sygnały, że JS rozwija się w tempie żółwia

Przygody juniora (1)