Contromisura per aver capovolto la griglia delle coordinate?

1

Quindi sto usando pygame per creare un semplice sparatutto dall'alto verso il basso, e sto facendo molti calcoli con l'angolo dalla prospettiva dall'alto verso il basso. Usiamo una semplice freccia e una palla come esempio, voglio che la freccia rossa continui a puntare sulla palla blu indipendentemente da dove si muove la pallina blu:

Emièsembratoabbastanzafacile,avevosolobisognodiatan2:

angle=math.atan2(blue.y-red.y,blue.x-red.x)

Mailproblemaècheatan2funzionaperunagrigliadicoordinatematematichecomequesta:

Dovealpha=math.atan2(blue.y-red.y,blue.x-red.x)

Malacosaconpygame(almenosuWindows)èchelagrigliadellecoordinatenonfunzionacomeunagrigliadicoordinatematematiche,inrealtàècapovoltaapartiredall'angoloinaltoasinistradellafinestradigioco:

Quindi,mentresembrachelapallinablusiapiùinaltoequindimatematicamenteblue.ydovrebbeesseremaggioredired.y,questoinrealtànonèilcasoacausadellagrigliadicoordinatecapovolta,chemath.atan2()diPythonnonloso,eilcalcolooriginalechehoavuto:

angle=math.atan2(blue.y-red.y,blue.x-red.x)

Produceeffettivamentelanegazionedell'angolocorretto.

Oral'ovviaprimasoluzionechehotrovatoèstatadicapovolgereilsegno,eabbastanzagiustohafunzionatoconquesto:

angle=-math.atan2(blue.y-red.y,blue.x-red.x)

Maiproblemisonoricominciatiunavoltacheavevobisognodifareulterioricalcolibasatisull'angolocalcolatoinprecedenza,chetecnicamenteèoracapovolto.

Qualicontromisurepossoprendereper"permanentemente" sbarazzarmi di questo problema?

Ecco un esempio reale di dove ho bisogno di questo, ho un'entità "zombi" che non fa altro che seguire l'obiettivo che è stato dato:

class Zombie(Entity):

    def __init__(self, *args, target=None, **kwargs):
        super().__init__(*args, **kwargs)
        self.target = target

    def update(self, dt, app):
        if self.target:
            # Face towards target
            dx = self.target.x - self.x
            dy = self.target.y - self.y
            self.angle = math.atan2(dy, dx)
            # Change velocity towards target
            speed = self.get_max_speed()
            vel_x = math.cos(angle) * speed
            vel_y = math.sin(angle) * speed
            self.velocity = (vel_x, vel_y)
        else:
            self.velocity = (0, 0)
        # Moves the zombie based on velocity
        super().update(dt, app)

Per questo caso specifico sono riuscito a risolverlo memorizzando l'angolo in una variabile separata per un uso successivo, e annullandolo separatamente dopo aver impostato self.angle :

# Face towards target
dx = self.target.x - self.x
dy = self.target.y - self.y
angle = math.atan2(dy, dx)
self.angle = -angle
# Change velocity towards target
speed = self.get_max_speed()
vel_x = math.cos(angle) * speed
vel_y = math.sin(angle) * speed
self.velocity = (vel_x, vel_y)

Ma questo è solo l'elemosina di altri bug, e sto cercando una soluzione più generica al problema.

    
posta Markus Meskanen 10.12.2017 - 05:59
fonte

1 risposta

7

Basta capovolgere la forma al momento del rendering (la parte finale dell'elaborazione) se il sistema di coordinate ti provoca mal di testa invece di provare ad affrontarlo in tutte le fasi intermedie in anticipo.

draw_shape(shape.x, screen.h - shape.y - shape.h, ...)

In pratica otterrai il sistema di coordinate come preferisci con + y andando verso l'alto e un valore y di 0 nella parte inferiore dello schermo, non in cima.

Se questo è poco pratico con quello che hai fatto finora, potresti semplicemente scrivere te stesso alcune funzioni trigonometriche che funzionano intuitivamente dato il sistema di coordinate che stai affrontando, come una funzione sinusoidale che restituisce una negazione del normale valore y o una che immette i valori capovolti (come nell'esempio precedente usando screen.h-shape.y ). Puoi risolverlo a livello di input o di output. Penso che il modo più semplice sia l'input.

Negare l'arcotangente mi fa un po 'male al cervello, cercando di visualizzare nel mio cervello la trasformazione tra i sistemi di coordinate (non aiuta che io sia veramente assonnato). Penso che potresti semplicemente annullare il vel_y .

Un'altra soluzione che funziona indipendentemente dal sistema di coordinate è usare la matematica vettoriale invece di lavorare con gli angoli con trig. Puoi ottenere la direzione semplicemente sottraendo la posizione del nemico dalla posizione del proiettile e quindi normalizzando il vettore risultante, e quindi moltiplicando per la velocità per ottenere la velocità.

vec.x = projectile.x - enemy.x
vec.y = projectile.y - enemy.y
vec_len_squared = vec.x*vec.x + vec.y*vec.y
if vec_len2 > 0:
    vec_rlen = 1.0 / sqrt(vec_len_squared)
    vec.x = (vec.x * vec_rlen) * speed
    vec.y = (vec.y * vec_rlen) * speed

Non ho usato trig in anni quindi questo almeno mi rende più facile.

    
risposta data 10.12.2017 - 06:27
fonte

Leggi altre domande sui tag