Matematyka i fizyka we flashu

barszcz

Matematyka i fizyka we flashu, czyli stworzenie prostej gry

Zapewne wielu z Was spotkało się z animacjami flasha, przede wszystkim grami. Przeważnie mają one nienaganną szatę graficzną (a to dzięki technice wektorowej, która pozwala na zapis grafiki w postaci algorytmu, co znacznie zmniejsza jej rozmiar na dysku). Jednak wielu z Was, nie domyśla się, iż do stworzenia takiej gry (mówię tutaj przede wszystkim o symulatorach, zręcznościówkach..) potrzebna jest nie tyle wiedza informatyczna, z zakresu programowania, co znajomość wzorów fizycznych i matematycznych. Aby nie zanudzać podam prosty przykład: "opadająca, a następnie po odpiciu o ziemię wznosząca się piłka"; do stworzenia tej prościutkiej animacji potrzebna jest kardynalna wiedza z zakresu dynamiki Newtona. Z uwagi na prostotę stworzenia takiej animacji nie zamieszczę jej kodu, lecz przejdę do nieco ciekawszych, a zarazem trudniejszych rzeczy.

Wyobraźmy sobie działo stojące na środku ekranu (środku obiektu animacji flasha). Działo obraca się w taki sposób, że zawsze jego lufa jest skierowana w stronę kursora (wystrzeleniem pocisku z takiego działa zajmę się później). Trzeba tutaj mieć podstawową wiedzę z programowania w Action-Scripcie; otóż każdy obiekt (zarejestrowany jako movie-clip) posiada właściwość "_rotation" - czyli obrót obiektu woku własnej osi. Domyślnie jest ona równa zeru i wtedy lufa naszego działa jest skierowana dokładnie ku górze. I w tym miejscu część informatyczna praktycznie się kończy. Czas zająć się funkcjami trygonometrycznymi!

_root.onEnterFrame = function() //zdarzenie wywoływane z częstotliwością
{
   //obliczenie odległości
   rx=_root.xmouse-dzialo._x;
   ry=_root.ymouse-dzialo._y;
   r=Math.sqrt((rx*rx)+(ry*ry));
   //wyliczenie alfy w radianach
   a=Math.asin(rx/r);
   //zamienienie jej na stopnie
   if(ry<=0) {
      dzialo._rotation=(a*180)/Math.PI;
   }
   if(ry>0) {
      dzialo._rotation=180-((a*180)/Math.PI);
   }
}

I gotowe, działo obraca się jak złoto!

Teraz zajmiemy się wystrzeleniem pocisku z tego działa. Będzie to zwykła, czarna kula domyślnie umieszczona w tym samym miejscu co działo, na niższym leyerze (poziomie). Tutaj również należy skorzystać z funkcji trygonometrycznych. Wpierw tworzymy funkcje, która sprowadza kule na domyślne miejsce, będzie ona wykorzystywana wiele razy. Następnie tworzymy zdarzenie naciśnięcia przycisku myszy, w nim obliczmy nowe prędkości kuli, którą poruszmy z kolei w zdarzeniu częstotliwości wyświetlania klatki. Jeśli kula wyjdzie poza obszar animacji, wróci na swoje domyślne miejsce i zatrzyma się. Oto kod:

//zadeklarowanie zmiennych
vkuli=2; //stała prędkość początkowa
vxkuli=0; //aktualna predkosc kuli OX
vykuli=0; //aktualna predkosc kuli OY
leci=-1;
NaPozycje();

function NaPozycje() //tworzymy nową funkcje
{
   //umieszczenie kuli na domyślnym miejscu
   kula._x=dzialo._x;
   kula._Y=dzialo._y;
   //wyzerowanie prędkości
   vxkuli=0;
   vykuli=0;
   leci=-1;
}

_root.onMouseDown = function() //tworzymy zdarzenie kliknięcia
{
   //jesli kula spoczywa
   if(leci==-1) {
      g=90-dzialo._rotation; //obliczenie gammy
      b=(g*Math.PI)/180; //zamienienie do radianow
      vxkuli=Math.cos(b)*vkuli; //obliczenie nowych predkosci kuli OX
      vykuli=-Math.sin(b)*vkuli; //obliczenie nowych predkosci kuli OY
      leci=0;
   }
}

