Skip to content
Advertisement

Pyglet game movement lagging behind

So, my snake makes a continuous movement, but if I press any key it goes back in time and lags back and forward. Here is a video: https://youtu.be/KCesu5bGiS8

My guess would be to update the key input faster, but when I do that everything updates faster, so the snake goes faster etc.

Code (as requested in text form) here:

import pyglet
import random

pyglet.resource.path = ["resources"]
pyglet.resource.reindex()
# sets the resource path


class Snake_Window(pyglet.window.Window):

    a = 0
    dtx = 160
    dty = 200
    # sets the basic direction and snake body x and y

    def __init__(self):
        super(Snake_Window, self).__init__(width=1280, height=720)
        # sets resolution and inherits

        self.key_handler = pyglet.window.key.KeyStateHandler()
        self.push_handlers(self.key_handler)
        # sets keys

        self.set_caption("Wild Snake")
        # gives it a name

        self.background_image = pyglet.resource.image("background.png")
        self.food_image = pyglet.resource.image("food.png")
        self.snake_head_image = pyglet.resource.image("snake_head.png")
        self.snake_body_image = pyglet.resource.image("snake_body.png")
        # makes images usable

        self.center_image(self.food_image)
        self.center_image(self.snake_head_image)
        self.center_image(self.snake_body_image)
        # centers the images using center_image

        self.snake_head = pyglet.sprite.Sprite(img=self.snake_head_image, x=200, y=200)
        self.snake_head.scale = 0.1
        self.snake_head.rotation = 270
        # sets snake_head as a image on screen

        self.snake_body = pyglet.sprite.Sprite(img=self.snake_body_image, x=self.dtx, y=self.dty)
        self.snake_body.scale = 0.1
        self.snake_body.rotation = 90
        # sets snake_body as a image on screen

        self.background = pyglet.sprite.Sprite(img=self.background_image, x=0, y=0)
        # sets background as a image on screen

        self.food = []
        # sets food

        pyglet.clock.schedule_interval(self.game_tick, 0.1)

    def center_image(self, image):
        # sets the center of the image to the actual center
        image.anchor_x = image.width / 2
        image.anchor_y = image.height / 2

    def update_snake_head(self):
        # makes the snake head go and sets the x and y for the body
        if self.a == 0:
            self.snake_head.x += 40
            self.dtx = self.snake_head.x - 40
            self.dty = self.snake_head.y
        elif self.a == 1:
            self.snake_head.x -= 40
            self.dtx = self.snake_head.x + 40
            self.dty = self.snake_head.y
        elif self.a == 2:
            self.snake_head.y += 40
            self.dty = self.snake_head.y - 40
            self.dtx = self.snake_head.x
        elif self.a == 3:
            self.snake_head.y -= 40
            self.dty = self.snake_head.y + 40
            self.dtx = self.snake_head.x

    def update_snake_body(self, dtx, dty):
        # makes the snakes body go
        self.snake_body.x = dtx
        self.snake_body.y = dty

    def game_tick(self, dt):
        # updates snakes head, snakes body, key presses and sets the background
        self.update_snake_head()
        self.update_snake_body(self.dtx, self.dty)
        self.draw_elements()
        self.key_press()
        print(dt)

    def draw_elements(self):
        # draws everything in window
        self.clear()
        self.background.draw()
        self.snake_head.draw()
        self.snake_body.draw()

    def key_press(self):
        # sets direction of snake upon key press and rotates his head accordingly
        if self.key_handler[pyglet.window.key.RIGHT]:
            if self.a == 1:
                pass
            else:
                self.a = 0
                self.snake_head.rotation = 270
        elif self.key_handler[pyglet.window.key.LEFT]:
            if self.a == 0:
                pass
            else:
                self.a = 1
                self.snake_head.rotation = 90
        elif self.key_handler[pyglet.window.key.UP]:
            if self.a == 3:
                pass
            else:
                self.a = 2
                self.snake_head.rotation = 180
        elif self.key_handler[pyglet.window.key.DOWN]:
            if self.a == 2:
                pass
            else:
                self.a = 3
                self.snake_head.rotation = 0


game_window = Snake_Window()

pyglet.app.run()

Advertisement

Answer

Converting all my comments into a answer instead. It won’t solve your problem completely. But due to lack of time, I’ll leave something useful at least that almost solves it.

The reason for these are a couple. One of them is that you use a scheduler to render stuff instead of using the built-in on_draw event. Can’t say for sure, but a good guess is that the graphical buffer gets updated/flipped automatically in on_draw while you’re doing your drawing and stuff in a side-chained render function. So moving all the rendering stuff into on_draw makes sense.

Another issue is that you don’t trigger on the actual key press, but instead you need to time the key press to each tick in the scheduler you got going – which you also have mushed into the rendering function. Essentially you’re doing eventhandling+rendering+updating+IO in one cluster*** of a function, heh. Instead, you should rely on on_key_press for keyboard events.

