menu
Krylan | Krzysztof Koperkiewicz
Blog

Efekty cząsteczkowe w Canvas JS

2017-08-18 / Gamedev / Komentarze (0) / Wyświetleń: 1099

HTML5 wraz z nowymi elementami pomagającymi w budowie stron internetowych, przyniósł też duży krok w stronę animacji i gier przeglądarkowych, pozwalając na tworzenie tego, do czego do tej pory używano Flasha, aby móc korzystać z aplikacji bez jej pobierania.

My, w dzisiejszym temacie, skupimy się na aspekcie tworzenia gier z wykorzystaniem elementu canvas, na którym, za pomocą JavaScriptu, możemy rysować obraz – w naszym przypadku, klatki gry. Aby nasza gra cieszyła oko i była bardziej żywa, dostarczyć musimy jej więcej ruchu, animacji, grafiki. Jednym z elementów, które są takim "szczegółem" wpływającym na wygląd naszej gry, są efekty cząsteczkowe. Tym razem pokażę sposób, w jaki mnie udało się to wykorzystać w swoich grach.

Pomijając podstawowe czynności (takie jak ustawienia naszego canvasa, czy sam sposób renderowania klatek) zabiorę się za wyjaśnienie głównej funkcji, która sprawia, że każda z cząsteczek się rusza. Gdy ją wywołamy za pierwszym razem, utworzy nam cząsteczki. Potem będziemy uruchamiać instrukcję z każdą klatką, aby zmienić ich położenie, co da nam płynną animację.

function particleEffect(particleSet, xStart = false, yStart = false, particleImage = false, particleNumber=50, lifetimeValue=1){
	if(particleSet === undefined || particleImage != false){
		particleSet = new Array();
		for(var i=0;i<=particleNumber;i++){
			particleSet[i] = {
				x: xStart,
				y: yStart,
				counter: -40,
				lifetime: lifetimeValue,
				xChange: Math.random() * (1 - (-1)) + (-1),
				yChange: Math.random() * (2 - 1) + 1,
				img: particleImage,
			};
		}
	}
	else{
		particleSet.forEach(function(thisEle){
			thisEle.x += thisEle.xChange;
			thisEle.counter += thisEle.yChange;
			thisEle.y = thisEle.y + thisEle.counter/10;
			if(thisEle.lifetime > 0){
				thisEle.lifetime -= 0.01;
				ctx.globalAlpha = Math.abs(thisEle.lifetime);
			}else{
				ctx.globalAlpha = 0;
			}
			var angle = (frameElapsed % 360) *3;
			drawRotate(thisEle.img, thisEle.x, thisEle.y, angle);
			ctx.globalAlpha = 1;
		});
	}
	return particleSet;
}


Funkcja zawiera kilka elementów, które były potrzebne w konkretnym efekcie, którego używałem w grach. Jak można zauważyć, sporo argumentów tej funkcji jest już przypisana domyślnie. Te argumenty prześlemy tylko za pierwszym razem, żeby wiadomo było, w którym miejscu ma rozpocząć efekt, jakiego obrazka użyć, oraz dodatkowo ile ma być cząsteczek i jak długo mają się pokazywać na ekranie.

Funkcja zwraca tablicę z wszystkimi cząsteczkami i ich położeniem, które się zmienia. W ten sposób przy każdej klatce animacji możemy nadpisywać ją nową tablicą ze zmienionymi wartościami, rysując jednocześnie każdą z cząsteczek na ekranie.

Napisałem też krótką funkcję drawRotate(), która rysuje obrazek obrócony o konkretny stopień:

function drawRotate(targetImage, x, y, angle){
    ctx.save();
    ctx.translate(x+targetImage.width/2, y+targetImage.height/2);
    ctx.rotate(angle*Math.PI/180);
    ctx.drawImage(targetImage, -(targetImage.width/2), -(targetImage.height/2));
    ctx.restore();
};


Kiedy mamy już te dwie funkcje, możemy utworzyć tablicę ze wszystkimi efektami cząsteczkowymi, których obecnie używamy:

var effectsArray = new Array();


A w funkcji renderującej całość zamieszczamy pętlę, która zajmie się każdym z efektów.

for(var key in effectsArray){
	effectsArray[key] = particleEffect(effectsArray[key]);
}


Ostatni element, którego nam brakuje, to rozpoczęcie efektu. W dowolnym miejscu w naszym kodzie (np. po wykryciu kolizji między graczem a bonusem do zebrania) zapiszemy w którymś z elementów tablicy funkcję, która rozpisze dla nas cząsteczki. Przykładowo wygląda to tak:

effectsArray[0] = particleEffect(effectsArray[0], 75, 75, particle, 50);


Kiedy podaliśmy funkcji wszystkie potrzebne informacje, otrzymamy gotową tablicę, która w każdej kolejnej klatce będzie na nowo rysowana wraz z postępującymi zmianami.

Poniżej możecie znaleźć cały kod w działaniu. Poza wyżej opisanymi elementami, znajdują się tam jeszcze części odpowiadające za rysowanie klatek. W poniższym przykładzie efekt cząsteczkowy resetuje się co trzy sekundy.

Jeśli chodzi o wydajność tego skryptu, to w moim przypadku przy około 1000 cząsteczek było widać brak płynności. Może macie jakieś inne sposoby na wykonanie podobnego efektu?


Poprzedni post
[Update] Painter Battle 3.5 – opis zmian
Następny post
Od czego zacząć naukę web developmentu?

Wygląda na to, że nic tu nie ma
Uszczęśliw kotka i napisz komentarz