Skocz do zawartości

GMS 2.3.2 / krzywa Beziera a strzelanie do obiektów poruszających się na ścieżce.


Rekomendowane odpowiedzi

Czołem, dzień dobry!

Zwracam się z prośbą o pomoc w 'ugryzieniu' tematu.

Sytuacja wygląda następująco:

W głównym Roomie' mam wyrysowany path po którym poruszają się 2 typy wrogów (oEnemy, oEnemySecondary). Dla uproszczenia możemy pominąć kwestię rozpoznawania który jest który. Ponadto, na ścieżce mam do wyboru ( ilość postawionych uzależniona od ilości monet) dwa rodzaje wież (oTower,oTower2) które 'strzelają' dwoma różnymi typami pocisków (oBullet, oBulletSecondary).  Każda z instancji Enemies po utraceniu swoich 'punktów życia', 'znika' ( instance_destroy() ). 
Mechanizm wykrywania i strzelania do przeciwników rozwiązałem tak: 
 

Cytat

oTower1
create: 

 

maxRange = 130;
minRange = 60;
fire_rate = room_speed / 2;
shooting = false;
objectToShoot = noone

 

alarm[0]:

if(instance_exists(objectToShoot)){
    var bullet = instance_create_depth(x,y, -9, oBullet);
    bullet.speed = 2;
    bullet.direction = point_direction(x,y, objectToShoot.x, objectToShoot.y);
    alarm[0] = fire_rate;
} else {
    shooting = false;
}

 

Draw: 

 

draw_self();
if(mouseOver(x,y,sprite_width, sprite_height)) {
    draw_circle(x,y, minRange, true);
    draw_circle(x,y, maxRange, true);
};

 

var oEnemyEn = instance_nearest(x + minRange,y + minRange,oEnemy);
var oEnemySecEn = instance_nearest(x + minRange,y + minRange,oEnemySecondary);
if (oEnemyEn) {
    var distanceToOEnemy = point_distance(x, y, oEnemyEn.x, oEnemyEn.y);
}

if(oEnemySecEn){
var distanceToOEnemySecondary = point_distance(x, y, oEnemySecEn.x, oEnemySecEn.y);
}

 

if (oEnemyEn && !oEnemySecEn) {
    var en = instance_nearest(x + minRange,y + minRange,oEnemy);
} else if (oEnemyEn && oEnemySecEn) {
    if (distanceToOEnemy > distanceToOEnemySecondary) {
        var en = instance_nearest(x + minRange,y + minRange,oEnemySecondary);
    } else if ( distanceToOEnemy <= distanceToOEnemySecondary) {
        var en = instance_nearest(x + minRange,y + minRange,oEnemy);
    }
} else if (!oEnemyEn && oEnemySecEn) {
    var en = instance_nearest(x + minRange,y + minRange,oEnemySecondary);
} else if (!oEnemyEn && !oEnemySecEn) {
    var en = instance_nearest(x + minRange,y + minRange,oEnemy);
}

 

if(en != noone) {

  if((point_distance(x, y, en.x, en.y) <= maxRange + 4) && (point_distance(x, y, en.x, en.y) >= minRange + 4)) {
        if(shooting == false) {
            alarm[0] = 1;
            shooting = true
        }
        
        objectToShoot = en;
    if(mouseOver(x,y,sprite_width, sprite_height)) {
            draw_circle(x,y, minRange, true);
            draw_circle(x,y, maxRange, true);
        };
    }else {
        shooting = false;
        objectToShoot = noone;
    }
}


Jak wyraźnie widać na załączonym wyżej przykładzie, kwestia namierzania i strzelania opiera się głównie na metodzie instance_nearest() oraz point_distance(). Same zaś enemies poruszają się po path: 
 

Cytat

path_start(Path1, oGlobalVariables.spd ,0,1);
hp = oGlobalVariables.hp;

 

I tu pojawia się moje pytanie. Czy jest jakiś sposób aby 'kula' (oBullet) po wystrzale zamiast lecieć 'prosto do celu', leciała do góry po parabolli. Tak jak jest np. prowadzony 'ogień' z haubicy.

Pozdrawiam.

Odnośnik do komentarza
Udostępnij na innych stronach

No witam!

Jeśli chodzi Ci mniej więcej o taki efekt:
lqZjX3M.gif

To miałem to samo pytanie w 2018r. 
Zrobiłem to za pomocą Konrada-GM i mój kod wyglądał mniej więcej tak:
CREATE pocisku:
 

