Ahmad Zaid
Ahmad Zaid

Reputation: 3

Animation In Pyglet using image region

import pyglet
from pyglet.window import Window, mouse, gl
from pyglet.image.codecs.png import PNGImageDecoder




window = pyglet.window.Window(
                790, 640,
              resizable=False,                                                  # Make sure it is not resizable
              caption="Something",                                     # Caption of window
              config=pyglet.gl.Config(double_buffer=True),                      # Avoids flickers
              vsync=False)

kitten = pyglet.image.load('bar.png', decoder=PNGImageDecoder())
image_part = kitten.get_region(x=0, y=0, width=400, height=40)
ball = pyglet.sprite.Sprite(image_part, x=50, y=20+50)
ball.scale = 0.25

image = kitten.get_region(x=0, y=40, width=400, height=40)
lol = pyglet.sprite.Sprite(image, x=50, y=30+50)
lol.scale = 0.25

a = kitten.get_region(x=0, y=80, width=200, height=40)
ab = pyglet.sprite.Sprite(a, x=50, y=40+50)
ab.scale = 0.25

def update(self, dt):
   on_draw()

@window.event
def on_draw():
    window.clear()
    pyglet.gl.glClearColor(255,255,255,255)
    lol.draw()
    ball.draw()
    ab.draw()

def update(dt):
    on_draw()   
pyglet.clock.schedule_interval(update, 1/60)


pyglet.app.run()

I am trying to make 2d animation of sorting algorithms and have no idea on how to animate the image-regions. when run this code, It gives three static bars on the screen, all I need is to switch their pplaces..! THanks for the help

Upvotes: 0

Views: 959

Answers (2)

furas
furas

Reputation: 142631

You have to change something in update to see animation - ie. you can move object

Simple example.

import pyglet

window = pyglet.window.WWindow(
                790, 640,
              resizable=False,                                                  # Make sure it is not resizable
              caption="Something",                                     # Caption of window
              config=pyglet.gl.Config(double_buffer=True),                      # Avoids flickers
              vsync=False)

image = pyglet.image.load('bar.png')

region = image.get_region(x=0, y=0, width=400, height=40)
ball = pyglet.sprite.Sprite(region, x=50, y=20+50)
ball.scale = 0.25

region = image.get_region(x=0, y=40, width=400, height=40)
lol = pyglet.sprite.Sprite(region, x=50, y=30+50)
lol.scale = 0.25

region = image.get_region(x=0, y=80, width=200, height=40)
ab = pyglet.sprite.Sprite(region, x=50, y=40+50)
ab.scale = 0.25

@window.event
def on_draw():
    window.clear()
    pyglet.gl.glClearColor(255, 255, 255, 255)
    ball.draw()
    lol.draw()
    ab.draw()

def update(dt):
    # change something
    ball.x += 1
    lol.y += 1
    ab.scale += 0.1

    #on_draw() # you don't need it - pyglet will do it

pyglet.clock.schedule_interval(update, 1/60)

pyglet.app.run()

Upvotes: 0

Torxed
Torxed

Reputation: 23480

You're simply never updating lol.x = <new pos>.
This should be done in your later update:

def update(dt):
    ball.x += 10

Most of the time you don't need to worry about updating the graphics either, but in on_draw() you might as well call for a screen updated via:

def on_draw():
    window.clear()
    lol.draw()
    window.flip()

And as someone pointed out, naming two functions def update() will cause the later one to replace the first one.

Since you're working with sprites, I thought I'd give you a neat little sprite class that might work better for you than static images.

import pyglet
from pyglet.gl import *

class Bar(pyglet.sprite.Sprite):
    def __init__(self, width=20, height=200, color="#C2C2C2", x=0, y=0):
        # == Must generate a texture before initialization of Sprite()
        self.texture = self.gen_solid_img(width, height, color)

        super(Bar, self).__init__(self.texture)

        self.y = y
        self.x = x

    def gen_solid_img(self, width, height, c, alpha=255):
        c = c.lstrip("#")
        c = max(6-len(c),0)*"0" + c
        r = int(c[:2], 16)
        g = int(c[2:4], 16)
        b = int(c[4:], 16)
        c = (r,g,b,int(alpha))
        return pyglet.image.SolidColorImagePattern(c).create_image(width,height)

    def draw_border(self, color=(0.2, 0.2, 0.2, 0.5)):
        self.draw_line((self.x, self.y), (self.x, self.y+self.height), color)
        self.draw_line((self.x, self.y+self.height), (self.x+self.width, self.y+self.height), color)
        self.draw_line((self.x+self.width, self.y+self.height), (self.x+self.width, self.y), color)
        self.draw_line((self.x+self.width, self.y), (self.x, self.y), color)

