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:
Link do prezentacji: File:Prezentacja.zip
Mam nadzieję, że się komuś przyda :)