Lastly, you’re doing math operations all over the place – any of which might be half way done when you’re doing the actual rendering. That’s why you might get ghosting or odd artifacts (some things aren’t completely done updating positions etc).

But here is a almost working example of a few steps taken to get closer to what you want. If no one else (including you) haven’t solved this by a few days I’ll go ahead and re-write most of your code and point you in a few good directions (batches being one of them).

import pyglet
import random

pyglet.resource.path = ["resources"]
pyglet.resource.reindex()
# sets the resource path


class Snake_Window(pyglet.window.Window):

    a = 0
    dtx = 160
    dty = 200
    # sets the basic direction and snake body x and y

    def __init__(self):
        super(Snake_Window, self).__init__(width=1280, height=720)
        # sets resolution and inherits

        self.key_handler = pyglet.window.key.KeyStateHandler()
        self.push_handlers(self.key_handler)
        # sets keys

        self.set_caption("Wild Snake")
        # gives it a name

        self.background_image = pyglet.resource.image("background.png")
        self.food_image = pyglet.resource.image("food.png")
        self.snake_head_image = pyglet.resource.image("snake_head.png")
        self.snake_body_image = pyglet.resource.image("snake_body.png")
        # makes images usable

        self.center_image(self.food_image)
        self.center_image(self.snake_head_image)
        self.center_image(self.snake_body_image)
        # centers the images using center_image

        self.snake_head = pyglet.sprite.Sprite(img=self.snake_head_image, x=200, y=200)
        self.snake_head.rotation = 270
        # sets snake_head as a image on screen

        self.snake_body = pyglet.sprite.Sprite(img=self.snake_body_image, x=self.dtx, y=self.dty)
        self.snake_body.scale = 0.1
        self.snake_body.rotation = 90
        # sets snake_body as a image on screen

        self.background = pyglet.sprite.Sprite(img=self.background_image, x=0, y=0)
        # sets background as a image on screen

        self.food = []
        # sets food

        pyglet.clock.schedule_interval(self.game_tick, 0.1)

    def on_draw(self):
        self.draw_elements()

    def center_image(self, image):
        # sets the center of the image to the actual center
        image.anchor_x = image.width / 2
        image.anchor_y = image.height / 2

    def update_snake_head(self):
        # makes the snake head go and sets the x and y for the body
        if self.a == 0:
            self.snake_head.x += 40
            self.dtx = self.snake_head.x - 40
            self.dty = self.snake_head.y
        elif self.a == 1:
            self.snake_head.x -= 40
            self.dtx = self.snake_head.x + 40
            self.dty = self.snake_head.y
        elif self.a == 2:
            self.snake_head.y += 40
            self.dty = self.snake_head.y - 40
            self.dtx = self.snake_head.x
        elif self.a == 3:
            self.snake_head.y -= 40
            self.dty = self.snake_head.y + 40
            self.dtx = self.snake_head.x

    def update_snake_body(self, dtx, dty):
        # makes the snakes body go
        self.snake_body.x = dtx
        self.snake_body.y = dty

    def game_tick(self, dt):
        # updates snakes head, snakes body, key presses and sets the background
        self.update_snake_head()
        self.update_snake_body(self.dtx, self.dty)

    def draw_elements(self):
        # draws everything in window
        self.clear()
        self.background.draw()
        print('Head:', self.snake_head.x, self.snake_head.y, {0:'Right', 1:'Left', 2: 'Up', 3:'Down'}[self.a])
        self.snake_head.draw()
        self.snake_body.draw()
        self.flip()

    def on_key_press(self, symbol, modifier):
        # sets direction of snake upon key press and rotates his head accordingly
        if symbol == pyglet.window.key.ESCAPE:
            pyglet.app.exit()
        if symbol == pyglet.window.key.SPACE:
            print('Here')
        if symbol == pyglet.window.key.RIGHT:
            if self.a == 1:
                pass
            else:
                self.a = 0
                self.snake_head.rotation = 270
        elif symbol == pyglet.window.key.LEFT:
            if self.a == 0:
                pass
            else:
                self.a = 1
                self.snake_head.rotation = 90
        elif symbol == pyglet.window.key.UP:
            if self.a == 3:
                pass
            else:
                self.a = 2
                self.snake_head.rotation = 180
        elif symbol == pyglet.window.key.DOWN:
            if self.a == 2:
                pass
            else:
                self.a = 3
                self.snake_head.rotation = 0


game_window = Snake_Window()
pyglet.app.run()

I’ll leave you not only with this ish-working code, but a good advice.
Stop asking so many questions, and start learn ways to debug why things are happening the way they do. You’re shooting in the dark right now, asking questions hoping someone will solve the problems for you so you can focus on the fun stuff – which is the game development itself.
But what you’ll have a lot of use for later in life – is finding ways to debug, probe, understand and pinpoint why things are or aren’t happening the way you want.

Put some print("moo") here and there, print some values, add logging/debugging all over the place until you get wiser. It’s not always efficient, but it got me to this point with your code.

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement