mgr inż. Wacław Libront * Bobowa 2019

ZSO Bobowa, ul. Długoszowskich 1, 38-350 Bobowa, tel: 0183514009, fax: 0183530221, email: sekretariat@zsobobowa.eu, www: zsobobowa.eu

Lekcja 5

Animacja w JS

  1. animacja
  2. przesuwanie
  3. odbijanie
  4. obracanie
  5. animacja

Animacja w JS
Na czym polega animacja? Rysujemy obiekt, potem wymazujemy ekran, ustawiamy nowe współrzędne i powtarzamy te trzy instrukcje wiele razy - to taki najprostszy schemat. W JS animację realizujemy rekurencyjnie. 

W ramce zestaw instrukcji realizujących algorytm animacji. Funkcje clearTimeout i setTimeout odpowiedzialne są za uruchamianie funkcji animacja co określony przedział czasu w milisekundach – zmienna skok. Zmienna czas jest tzw. „uchwytem” funkcji.

var w = c.canvas.width;
var h = c.canvas.height;
var skok = 10;
var czas;
function animacja() {
  c.clearRect(0, 0, w, h);
  //rysowanie i przesuwanie obiektu



  clearTimeout(czas);
  czas = setTimeout(animacja, skok); 
}
//pierwsze wywołanie funkcji rekurencyjnej
animacja();

Przesuwanie
Aby przesunąć obiekt musimy za każdym zwiększyć jego współrzędne (X,Y) o określony skok (vX,vY). Im większe wartości vX i vY, tym obiekt będzie się szybciej przesuwał.

var w = c.canvas.width;
var h = c.canvas.height;
var skok = 10;
var czas;
//początkowe położenie
var x = 0;
var y = 0;
//początkowa prędkość
var vx = 2;
var vy = 1;
//bok kwadratu
var bok = 50;

function animacja() {
  //czyszczenie okna canvas
  c.clearRect(0, 0, w, h);
  //rysowanie ramki wokół canvas
  c.strokeRect(0, 0, w, h);
  
  //przesuwanie obiektu
  x = x + vx;
  y = y + vy;
  //rysowanie obiektu
  c.fillRect(x, y, bok, bok); 
  
  //rekurencyjne wywołanie kolejnej animacji
  clearTimeout(czas);
  czas = setTimeout(animacja, skok); 
}

animacja();

Odbijanie - instrukcja warunkowa
Gdy obiekt dociera do brzegu powinien się „odbić”, tzn. zmienić kierunek, skąd przyleciał, na przeciwny. Matematycznie wystarczy zmienić znak  na przeciwny vx - w poziomie lub vy - w pionie. Należy uwzględnić również szerokość i wysokość obiektu.

Instrukcje warunkowe służą do podejmowania decyzji, "w którą stronę" ma zmierzać program. Decyzję podejmujemy za pomocą warunku logicznego, którego wynikiem jest zawsze prawda lub fałsz. Jeśli warunek logiczny jest prawdziwy, to wykonywana jest instrukcja. Jeśli warunek logiczny jest fałszywy, to instrukcja nie jest wykonywana. Warunki logiczne mogą być proste (sprawdzamy czy jest równe, różne, mniejsze lub większe) lub złożone (sprawdzamy tzw. sumę lub iloczyn logiczny).

Instrukcje w ramce wstawiamy do środka pętli animacyjnej - po instrukcjach obliczających nowe położenie obiektu.

//odbicia od brzegów
if (x < 0) vx=-vx;	// lewy
if (x+bok > w) vx=-vx; 	// prawy
if (y < 0) vy=-vy;}	// górny
if (y+bok > h) vy=-vy; 	// dolny

Możemy zastosować złożone warunki logiczne i z czterech instrukcji warunkowych zostaną dwie. Zastosowano tzw. sumę logiczną, która oznacza, że nastąpi zmiana kierunku ruchy gdy jeden z dwóch warunków logicznych będzie prawdziwy: pierwszy LUB drugi

if (x+bok > w || x < 0) vx=-vx; 
if (y+bok > h || y < 0) vy=-vy;

Obracanie
Jeśli obiekt ma zdefiniowany kąt obrotu, to postępujemy podobnie jak podczas przesuwania – zwiększamy kąt o jakiś elementarny składnik – dK. Musimy także sprawdzać, kiedy kąt osiągnie wartość graniczną i w odpowiedni sposób go zmodyfikować.

//początkowy kąt i skok kąta
var kat = 0;
var vk = 1;

//w pętli animacyjnej zwiększamy i sprawdzamy kąt
kat = kat + vk;
if (kat>=360) {vk=-vk

Funkcja rysująca kwadrat z możliwością obracania. Wykorzystujemy translację i rotację obszaru canvas.

//obrotowy kwadrat 
function kwaO(xs,ys,bok,kat,kolor){
  c.save();
  c.translate(xs-bok/2,ys-bok/2);
  c.rotate(Math.PI*kat/180);
  c.fillStyle=kolor;
  c.fillRect(-bok/2,-bok/2,bok,bok);
  c.restore();
} 

Zmienione zostaną instrukcje warunkowe - kwadrat po odbiciu od brzegu będzie również zmieniał kierunek obrotu. Ponieważ w instrukcji warunkowej należy wykonać dwie instrukcje, dlatego musimy zastosować instrukcję bloku {}.

if (x > w || x < bok)
{
  vx=-vx;
  vk=-vk;
}
if (y > h || y < bok)
{
  vy=-vy;
  vk=-vk;
}

// te same instrukcje można zapisać w jednym wierszu
if (x>w || x<bok) {vx=-vx;vk=-vk;}
if (y>h || y<bok) {vy=-vy;vk=-vk;}

Sposób, w jaki zapiszemy poszczególne instrukcje (osobne wiersze i wcięcia) nie ma znaczenia dla wykonywanego programu, ale ma ogromne znaczenie dla samego piszącego program - lepiej się "czyta" program i łatwiej go modyfikuje.


Animacja
Cały program realizujący animację - przesuwanie i obracanie kwadratowego obiektu. Zwróć uwagę na następujące elementy:

<canvas width="400" height="400" id="can"></canvas>
<script>
  var c = can.getContext("2d");


var w = c.canvas.width;
var h = c.canvas.height;
var skok = 10;
var czas;

var x = 100;
var y = 100;
var vx = 2;
var vy = 1;
var kat = 0;
var vk = 1;
var bok = 50;

function kwaO(xs,ys,bok,kat,kolor){
  c.save();
  c.translate(xs-bok/2,ys-bok/2);
  c.rotate(Math.PI*kat/180);
  c.fillStyle=kolor;
  c.fillRect(-bok/2,-bok/2,bok,bok);
  c.restore();
} 

function animacja() {
  c.clearRect(0, 0, w, h);
  c.strokeRect(0, 0, w, h);

  x = x + vx;
  y = y + vy;
  kat = kat + vk;
  
  if (x > w || x -bok < 0){vx=-vx; vk=-vk;}
  if (y > h || y -bok < 0){vy=-vy; vk=-vk;}
  if (kat >= 360) kat = 0;
  
  kwaO(x,y,bok,kat,'red');
  
  clearTimeout(czas);
  czas = setTimeout(animacja, skok); 
}

animacja();
  
</script>

Szablon

<canvas width="400" height="400" id="can"></canvas>
<script>
  var c = can.getContext("2d");

  var w = c.canvas.width;
  var h = c.canvas.height;
  var skok = 10;
  var czas;
  
function animacja() {
  c.clearRect(0, 0, w, h);
  //rysowanie i przesuwanie obiektu




  clearTimeout(czas);
  czas = setTimeout(animacja, skok); 
}

animacja();
</script>