Python 3.x Pyglet 3d控件未按预期工作

Python 3.x Pyglet 3d控件未按预期工作,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:

我目前正在学习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键上的
\u press
,其效果如下:

self.change_z = -self.speed
self.position[2] += self.change_z # self.position[2] equals now -self.speed
现在按一次
W
,然后再次调用按键上的
\u 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
实际上是一个速度,而不是位置。我建议您将
self.position
重命名为
self.velocity
或类似的名称


或者,您可以在每次更改位置时通过执行以下操作重建矩阵:

def on_draw(自):
self.clear()
glLoadIdentity()
透视图(90,0.5,0.01,1000)
GLTRANSTEF(*self.player.position)
self.quad.vertices.draw(GL_三角形)

我不得不再进一步。如果您添加另一种方法,
self.position
只是一种速度(在您的原始版本中!),这一事实就会变得显而易见:

class Window(...):

    # ...

    def update(self, dt):
        self.clear()
        glTranslatef(*self.player.position)
        self.quad.vertices.draw(GL_TRIANGLES)
并使用以下行扩展
窗口

class Window(...):
    def __init__(...):
        # ...

        import pyglet.clock
        pyglet.clock.schedule_interval(self.update, 1/60)
        # pyglet now calls update(...) 60 times a second
    


谢谢你的回答。但是现在,当我按下这些键时,屏幕会变成紫色或绿色。
class Window(...):
    def __init__(...):
        # ...

        import pyglet.clock
        pyglet.clock.schedule_interval(self.update, 1/60)
        # pyglet now calls update(...) 60 times a second