Blog (9)
Komentarze (25)
Recenzje (2)
@lukasz.developerHTML5 w tworzeniu gier (cz. 3)

HTML5 w tworzeniu gier (cz. 3)

13.04.2011 01:39, aktualizacja: 13.04.2011 21:00

Hej,

inne zajęcia trochę odciągnęły mnie od blogowania, jednak po dłuższym czasie napisałem trzecią, jak na razie ostatnią część (mini)cyklu o HTML5 i wykorzystywaniu jego możliwości w połączeniu z Java Scriptem do tworzenia prostych gier. Czas więc odnaleźć na dysku nieco przykurzony programik z opadającymi płatkami śniegu i brać się do jego rozbudowy :).

Poprzednie części minikursu możecie znaleźć wśród wcześniejszych postów: część l., pokazująca jak stworzyć szkielet strony z elementem canvas (płótnem) i wykonywać na nim proste operacje za pomocą języka Java Script część ll., prezentującą jak zmienić opadające kółka w płatki śniegu i dodać odrobinę interaktywności ;)

Dziś zmodyfikujemy nieznacznie zaimplementowaną wcześniej obsługę klawiatury, dodamy do gry zasady oraz umożliwimy odgrywanie dźwięków.

Obsługa klawiatury

Ten temat został już poruszony w poprzedniej części kursu. Ze stworzonego przez nas kodu usuniemy liczby o znaczeniu, które na pierwszy rzut oka może nie być jasne jeśli włączmy aplikację po dłuższej przerwie ;). Mowa o kodach klawiszy.

Dodajmy na początku naszego pliku z kodem JS pomocniczą "strukturę", zbierającą kody klawiszy, które mogą się nam przydać :).


var kodyKlawiszy = {
					lewo : 37,  /* strzałka w lewo */
					prawo : 39, /* strzałka w prawo */
					gora : 38, /* strzałka w dół */
					dol : 40, /* strzałka w górę */
					akcja: 32 /* spacja */
			   };

Następnie zmieńmy kod funkcji ruchGracza tak, aby używał naszej struktury:


function ruchGracza()
{
if ((wcisnietyKlawisz == kodyKlawiszy.lewo) && (gracz.x > gracz.szybkosc))
	{
		gracz.x -= gracz.szybkosc;
	}
	else if ((wcisnietyKlawisz == kodyKlawiszy.prawo) && (gracz.x < (szerokoscCanvas - gracz.szybkosc)))
	{
		gracz.x += gracz.szybkosc;
	}
}

Dzięki temu rozwiązaniu patrząc na kod od razu widać, którego klawisza on dotyczy. Ma to jeszcze jedną zaletę: jeśli nagle stwierdzimy, że zamiast akcji dla Ctrl lepiej używać spacji, nie musimy przeglądać całego kodu. Wystarczy, że zmienimy go w strukturze kodyKlawiszy i sprawa załatwiona :).

Nasza śniegowa kula przesuwa się już z lewo i prawo. Czas dać jej więcej swobody i umożliwić jej ruch również w pionie :).


function ruchGracza()
{
	if ((wcisnietyKlawisz == kodyKlawiszy.lewo) && (gracz.x > gracz.szybkosc))
	{
		gracz.x -= gracz.szybkosc;
	}
	else if ((wcisnietyKlawisz == kodyKlawiszy.prawo) && (gracz.x < (szerokoscCanvas - gracz.szybkosc)))
	{
		gracz.x += gracz.szybkosc;
	}
	else if ((wcisnietyKlawisz == kodyKlawiszy.gora) && (gracz.y > gracz.szybkosc))
	{
		gracz.y -= gracz.szybkosc;
	}
	else if ((wcisnietyKlawisz == kodyKlawiszy.dol) && (gracz.y < (wysokoscCanvas - gracz.szybkosc)))
	{
		gracz.y += gracz.szybkosc;
	}
}

Cel gry

Jeśli chcemy nasze dzieło można było nazywać grą, powinniśmy dać jej pewien określony cel. Proponuję, aby w przypadku tego demka zadaniem gracza było unikanie przez jak najdłuższy czas wszystkich płatków śniegu. Potrzebujemy więc licznika, który będzie ów czas odmierzał.

Dodajmy dla niego element div do kodu w pliku strony html:

[code] W śniegu

W śniegu

0
Element canvas nie jest obsługiwany przez twoją przeglądarkę [/code]

Notka Stronę początkowo przygotowałem po angielsku i zauważyłem, że niektóre teksty nie zostały przetłumaczone. Korzystając z okazji postanowiłem więc naprawić to niedopatrzenie ;).

Uwaga Jeśli polskie znaki nie będą się poprawnie wyświetlać pomimo ustawienia lang="pl" i charset="UTF-8", pamiętajmy, aby upewnić się czy kodowanie pliku z kodem źródłowym to UTF-8.

