Pyglet 3d 控件无法按预期工作
Pyglet 3d control not working as intended
我目前正在学习 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()
您可能误解了 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
我目前正在学习 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()
您可能误解了 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