Skocz do zawartości

Płynne przemieszczenanie się do punktu


Nirvan

Rekomendowane odpowiedzi

Nie wiem jak zrobić dokłądne płynne przemieszczanie się do jakiegoś punktu.

Szperałem po forum i znalazłem coś takiego jak interpolacja, ale nigdzie nie było konkretów.

Chciałem zrobić przemieszczanie się od x i y do innego x i y z konkretną prędkością. Coś w stylu x=SmoothValue(x,xx,10);

Chodzi o to żeby obiekt na początku wolno się rozpędzał a na końcu zwalniał.

(pisałem to przecież na początku a musialem dać edit żeby to dopisać ;| )

 

Z góry dzięki.

Odnośnik do komentarza
Udostępnij na innych stronach

Skoro chodzi ci o płynne przejście to pewnie też płynny start i zakończenie drogi. A więc potrzebna ci zmienna zmiany prędkości - przyśpieszenie i coś ograniczające prędkość ruchu.

Plan: musisz wymyślić sobie jakieś przyśpieszenie, np 0.5, oraz maksymalną prędkość, np 10.

 

Kod (zał: speed = 0, (xx,yy) to pozycja, gdzie chce się przemieścić, dv to przyśpieszenie, msp maksymalna prędkość, goo to czy obiekt ma się przemieszczać

GML (Create)
// deklaracja danych, dobry nawyk

xx = 0;

yy = 0;

dv = 0.5;

msp = 10;

goo = 0;

 

GML (Step)
// kod aktywujący ruch przez kliknięcie myszką

if (mouse_check_button_pressed(mb_left) && goo == 0)

{

// ustawienie danych do przelotu

xx = mouse_x;

yy = mouse_y;

goo = 1;

}

if (goo == 1)

{

// wzór fizyczny s = v^2/2a czyli droga jaką pokona jeszcze rozpędzony obiekt w ruchu opóźnionym.

// Sprawdzamy, czy dystans jest mniejszy od tego i czy powinniśmy hamować

if (speed*speed/2/dv < point_distance(x, y, xx, yy))

speed = max(speed-dv, 0);

// w przeciwnym wypadku przyśpieszamy w tamtym kierunku

else move_towards_point(xx, yy, min(speed+dv, msp));

// jeżeli obiekt mimo powyższego stoi znaczy, że ruch się skończył

if (speed == 0) goo = 0;

}

Odnośnik do komentarza
Udostępnij na innych stronach

Coś jest tu spiepszone bo obiekt stoi, i ani rusz.

Kombinowłem trochę z kodem ale bez efektu.

I nie jestem pewny czy działało by to jakby np podczas ruchu punkty docelowe się zmieniły.

Może zapodam kod na którym eksperymentowałem, ale to jest od zmiany direction.

 

GML (by Harrrry)
// SmoothDirection (aktualna wartość w stopniach, wartość docelowa, szybkość)

q1=abs(argument0-(argument1+360));

q2=abs(argument0-argument1);

q3=abs(argument0-(argument1-360));

q=0;

if q1<=q2 and q1<=q3 q=1;

if q2<=q1 and q2<=q3 q=0;

if q3<=q1 and q3<=q2 q=-1;

argument1+=360*q;

q=argument0+(argument1-argument0)*(argument2/100);

return q mod 360;

 

I wykorzystanie tego skryptu wygląda podobnie jak to co dałem na początku w 1 poscie ze SmoothValue

Odnośnik do komentarza
Udostępnij na innych stronach

spiepszone

:rolleyes:

interpolacja

rolleyes.gif

 

Nie powinieneś pisać skryptu, jeśli nie potrafisz sobie poradzić nawet bez niego. To tylko dodatkowe komplikowanie sprawy. Jeśli ci już tak zależy, proszę, oto i on:

 

GML
// arg[ 0 ] - x

// arg[ 1 ] - y

// arg[ 2 ] - speed

xx = argument[ 0 ];

yy = argument[ 1 ];

spd = argument[ 2 ]

 

dir = point_direction( x, y, xx, yy );

 

xw = ( xx > x );

yw = ( yy > y );

 

if ( x != xx || y != yy )

{

if ( xw )

x = min( xx, x + lengthdir_x( spd, dir ) );

else

x = max( xx, x + lengthdir_x( spd, dir ) );

if ( yw )

y = min( yy, y + lengthdir_y( spd, dir ) );

else

y = max( yy, y + lengthdir_y( spd, dir ) );

}

Chociaż skrypt w ogóle mi tu nie pasuje, no ale niech będzie.

 

Użycie? Walisz smooth_move( x, y, szybkosc ) w Stepie. Oczywiście nazwę możesz zmienić.

Odnośnik do komentarza
Udostępnij na innych stronach

Koleś, chyba sobe jaja ze mnie robisz. Wchodzisz w dany room -> Settings -> Speed i ustawiasz na co najmniej 60.

 

Następnie w Global Games Settings -> Graphics -> Zaznaczasz "Interpolate colors between pixels".

 

To, co napisałem, wykorzystuje maksymalną możliwą płynność. Wydaje ci się niepłynne, ponieważ akcje wykonują się z częstotliwością 30 Herzów, tzn. 30 razy na sekundę. Normalne gry, przynajmniej powinny, działać pod FPSami dwa razy większymi. Jeżeli nawet 60 FPS ci nie pasuje, głupiś ty i tyle :) .

 