W pliku ze stworzonym przez nas skryptem w JS dodajmy natomiast ustawienie początkowej wartości dla wyświetlanego licznika, który wystartuje przy inicjalizacji gry i zostanie zatrzymany w chwili pierwszego zetknięcia z płatkiem śniegu.

Zmodyfikujmy w tym celu funkcję inicjalizujGre w przedstawiony sposób:


...
function inicjalizujGre(glownyCanvas)
{
canvasElement = glownyCanvas;
canvasElement.width = szerokoscCanvas;
canvasElement.height = wysokoscCanvas;

licznikElement = document.getElementById("licznik");
licznikElement.innerHTML = "0";
...
}
...

dodajmy pola dla przechowywania wartości licznika


/* licznik czasu gry w milisekundach */
var licznik = 0;
/* liczba klatek po ostatnim odswiezeniu licznika na stronie */
var klatkaPoOdswiezeniu = 0;
/* informacja co ile klatek licznik na stronie ma zostac odswiezony*/
var odswiezajCoLiczbeKlatek = 10;

pierwsze z nich będzie przechowywało faktyczną wartość, a drugie informację o liczbie klatek od ostatniego odświeżenia licznika. Trzecie pole określa co ile klatek licznik ma być odświeżany.

W głównej pętli aktualizujmy nasz licznik o odpowiednią wartość:


function glownaPetla()
{
/* aktualizuj licznik czasu */
licznik += dlugoscKlatki/1000.0;
klatkaPoOdswiezeniu = (klatkaPoOdswiezeniu + 1) % odswiezajCoLiczbeKlatek;
if (klatkaPoOdswiezeniu == 0)
{
	/* aktualizuj wyswietlana wartosc licznika */
	if (licznikElement)
	{
		/* wyswietl liczbe zaokraglona do jednego miejsca po przecinku */
		licznikElement.innerHTML = licznik.toFixed(1);
	}
}
...
}

Na koniec dodajmy funkcję weryfikującą czy nasza śniegowa kulka koliduje z przynajmniej jednym z opadających płatków:


function sprawdzKolizje()
{
	for(var j = 0; j < platki.length; j++)
	{
		if (Math.abs(platki[j].x - gracz.x) < gracz.r + platki[j].aktualneR/2)
		{
			if (Math.abs(platki[j].y - platki[j].r/2 - gracz.y) < gracz.r + platki[j].r/2)
			{
				return true;
			}
		}
	}
	return false;
}

jeśli tak jest, wyświetlimy odpowiednią informację i zatrzymamy grę:


function glownaPetla()
{
...
if (klatkaPoOdswiezeniu == 0)
{
	...
}

/* sprawdz kolizje z platkami  */
if (sprawdzKolizje())
{
	clearInterval(glownaPetlaUchwyt);
	var gameEndText = "KONIEC GRY";
	var counterText = "Punkty: " + licznik.toFixed(1);
	/* napisz wysrodkowany tekst z wynikiem punktowym gracza */
	context.shadowColor = "white";
	context.fillStyle = "#FFD800";
	context.font = "bold 20px sans-serif";
	context.fillText(gameEndText, szerokoscCanvas/2 - context.measureText(gameEndText).width/2, wysokoscCanvas/2 - 30);
	context.fillText(counterText, szerokoscCanvas/2 - context.measureText(counterText).width/2, wysokoscCanvas/2);
	return;
}
...
}

W powyższym fragmencie używamy metody fillText do narysowania wskazanego tekstu oraz measureText do uzyskania informacji o jego graficznej długości. Zgodnie ze znalezionymi informacjami tekst może zajmować więcej miejsca niż to określa użyty przez nas sposób, jednak na nasze potrzeby dokładność powinna być wystarczająca. Zainteresowanych tematem odsyłam do specyfikacji. Jak pewnie zauważyliście użyliśmy tu również nowej zmiennej o nazwie glownaPetlaUchwyt. Wskazuje ona niejako, o które okresowe wywołanie metody nam chodzi. Wartość tą uzyskać możemy zapisując wartość zwracaną przez odpowiednie wywołanie funkcji setInterval. Dodajmy zatem nową zmienną:


var glownaPetlaUchwyt;

i zmodyfikujmy odpowiednią linię w metodzie inicjalizujGre:


function inicjalizujGre(glownyCanvas)
{
...
/* jeśli element canvas jest obsługiwany */
if (canvasElement.getContext)
{
...			
/* uruchom glowna petle gry */
glownaPetlaUchwyt = setInterval(glownaPetla, dlugoscKlatki);
}
...
}

Dźwięki

