#python-3.x #opengl #3d #pyglet
#python-3.x #opengl #3D #pyglet
Вопрос:
В настоящее время я изучаю основы pyglet и opengl. Я просмотрел несколько руководств и веб-сайтов по изучению pyglet и opengl, и я подумал, что мог бы создать простую 3D-игру. Однако я застрял на элементах управления движением камеры и, похоже, не могу понять, что не так с кодом. Когда я нажимаю, S
камера нормально перемещается назад, но затем, когда я нажимаю W
, она не перемещается, и если я нажимаю ее снова, она перемещается, но немного быстрее, чем раньше. Почему это происходит?
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()
Ответ №1:
Вероятно, вы неправильно поняли glTranslate
функцию.
glTranslate
работает таким образом, что он принимает текущую матрицу и умножает ее на матрицу преобразования, заданную параметрами glTranslate
.
Итак, вызов glTranslate(x, y, z) приводит к следующему уравнению:
new_position = old_position (x, y, z)
Что делает (x, y, z), если вы вызываете glTranslate
каждый кадр, скорость изменения (т. Е. скорость).
Почему он останавливается, когда я нажимаю S и W?
Что ж, давайте взглянем на код и уравнение. Вы используете self.position
в качестве параметра для glTranslate
. Итак, ваше self.position
значение — это не положение, а текущая скорость (или скорость изменения) камеры.
Если вы нажмете S
один раз, on_key_press
будет вызван, со следующими эффектами:
self.change_z = -self.speed
self.position[2] = self.change_z # self.position[2] equals now -self.speed
Теперь нажмите W
один раз, еще раз on_key_press
будет вызван снова, в результате чего это:
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
Подразумевается, что каждый раз, когда вы нажимаете любую клавишу управления, вы дискретно ускоряете свою камеру.
Предполагая, что вы нажали S
дважды после запуска программы, это приведет к self.position[2]
равному 2 * -self.speed
.
Как это исправить?
Измените следующее
self.position[0] = self.change_x
self.position[2] = self.change_z
Для
self.position[0] = self.change_x
self.position[2] = self.change_z
Я действительно надеюсь, что прояснил, почему self.position
на самом деле это скорость, а не позиция. Я предлагаю вам переименовать self.position
в self.velocity
или что-то еще в этом роде.
В качестве альтернативы вы можете перестраивать матрицу каждый раз, когда меняете свою позицию, выполнив следующее:
def on_draw(self):
self.clear()
glLoadIdentity()
gluPerspective(90, 0.5, 0.01, 1000)
glTranslatef(*self.player.position)
self.quad.vertices.draw(GL_TRIANGLES)
Я не могу не дать следующий шаг. Тот факт, что self.position
это просто скорость (в вашей оригинальной версии!), становится очевидным, если вы добавите другой метод:
class Window(...):
# ...
def update(self, dt):
self.clear()
glTranslatef(*self.player.position)
self.quad.vertices.draw(GL_TRIANGLES)
и расширьте Window.__init__
следующими строками:
class Window(...):
def __init__(...):
# ...
import pyglet.clock
pyglet.clock.schedule_interval(self.update, 1/60)
# pyglet now calls update(...) 60 times a second
Комментарии:
1. Спасибо за ответ. Однако теперь, когда я нажимаю клавиши, экран становится фиолетовым или зеленым.