Search code examples
pythonpyglet

Smooth movement in pyglet


So after using Tkinter for our game, we decided to move over to Pyglet. But one of the problems I am having is the movement, in Tkinter I was able to make a smooth movement system but in pyglet all I can do is get the character to move in a jittery way.

import pyglet
from pyglet.window import key, Window
from pyglet import clock
from threading import Timer

X = 5 #Speed of the player
w = 0 #Controls +y movement
a = 0 #Controls -x movement
s = 0 #Controls -y movement
d = 0 #Controls +x movement

window = Window(width = 500, height = 500) #Defines window

MainChar = pyglet.image.load("Mainchar.png") #Loads the Mainchar.png
Player = pyglet.sprite.Sprite(MainChar, x = 0, y = 0) #Makes MainChar into a sprite

@window.event
def on_key_press(symbol, modifiers): #Looks for a keypress
    print("keypress")
    if symbol == key.W:
        global w
        global a
        global s
        global d
        w = True
    elif symbol == key.A:
        a = True
    elif symbol == key.S:
        s = True
    elif symbol == key.D:
        d = True

@window.event
def on_key_release(symbol, modifiers):
    print("keyup")
    if symbol == key.W:
        w = False
    elif symbol == key.A:
        a = False
    elif symbol == key.S:
        s = False
    elif symbol == key.D:
        d = False
@window.event
def moveT():
    print("cycle")
    def moveD():
        if w == True:
            Player.y += 0.1
        elif a == True:
            Player.x -= 5
        elif s == True:
            Player.y -= 5
        elif d == True:
            Player.x += 5
        moveT()
    moveTimer = Timer(0.01, moveD)
    moveTimer.start()

@window.event
def on_draw():
    window.clear()
    Player.draw()

moveT()
pyglet.app.run()

The reason I have w, a, s and d as bools, this is so I can move the character with the key held instead of a keypress.

Any help would be wonderful, thanks in advance!


Solution

  • The issue is that you use pythons threading. This doesn't trigger the pyglet window to be redrawn.
    You've to use pyglet.clock and to schedule a function to be called every time the clock is ticked. This causes that the pyglet window is updated, too and the on_draw() event is triggered. e.g.:

    @window.event
    def moveT(dt):
    
        if w == True:
            Player.y += 0.1
        elif s == True:
            Player.y -= 5
    
        if a == True:
            Player.x -= 5
        elif d == True:
            Player.x += 5
    
    pyglet.clock.schedule_interval(moveT, 1 / 60)
    

    Further more w, a, s and d have to be declared global in on_key_release, too.

    import pyglet
    from pyglet.window import key, Window
    from pyglet import clock
    
    X = 5 #Speed of the player
    w, a, s, d = False, False, False, False 
    
    window = Window(width = 500, height = 500) #Defines window
    
    MainChar = pyglet.image.load("Mainchar.png")
    Player = pyglet.sprite.Sprite(MainChar, x = 0, y = 0)
    
    @window.event
    def on_key_press(symbol, modifiers): #Looks for a keypress
        global w, a, s, d
        if symbol == key.W:
            w = True
        elif symbol == key.A:
            a = True
        elif symbol == key.S:
            s = True
        elif symbol == key.D:
            d = True
    
    @window.event
    def on_key_release(symbol, modifiers):
        global w, a, s, d
        if symbol == key.W:
            w = False
        elif symbol == key.A:
            a = False
        elif symbol == key.S:
            s = False
        elif symbol == key.D:
            d = False
    
    @window.event
    def moveT(dt):
    
        if w == True:
            Player.y += 0.1
        elif s == True:
            Player.y -= 5
    
        if a == True:
            Player.x -= 5
        elif d == True:
            Player.x += 5
    
    @window.event
    def on_draw():
        window.clear()
        Player.draw()
    
    pyglet.clock.schedule_interval(moveT, 1 / 60)
    pyglet.app.run()