Actualmente estoy escribiendo un juego muy simple usando python y pygame. Tiene cosas que se mueven. Y para hacer que estas cosas se movieran sin problemas, arreglé el bucle principal del juego como se dice en Fix Your Timestep, con interpolación.¿Cómo manejarías la interpolación en un juego de pitón?
Así es como manejo la interpolación ahora.
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]
Las funciones y tipos de datos lerp_xy()
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')
Los tipos de datos son, por supuesto temporal, pero todavía esperan que tendrán la X e Y. atributos en el futuro. actualización: lerper.alpha se actualiza cada cuadro.
El envío se agrega como un único objeto: es la nave del jugador. Las estrellas se agregan como una lista. Las viñetas se agregan como dict {id, Bullet}, ya que las viñetas se agregan y eliminan todo el tiempo, tengo que rastrear qué viñeta es la que, interpolar si ambas están presentes y hacer algo si solo se ha agregado o eliminado.
De todos modos este código aquí es una mierda. Creció a medida que añadí funciones, y ahora quiero reescribirlo para que sea más genérico, para que pueda seguir creciendo y no convertirse en una pila de poo unpythonic apestosa.
Ahora sigo siendo bastante nuevo en Python, aunque ya me siento bastante cómodo con la lista de comprensiones, generadores y corutinas.
Lo que menos experiencia tengo es el lado OO de Python, y el diseño de una arquitectura de algo más grande que un script desechable de 10 líneas.
La pregunta no es una pregunta como en algo que no sé y no puedo hacer nada al respecto. Estoy seguro de que soy capaz de volver a escribir este código bastante simple que funcionará de alguna manera cerca de lo que quiero.
Lo que sí quiero saber, es la forma en que los programadores experimentados de Python resolverán este problema simple de manera pitónica, así que (y por supuesto otros) podría aprender lo que se considera una forma elegante de manejar este caso entre Python desarrolladores.
Por lo tanto, lo que quiero lograr aproximadamente, en pseudocódigo:
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())
Sin embargo no deje que eso le impida pseudocódigo si usted tiene una mejor solución en mente =)
So. Hacer todos los objetos del juego como una clase separada/heredada? ¿Forzarlos a todos a tener id? Agrégalos todos como list/dict lerper.add([ship])
? Haz una clase de contenedor especial heredando de dict/whatever? ¿Qué consideras una forma elegante y pitónica de resolver esto? ¿Como lo harias?
¿Leyó usted toda la cuestión? No veo nada relacionado con la interpolación o el problema que presenté en su respuesta. La única "idea" que veo en tu respuesta es "haz que cada objeto del juego maneje su propia interpolación", pero ni siquiera lo mencionas O.o – Mikka
Quizás malentendí tu pregunta. Lo interpreto en el sentido de "¿Cómo reviso mi juego para que sea más genérico y se pueda expandir fácilmente?". Si su pregunta fue en realidad "¿Cómo reviso mi algoritmo de interpolación para que sea más genérico?", Entonces ya ha adivinado mi opinión: haga que cada objeto del juego maneje su propia interpolación. (preferiblemente solo una vez, en la clase base del Proyectil) – Kevin