Attualmente sto scrivendo un gioco molto semplice usando python e pygame. Ha cose che si muovono. E per far muovere questa roba senza problemi ho organizzato il ciclo di gioco principale come detto in Fix Your Timestep, con interpolazione.Come gestireste l'interpolazione in un gioco Python?
Ecco come gestisco l'interpolazione ora.
class Interpolator(object):
"""Handles interpolation"""
def __init__(self):
self.ship_prev = None
self.ship = None
self.stars_prev = []
self.stars = []
self.bullets_prev = {}
self.bullets = {}
self.alpha = 0.5
def add_ship(self, ship):
self.ship_prev = self.ship
self.ship = ship
def add_stars(self, stars):
self.stars_prev = self.stars
self.stars = stars[:]
def add_bullets(self, bullets):
self.bullets_prev = self.bullets
self.bullets = bullets.copy()
def add_enemies(self, enemies):
self.enemies_prev = self.enemies
self.enemies = enemies # to be continued
def lerp_ship(self):
if self.ship_prev is None:
return self.ship
return lerp_xy(self.ship_prev, self.ship, self.alpha)
def lerp_stars(self):
if len(self.stars_prev) == 0:
return self.stars
return (lerp_xy(s1, s2, self.alpha) for s1, s2 in izip(self.stars_prev, self.stars))
def lerp_bullets(self):
keys = list(set(self.bullets_prev.keys() + self.bullets.keys()))
for k in keys:
# interpolate as usual
if k in self.bullets_prev and k in self.bullets:
yield lerp_xy(self.bullets_prev[k], self.bullets[k], self.alpha)
# bullet is dead
elif k in self.bullets_prev:
pass
# bullet just added
elif k in self.bullets:
yield self.bullets[k]
I lerp_xy() funzioni e tipi di dati
def lerp_xy(o1, o2, alpha, threshold=100):
"""Expects namedtuples with x and y parameters."""
if sqrt((o1.x - o2.x) ** 2 + (o1.y - o2.y) ** 2) > 100:
return o2
return o1._replace(x=lerp(o1.x, o2.x, alpha), y=lerp(o1.y, o2.y, alpha))
Ship = namedtuple('Ship', 'x, y')
Star = namedtuple('Star', 'x, y, r')
Bullet = namedtuple('Bullet', 'x, y')
I tipi di dati sono ovviamente temporanea, ma ho ancora aspettare avranno la x ed y attributi in futuro. Aggiornamento : lerper.alpha viene aggiornato ogni frame.
La nave viene aggiunta come un singolo oggetto: è la nave giocatore. Le stelle vengono aggiunte come elenco. I proiettili sono aggiunti come dict {id, Bullet}, poiché i proiettili vengono aggiunti e rimossi in continuazione, devo tenere traccia di quale pallino è che, interpolare se entrambi sono presenti e fare qualcosa se è stato appena aggiunto o eliminato.
In ogni caso questo codice qui è schifo. Cresceva man mano che aggiungevo funzionalità, e ora voglio riscriverlo per essere più generico, in modo che possa continuare a crescere e non diventare un non banale mucchio di cacca puzzolente.
Ora sono ancora piuttosto nuovo in Python, anche se mi sento abbastanza a mio agio con le list comprehensions, i generatori e le coroutine già.
Quello che ho meno esperienza è il lato OO di Python e la progettazione di un'architettura di qualcosa di più grande di uno script usa e getta di 10 righe.
La domanda non è una domanda come in qualcosa che non conosco e non posso farci nulla. Sono sicuro di essere in grado di riscrivere questo codice piuttosto semplice che funzionerà in qualche modo vicino a ciò che voglio.
Quello che voglio sapere, è il modo in cui i programmatori Python esperti risolvono questo semplice problema in modo pironico, così io (e naturalmente altri) potrei imparare quello che è considerato un modo elegante di gestire un caso simile tra Python sviluppatori.
Quindi, quello che circa voglio raggiungere, in pseudocodice:
lerper = Interpolator()
# game loop
while(1):
# physics
# physics done
lerper.add(ship)
lerper.add(stars)
lerper.add(bullets)
lerper.add(enemies) # you got the idea
# rendering
draw_ship(lerper.lerp('Ship'))
# or
draw_ship(lerper.lerp_ship())
Tuttavia non lasciatevi pseudocodice si ferma se si dispone di una soluzione migliore in mente =)
So. Rendi tutti gli oggetti di gioco come classe separata/ereditata? Costringili tutti ad avere l'id? Aggiungili tutti come lista/dict lerper.add([ship])
? Crea una classe contenitore speciale ereditando da Dict/Qualunque? Cosa consideri un modo elegante e pitonioso per risolvere questo? Come lo faresti?
Hai letto tutta la questione? Non vedo nulla relativo all'interpolazione o al problema che ho presentato nella risposta. L'unica "idea" che vedo nella tua risposta è "fai in modo che ogni oggetto di gioco gestisca la propria interpolazione", ma non lo menzioni nemmeno O.o – Mikka
Forse ho frainteso la tua domanda. Intendevo dire: "Come posso modificare il mio gioco in modo che sia più generico e possa essere facilmente ampliato?". Se la tua domanda era in realtà "Come posso modificare il mio algoritmo di interpolazione per essere più generico?", Hai già indovinato la mia opinione: fai in modo che ogni oggetto di gioco gestisca la propria interpolazione. (preferibilmente solo una volta, nella classe base di Projectile) – Kevin