Gra bez dźwięków jest jak...w każdym razie powinna jakieś dźwięki mieć :P. Dlatego na zakończenie dodamy do naszej zimowej gry chociaż odgłosy towarzyszące zmianie kierunku kulki.

Do katalogu ze skryptem dodajmy krótki plik z dźwiękiem, którego chcemy użyć. Ważne, aby plik był w formacie *.ogg (jeśli demo ma działać w firefox 3.5 lub 4). Nazwijmy plik sound.ogg. Dodajmy nową zmienną:


var audioElement;

a następnie w metodzie inicjalizującej inicjalizujGre dopiszmy kilka linii wczytujących dane z pliku:


function inicjalizujGre(glownyCanvas)
{
canvasElement = glownyCanvas;
canvasElement.width = szerokoscCanvas;
canvasElement.height = wysokoscCanvas;

audioElement = document.createElement('audio');
audioElement.setAttribute('src', 'sound.ogg');
audioElement.load();
...
}

funkcję obsługującą wciśnięcie klawisza (zdefiniowaną wewnątrz funkcji inicjalizującej grę) zmodyfikujmy tak, aby miała postać:


function inicjalizujGre(glownyCanvas)
{
...
/* jeśli element canvas jest obsługiwany */
if (canvasElement.getContext)
{
...
document.onkeydown = function(e)
								{
									var e = window.event || e;
									
									if (wcisnietyKlawisz != e.keyCode)
									{
										wcisnietyKlawisz = e.keyCode;
										audioElement.pause();
										audioElement.currentTime = 0;
										audioElement.play();
									}
								};
...
}
...
}

zatrzymujemy odtwarzanie włączone wcześniej (jeśli nie zostało ono zakończone), resetujemy pozycję odtwarzania do początku pliku i ponownie pozwalamy odtworzyć nasz dźwięk. Teraz przy każdej zmianie kierunku ruchu kulki towarzyszyć nam będzie efekt dźwiękowy :).

Przedstawiona tu obsługa dźwięków jest bardzo podstawowa i nieco uproszczona. W celu uzyskania dokładniejszych informacji można zajrzeć na wybraną stronę z podanych w sekcji Przydatne linki.

Dalsza rozbudowa gry

Dodanie możliwości wielokrotnej rozgrywki, menu itd. nie wnosi specjalnie wiele nowego i może bazować na przedstawionych tu informacjach. Dlatego też, aby nie rozdmuchiwać niepotrzebnie naszego tutoriala, pozostawiam dodanie tej funkcjonalności, a także dalszą rozbudowę gry jako ćwiczenie dla chętnych :).

Na zachętę zamieszczam obrazek z canvasa podczas gry :).

376933

Podsumowanie

Ten krótki kurs to w zamierzeniu pewna prosta prezentacja ilustrująca jak przy użyciu HTML5 i odrobiny Java Script można dodać do naszej strony trochę więcej interaktywności lub wzbogacić ją o prostą grę. Nie miał być to megatutorial jak opanować tajniki HTML5 i Java Script, lecz raczej kilka artykułów opisujących w jaki sposób rozpocząć swoją przygodę z każdym z nich i zachęcić do ich dalszego poznawania. Jeśli chcecie pogłębić swoją wiedzę na poruszane tematy, możecie np.: zajrzeć do linków umieszczonych sekcji Przydatne linki w wybranej części cyklu :).

Mam nadzieję, że wszystkim, którzy nie mieli wcześniej okazji do zabawy z HTML5 i JS poprzez ten kurs przybliżyłem trochę tematykę tworzenia interaktywnych treści i prostych gier na stronach www.

Starałem się, aby przedstawione w każdej z części opisy i fragmenty kodu nie zawierały błędów uniemożliwiających kompilację. Jeśli jednak będziecie mieli jakiekolwiek problemy lub dodatkowe pytania związane z tematem, piszcie.

Pozdrawiam,

Łukasz

Przydatne linki

http://www.whatwg.org/specs/web-apps/current-work/multipage/index.html... specyfikacja HTML5 w przystępnej formie, istnieje też możliwość pobrania jej w postaci pliku PDF

http://diveintohtml5.org znacznie bardziej obszerny opis możliwości HTML5, z uwzględnieniem elementu Canvas, obsługi plików wideo, geolokacji, tworzeniu stron działających offline i innych.

http://www.html5rocks.com/tutorials/audio/quick przystępny opis krok po kroku jak umieścić na stronie i obsługiwać tagi audio

http://www.position-absolute.com/articles/introduction-to-the-html5-au... kolejny artykuł o obsłudze tagów audio

http://www.elated.com/articles/javascript-timers-with-settimeout-and-s... artykuł opisujący metody czasowego wywoływania funkcji setTimeout i setInterval

Wybrane dla Ciebie
Komentarze (2)