One example of using this would be to replace:

kitten = pyglet.image.load('bar.png', decoder=PNGImageDecoder())
image_part = kitten.get_region(x=0, y=0, width=400, height=40)
ball = pyglet.sprite.Sprite(image_part, x=50, y=20+50)
ball.scale = 0.25

with:

ball = Bar(x=0, y=0, width=400, height=40)

I would also recommend switching from decorators to a inherited class structure just so it's easier to work with each object as your code grows.

A basic class skeleton would look like this:

import pyglet
from pyglet.gl import *

key = pyglet.window.key

class main(pyglet.window.Window):
    def __init__ (self):
        super(main, self).__init__(800, 600, fullscreen = False, vsync=False)
        self.x, self.y = 0, 0

        self.bg = pyglet.sprite.Sprite(pyglet.image.load('background.jpg'))
        self.sprites = {}
        self.alive = 1

    def on_draw(self):
        self.render()

    def on_close(self):
        self.alive = 0

    def on_key_press(self, symbol, modifiers):
        if symbol == key.ESCAPE: # [ESC] is pressed
            self.alive = 0

    def render(self):
        self.clear()
        self.bg.draw()

        for sprite_name, sprite_obj in self.sprites.items():
            sprite_obj.draw()

        self.flip()

    def run(self):
        while self.alive == 1:
            self.render()

            # -----------> This is key <----------
            # This is what replaces pyglet.app.run()
            # but is required for the GUI to not freeze
            #
            event = self.dispatch_events()

x = main()
x.run()

Now merging these two class based code snippets together and you should have something that looks like this:

import pyglet
from pyglet.gl import *

key = pyglet.window.key

class Bar(pyglet.sprite.Sprite):
    def __init__(self, width=20, height=200, color="#C2C2C2", x=0, y=0):
        # == Must generate a texture before initialization of Sprite()
        self.texture = self.gen_solid_img(width, height, color)

        super(Bar, self).__init__(self.texture)

        self.y = y
        self.x = x

    def gen_solid_img(self, width, height, c, alpha=255):
        c = c.lstrip("#")
        c = max(6-len(c),0)*"0" + c
        r = int(c[:2], 16)
        g = int(c[2:4], 16)
        b = int(c[4:], 16)
        c = (r,g,b,int(alpha))
        return pyglet.image.SolidColorImagePattern(c).create_image(width,height)

    def draw_border(self, color=(0.2, 0.2, 0.2, 0.5)):
        self.draw_line((self.x, self.y), (self.x, self.y+self.height), color)
        self.draw_line((self.x, self.y+self.height), (self.x+self.width, self.y+self.height), color)
        self.draw_line((self.x+self.width, self.y+self.height), (self.x+self.width, self.y), color)
        self.draw_line((self.x+self.width, self.y), (self.x, self.y), color)

class main(pyglet.window.Window):
    def __init__ (self):
        super(main, self).__init__(800, 600, fullscreen = False, vsync=False)
        self.x, self.y = 0, 0

        self.bg = pyglet.sprite.Sprite(pyglet.image.load('background.jpg'))
        self.sprites = {}
        self.sprites['ball'] = Bar()
        self.alive = 1

    def on_draw(self):
        self.render()

    def on_close(self):
        self.alive = 0

    def on_key_press(self, symbol, modifiers):
        if symbol == key.ESCAPE: # [ESC] is pressed
            self.alive = 0
        elif symbol == key.RIGHT: # [RightArrow] is pressed
            self.sprites['ball'].x += 10
        elif symbol == key.LEFT:
            self.sprites['ball'].x -= 10
        elif symbol == key.UP:
            self.sprites['ball'].y += 10
        elif symbol == key.DOWN:
            self.sprites['ball'].y -= 10

    def render(self):
        self.clear()
        self.bg.draw()

        ## == Do some calculations and moving around here maybe.
        ##    Unless you'll be using on_key_press() as I did here.

        for sprite_name, sprite_obj in self.sprites.items():
            sprite_obj.draw()

        self.flip()

    def run(self):
        while self.alive == 1:
            self.render()

            # -----------> This is key <----------
            # This is what replaces pyglet.app.run()
            # but is required for the GUI to not freeze
            #
            event = self.dispatch_events()

x = main()
x.run()

I've added so that you can press any arrow (right, left, up, down) in order to move around the simple bar that I created here.

It supports color, doesn't have a picture but that's kind of easy to add in there, just replace self.texture = gen_solid_image(...) and you're done.

I've also made a little comment on where you can do some calculations and moving around.

do not try to use threads, it will only make your life harder.

Upvotes: 1

Related Questions