El control Pyglet 3d no funciona como se esperaba
Actualmente estoy aprendiendo los conceptos básicos de pyglet y opengl. He visto varios tutoriales y sitios web para aprender pyglet y opengl, y pensé que haría un juego simple en 3D. Sin embargo, estoy atascado en los controles de movimiento de la cámara y parece que no puedo averiguar qué está mal con el código. Cuando presiono, Sla cámara se mueve hacia atrás normalmente, pero luego cuando presiono Wno se mueve, y si la presiono de nuevo, se mueve pero un poco más rápido que antes. ¿Por qué está pasando esto?
from pyglet.gl import *
from pyglet.window import key
import math
class Triangle:
def __init__(self):
self.vertices = pyglet.graphics.vertex_list(3, ('v3f', [-0.5, -0.5, 0.0, 0.5, -0.5, 0.0, 0.0, 0.5, 0.0]),
('c3B', [100, 200, 220, 200, 110, 100, 100, 250, 100]))
class Quad:
def __init__(self):
self.vertices = pyglet.graphics.vertex_list_indexed(4, [0, 1, 2, 2, 3, 0],
('v3f', [-0.5, -0.5, 0.0, 0.5, -0.5, 0.0, 0.5, 0.5, 0.0, -0.5, 0.5, 0.0]),
('c3f', [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0]))
class Player:
def __init__(self):
self.position = [0, 0, 0]
self.rotation = [0, 0]
self.change_x = 0
self.change_z = 0
self.speed = 1
def controls(self, keys):
self.change_x = 0
self.change_z = 0
if keys == key.W:
self.change_z = self.speed
if keys == key.S:
self.change_z = -self.speed
if keys == key.A:
self.change_x = -self.speed
if keys == key.D:
self.change_x = self.speed
self.position[0] += self.change_x
self.position[2] += self.change_z
class Window(pyglet.window.Window):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.set_minimum_size(300, 300)
glClearColor(0.2, 0.3, 0.2, 1.0)
gluPerspective(90, 0.5, 0.01, 1000)
self.quad = Quad()
self.player = Player()
def on_key_press(self, KEY, MOD):
self.player.controls(KEY)
def on_draw(self):
self.clear()
glTranslatef(*self.player.position)
self.quad.vertices.draw(GL_TRIANGLES)
def on_resize(self, width, height):
glViewport(0, 0, width, height)
if __name__ == '__main__':
window = Window(500, 500, 'My Window', resizable = True)
pyglet.app.run()
Respuestas
Probablemente no entendiste la glTranslatefunción.
glTranslatefunciona de tal manera que toma la matriz actual y la multiplica con una matriz de traducción dada por los parámetros de glTranslate.
Entonces, llamar a glTranslate (x, y, z) da como resultado la siguiente ecuación:
new_position = old_position + (x, y, z)
Lo que hace (x, y, z), si llama a glTranslatecada cuadro, la tasa de cambio (es decir, la velocidad).
¿Por qué se detiene cuando presiono S y W?
Bueno, echemos un vistazo al código y la ecuación. Usas self.positioncomo parámetro para glTranslate. Entonces, tu self.positionno es la posición sino la velocidad actual (o tasa de cambio) de la cámara.
Si presiona Suna vez, on_key_pressserá llamado, con los siguientes efectos:
self.change_z = -self.speed
self.position[2] += self.change_z # self.position[2] equals now -self.speed
Ahora presione Wuna vez, una vez más on_key_pressserá llamado nuevamente, resultando en esto:
self.change_z = +self.speed
self.position[2] += self.change_z # self.position[2] equals now 0, because self.position[2] was -self.speed; -self.speed + self.speed = 0
La implicación es que cada vez que presiona cualquiera de las teclas de control, acelera la cámara discretamente.
Suponiendo que presionó Sdos veces después de iniciar el programa, el resultado sería self.position[2]igual a 2 * -self.speed.
¿Cómo arreglar esto?
Cambiar lo siguiente
self.position[0] += self.change_x
self.position[2] += self.change_z
a
self.position[0] = self.change_x
self.position[2] = self.change_z
Realmente espero haber dejado claro, por qué self.positiones en realidad una velocidad y no la posición. Le sugiero que cambie el nombre self.positiona self.velocityo algo más a lo largo de las líneas.
Alternativamente, puede reconstruir la matriz cada vez que cambie su posición haciendo lo siguiente:
def on_draw(self):
self.clear()
glLoadIdentity()
gluPerspective(90, 0.5, 0.01, 1000)
glTranslatef(*self.player.position)
self.quad.vertices.draw(GL_TRIANGLES)
No puedo evitar dar un paso más. El hecho de que self.positionsea solo una velocidad (¡en su versión original!), Se hace evidente si agrega otro método:
class Window(...):
# ...
def update(self, dt):
self.clear()
glTranslatef(*self.player.position)
self.quad.vertices.draw(GL_TRIANGLES)
y ampliar Window.__init__con las siguientes líneas:
class Window(...):
def __init__(...):
# ...
import pyglet.clock
pyglet.clock.schedule_interval(self.update, 1/60)
# pyglet now calls update(...) 60 times a second