///Caly kod inicjializacji strzelania
// wirtualna pozycja do wyliczenia "wygiecia"
ghost_x = x //to jest tak naprawde xstart
ghost_y = y //to jest tak naprawde ystart ale później będzie manipulacja tych dwóch zmiennych

// strona lotu czaru
// 1  - prawa strona
// -1 - lewa strona
var _pd = point_direction(x, y, oPlayer.x, oPlayer.y);
if(_pd > 90 and _pd < 270) wing = -1 else wing = 1 //prawo lub lewo

// poczatkowy dystans do celu
start_distance = point_distance(xstart, ystart, oPlayer.x, oPlayer.y);

//wybierz czy pocisk ma leciec gora czy dolem
way = choose(true, false);


 STEP pocisku:
 

// liczymy aktualna odleglosc
var distance = point_distance(ghost_x, ghost_y, oPlayer.x, oPlayer.y);
var angle = point_direction(ghost_x, ghost_y, oPlayer.x, oPlayer.y);
var angle90 = angle + 90 * wing; //90 - sila zagiecia

// glowna funkcja przesuniecia
var factor = sin((distance / start_distance) * pi);
var maxlen = sqr(log2(start_distance));

var offx = lengthdir_x(maxlen * factor, angle90);
var offy = lengthdir_y(maxlen * factor, angle90);


//  poruszamy obiektem w kierunku celu
var spd = irandom(7)+2;
ghost_x += lengthdir_x(spd, angle);
ghost_y += lengthdir_y(spd, angle);

// Zaginamy 
if(way) //w=true leci gora
{
    x = ghost_x + offx;
    y = ghost_y + offy;
}
else        //w=false leci dolem
{
    x = ghost_x - offx;
    y = ghost_y - offy;
}



Jeżeli chcesz obszernego wytłumaczenia, to poczytaj odpowiedź od @Konrad-GM, bo nieźle mi to wtedy wytłumaczył.

 

Odnośnik do komentarza
Udostępnij na innych stronach

Hej @SimianVirus7.
Po pierwsze dziękuję, za szybką odpowiedź. Naturalnie, post z 2018 widziałem, zamierzam cały wątek prześledzić dokładniej i wyciągnąć wnioski. 
Zasadniczo to w sumie o efekt lotu parabolicznego mi chodziło, z tym jednak zastrzeżeniem, że oEnemy porusza się ze stałą prędkością po path'ie. Boję się więc, że 'kula' będzie śledziła non stop wrogi obiekt i w konsekwencji tor lotu pocisku przypominać będzie odwróconą literę 'U', ale z jedną dużo dłuższą połową

Odnośnik do komentarza
Udostępnij na innych stronach

Cóż, chyba już wiem o co Ci chodzi. Ja zrobiłem to samo w swojej grze, czyli, że pocisk ma lecieć w miejsce w którym gracz był, kiedy był wystrzelony czar. Dla osiągnięcia takiego efektu, stworzyłem osobny obiekt "oTarget". Pojawiał się on podczas strzału w miejscu gracza i do niego odwoływał się pocisk przy obliczaniu x,y (w górnym przykładzie, wylicza on dystans odwołując się do oPlayer.x/oPlayer.y);

Mniej więcej tak wyglądałby pseudokod:


if(strzal == true)
{
	var _target = instance_create(oPlayer.x, oPlayer.y, oTarget) //wpisuje go do zmiennej, żeby nim manipulować
	var _pocisk = instance_create(x, y, oPocisk);
		_pocisk.target_x = _target.x; //przypisz dla pocisku współrzędną x celu
		_pocisk.target_y = _target.y; //przypisz dla pocisku współrzędną y celu
}


i wtedy każde wyliczenia odwołują się do target_x/target_y a nie do oPlayer.x/oPlayer.y

U siebie dodałem jeszcze, że jak pocisk ma kolizje z oTarget (tym przypisanym), to traci prędkość i znika po czasie. Efekt wyszedł taki:
Wizard2.gif

(Obiekt oTarget nie ma sprite, dlatego go nie widać)

Odnośnik do komentarza
Udostępnij na innych stronach

Rozwiązanie jakie ja używam u siebie w jednym projekcie to stworzenie zaokrąglanego nie zamkniętego path dla pocisku. Punkt początkowy i końcowy mamy. Wystarczy dodać pomiędzy nimi jeszcze jeden punkt w x = mean( x1, x2 ) i y = mean( y1, y2 )-50

Pocisk będzie podążał po path całkiem ładnym łukiem

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ę...