Twoje utrapienie może być także spowodowane tym, że dostałeś coś innego niż chciałeś. Ale wyraziłeś się jasno, że potrzebujesz ruchu jednostajnego. Taki też ode mnie otrzymałeś.

Odnośnik do komentarza
Udostępnij na innych stronach

Może to przez ogra, może ma problemy z lengthdirami, jak robiłem coś z sinusami i były te mniejsze wartosci to gra się zawieszała.

Może potem jeszcze uda mi się to poprawić.

Mam zawsze na 60 fps :P

 

Edit: Teraz zrobiłem to w 2D, nie chodzi o to zeby leciało tak, tylko żeby na początku wolno leciał, potem szybciej i na końcu zwalniał.

Wgl to najlepiej jakby było coś takiego dla jednej wartości.

Odnośnik do komentarza
Udostępnij na innych stronach

Teraz widzę edycję w pierwszym poście :) :) . Zaczekaj, zaraz zapodam przykład.

 

Edit: Fizyka się kłania, a dokładnie wzór

 

v^2 / 2a = s

 

Wyprowadzony następująco:

 

{ vt - at^2 / 2 = s

{ t = v / a

 

Podstawiając drugie wyrażenie do pierwszego otrzymujemy pożądany efekt :) .

 

v^2 / a - a * ( v^2 / a^2 ) = s

=>

v^2 / 2a = s

 

Rozwiązanie:

 

Create:

GML
spd = 0;

xx = x;

yy = y;

xw = false;

yw = false;

dir = 0;

 

// do twojej edycji:

minspd = 0.2; // predkosc minimalna

maxspd = 6; // predkosc maksymalna

accspd = 0.1; // przyspieszenie</span>

Step:

GML
if ( x != xx || y != yy )

{

if ( spd * spd / ( 2 * accspd ) > point_distance( x, y, xx, yy ) )

spd = max( minspd, spd - accspd );

else

spd = min( spd + accspd, maxspd );

 

if ( xw )

x = min( xx, x + lengthdir_x( spd, dir ) );

else

x = max( xx, x + lengthdir_x( spd, dir ) );

if ( yw )

y = min( yy, y + lengthdir_y( spd, dir ) );

else

y = max( yy, y + lengthdir_y( spd, dir ) );

}

else

{

spd = minspd;

}

No i u mnie jeszcze Global Mouse Left Pressed:

GML
xx = mouse_x;

yy = mouse_y;

xw = ( xx > x );

yw = ( yy > y );

 

dir = point_direction( x, y, xx, yy );

 

spd = minspd;

U mnie działa elegancko ;) .

 

Pozdrawiam,

Sernat.

Odnośnik do komentarza
Udostępnij na innych stronach

To już dobrze działa, nie tak bardzo płynnie jak ten kod do direction ale nie szkodzi, mam jeszcze tylko problemy nad tym zeby zrobić taką łagodną zmianę dla jednej zmiennej, że np chce zeby zmienna v = 10 zmieniła się tak płynnie na 50.

Odnośnik do komentarza
Udostępnij na innych stronach

A dokładnie ( 2 * time )...

 

Edit:

 

Sorry, ale wczoraj byłem już zmęczony, a to co napisałem miało taki sam sens, jak produkcje Bedzioma. Oto kod w Step:

GML
t += 1;

 

if ( 2 * t < time )

v = min( v + 2 * maxv / time , maxv );

else

v = max( v - 2 * maxv / time, 0 );

 