_root.onEnterFrame = function() //dopisanie do zdarzenia
{
   //poruszanie kuli
   kula._x += vxkuli;
   kula._y += vykuli;
   //powrot jesli wyjdzie poza
   if(kula._x<0 || kula._x>550 || kula._y<0 || kula._y>400) {
      NaPozycje();
   }
}

Pamiętajmy, że kula i działo są na osobnych leyerach (poziomach animacji)!

Właściwie animacja jest już skończona. Działo działa jak należy, brakuje jedynie wrogów, ale to już inna bajka. Ja jednak chciałbym nieznacznie nawiązać to fizyki. Otóż wyobraźmy sobie takie działo, ale na wodzie; nie stało by w miejscu, lecz odpłynęło by w przeciwną stronę niż wystrzelona kula. To nic innego, jak zasada zachowania pędu; przed wystrzeleniem był zerowy, to i po wystrzeleniu wysi być równy zeru. Niech masa kuli będzie równa 2, zaś masa działa 3 razy większa = 6.

_root.onMouseDown = function() //dopisanie do zdarzenia kliknięcia
{
   vxdziala=-(mkuli*vxkuli)/mdziala; //obliczenie prędkości działa OX
   vydziala=-(mkuli*vykuli)/dziala; //obliczenie prędkości działa OY
}

_root.onEnterFrame = function() //dopisanie do funkcji częstotliwości
{
   //poruszanie działa
   dzialo._x += vxdziala;
   dzialo._y += vydziala;
}

A OTO CAŁY KOD PROGRAMU:

//zadeklarowanie zmiennych
vkuli=2; //stała prędkość początkowa
vxkuli=0; //aktualna prędkość kuli OX
vykuli=0; //aktualna prędkość kuli OY
leci=-1;
vxdziala=0; //aktualna prędkość działa OX
vydziala=0; //aktualna prędkość działa OY
mkuli=2; //masa kuli
mdziala=6; //masa działa
NaPozycje();

function NaPozycje() //tworzymy nową funkcje
{
   //umieszczenie kuli na domyślnym miejscu
   kula._x=dzialo._x;
   kula._Y=dzialo._y;
   //wyzerowanie prędkości
   vxkuli=0;
   vykuli=0;
   leci=-1;
}

_root.onMouseDown = function() //tworzymy zdarzenie kliknięcia
{
   //jesli kula spoczywa
   if(leci==-1) {
      g=90-dzialo._rotation; //obliczenie gammy
      b=(g*Math.PI)/180; //zamienienie do radianów
      vxkuli=Math.cos(b)*vkuli; //obliczenie nowych prędkości kuli OX
      vykuli=-Math.sin(b)*vkuli; //obliczenie nowych prędkości kuli OY
      leci=0;
      vxdziala=-(mkuli*vxkuli)/mdziala; //obliczenie prędkości działa OX
      vydziala=-(mkuli*vykuli)/dziala; //obliczenie prędkości działa OY
   }
}

_root.onEnterFrame = function() //zdarzenie wywoływane z częstotliwością
{
   //obrót działa
   //obliczenie odleglosci
   rx=_root.xmouse-dzialo._x;
   ry=_root.ymouse-dzialo._y;
   r=Math.sqrt((rx*rx)+(ry*ry));
   //wyliczenie alfy w radianach
   a=Math.asin(rx/r);
   //zamienienie jej na stopnie
   if(ry<=0) {
      dzialo._rotation=(a*180)/Math.PI;
   }
   if(ry>0) {
      dzialo._rotation=180-((a*180)/Math.PI);
   }

   //poruszanie obiektów
   //poruszanie kuli
   kula._x += vxkuli;
   kula._y += vykuli;
   if(vxkuli==0 && vykuli==0) {
      kula._x=dzialo._x;
      kula._y=dzialo._y;
   }
   //powrot jesli wyjdzie poza
   if(kula._x<0 || kula._x>550 || kula._y<0 || kula._y>400) {
      NaPozycje();
   }
   //poruszanie dziala
   dzialo._x += vxdziala;
   dzialo._y += vydziala;
}

Screenshot z prezentacji:
Prezentacja.jpg
Link do prezentacji: File:Prezentacja.zip

1 komentarz

Mam nadzieję, że się komuś przyda :)