Reputation: 23
I am currently learning the basics of pyglet and opengl. I have watched a number of tutorials and websites to learn pyglet and opengl, and I thought I would make a simple 3d game. However I am stuck on the camera movement controls and I can't seem to figure out what is wrong with the code. When I press S
the camera moves back normally, but then when I press W
it doesn't move, and if I press it again it moves but a little faster than before. Why is this happening?
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()
Upvotes: 2
Views: 132
Reputation: 754
You probably misunderstood the glTranslate
function.
glTranslate
works in such a way, that it takes the current matrix and multiplies with a translation matrix given by parameters of glTranslate
.
So, calling glTranslate(x, y, z) results in the following equation:
new_position = old_position + (x, y, z)
Which makes (x, y, z), if you call glTranslate
every frame, the rate of change (i.e. the velocity).
Well, let's take a look at the code and the equation. You use self.position
as parameter for glTranslate
. So, your self.position
is not the position but the current velocity (or rate of change) of the camera.
If you press S
once, on_key_press
will be called, with following effects:
self.change_z = -self.speed
self.position[2] += self.change_z # self.position[2] equals now -self.speed
Now press W
once, yet again on_key_press
will be called again, resulting in this:
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
The implication is that every time you press either control key, you accelerate your camera discretely.
Assuming you pressed S
twice after starting the program would cause self.position[2]
to equal to 2 * -self.speed
.
Change the following
self.position[0] += self.change_x
self.position[2] += self.change_z
to
self.position[0] = self.change_x
self.position[2] = self.change_z
I really hope I made it clear, why self.position
is actually a velocity and not the position. I suggest you rename self.position
to self.velocity
or something else along the lines.
Alternatively you can rebuild the matrix every time you change your position by doing the following:
def on_draw(self):
self.clear()
glLoadIdentity()
gluPerspective(90, 0.5, 0.01, 1000)
glTranslatef(*self.player.position)
self.quad.vertices.draw(GL_TRIANGLES)
I cannot help but give a further step. The fact that self.position
is just a velocity (in your original version!), becomes apparent if you add a another method:
class Window(...):
# ...
def update(self, dt):
self.clear()
glTranslatef(*self.player.position)
self.quad.vertices.draw(GL_TRIANGLES)
and extend Window.__init__
with the following lines:
class Window(...):
def __init__(...):
# ...
import pyglet.clock
pyglet.clock.schedule_interval(self.update, 1/60)
# pyglet now calls update(...) 60 times a second
Upvotes: 1