a += v;

Seems to work...

Odnośnik do komentarza
Udostępnij na innych stronach

Wiem czego chce :P Chce tak jak w tym kodzie, tylko ze tu wartosc sie zmienia zeby wybrać krótszą droge.

 

GML
// SmoothDirection (aktualna wartość w stopniach, wartość docelowa, szybkość)

q1=abs(argument0-(argument1+360));

q2=abs(argument0-argument1);

q3=abs(argument0-(argument1-360));

q=0;

if q1<=q2 and q1<=q3 q=1;

if q2<=q1 and q2<=q3 q=0;

if q3<=q1 and q3<=q2 q=-1;

argument1+=360*q;

q=argument0+(argument1-argument0)*(argument2/100);

return q mod 360;

 

wykorzystanie

GML
a=SmoothDirection(a,newa,10);
Odnośnik do komentarza
Udostępnij na innych stronach

Zmienna musi zmieniać wartość najpierw powoli, rozpędzając się i spowalniając na końcu i musi tak dojść do konkretnej liczby.

Coś w tym stylu co daleś przedtem np:

 

początkowa_wartość=0;

końcowa_wartość=100;

czas=120;

minimalna_prędkość=0.001;

maxymalna_prędkość=10;

przyspieszenie=0.025;

Odnośnik do komentarza
Udostępnij na innych stronach

Poprawka mojego kodu, faktycznie nie działał, bo zły kierunek znaku :) no i lekka zmiana w okolicy move_towards_point() :)

 

Przykład (GM8): TUTAJ

 

Kod:

GML (Create)
// zmienne pomocnicze

trwa_ruch = 0;

xx = 0;

yy = 0;

 

GML (Step)
// kod aktywujący ruch przez kliknięcie myszką

if (mouse_check_button_pressed(mb_left) && trwa_ruch == 0)

{

xx = mouse_x;

yy = mouse_y;

trwa_ruch = 1;

}

 

// Funkcja wymaga stałego działania

if (trwa_ruch == 1)

{

trwa_ruch = SmoothDirection(xx, yy, 0.25, 10);

}

 

GML (Script SmoothDirection)
// Function SmoothDirection(x, y, przys., maks_pred.)

// wzór fizyczny s = v^2/2a czyli droga jaką pokona jeszcze rozpędzony obiekt w ruchu opóźnionym.

// Sprawdzamy, czy dystans jest mniejszy od tego i czy powinniśmy hamować

// +2*speed po to, żeby obiekt potem nie zawracał jeśli przypadkiem ominie punkt

if (speed*speed/2/argument2+speed*2 > point_distance(x, y, argument0, argument1))

speed = max(speed-argument2, 0);

// w przeciwnym wypadku przyśpieszamy i korygujemy kurs

else

{

speed = min(speed+argument2, argument3);

direction = point_direction(x, y, argument0, argument1);

}

// jeśli ruch skończony, zwracamy zero, a jeśli nie to ruch kontynuujemy

if (speed == 0) return false;

return true;

Odnośnik do komentarza
Udostępnij na innych stronach

Jeśli to ma być linia prosta, możesz korzystać z interpolacji.

Interpolacja:

GML
var xs,ys,xg,yg,a:

xs = argument0 //x startowe

ys = argument1 //y startowe

xg = argument2 //x końcowe

yg = argument3 //y końcowe

a = argument4 //wartość przesunięcia po linii; od 0 do 1, w przeciwnym wypadku wyjdzie poza odcinek

x = 2*xs-(xg*a)

y = 2*ys-(yg*a)

Szybciej będzie działać, jeśli nie będziesz używać konstrukcji 'var', tylko po prostu we wzorze używaj argument[numer].

 

Rozkład normalny pozwoli Ci zrobić gładkie przechodzenie z punktu A do punktu B:

GML
return (1/sqrt(2*pi))*exp(-sqr(argument0)/2)

To wzór uproszczony na najbardziej znany wykres tej funkcji. Poszukaj więcej na Wikipedii.

Odnośnik do komentarza
Udostępnij na innych stronach

Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto

Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.

Zarejestruj nowe konto

Załóż nowe konto. To bardzo proste!

Zarejestruj się

Zaloguj się

Posiadasz już konto? Zaloguj się poniżej.

Zaloguj się
  • Ostatnio przeglądający   0 użytkowników

    • Brak zarejestrowanych użytkowników przeglądających tę stronę.
×
×
  • Dodaj nową pozycję...