Skip to main content
GameDev.net gamedev.net
🔒 Locked 🎮 Unity

Python + Pygame Problem

Started by ErikNavarro Jan 31, 2011 at 5:27 AM 5 replies 2.8k views
Original Post
ErikNavarro
ErikNavarro


import os, sys
import pygame
from pygame.locals import *

SCREENRECT = Rect(0, 0, 590, 400)
def load_image(name):
fullname = name
try:
image = pygame.image.load(fullname)
except pygame.error:
print ('Cannot load image:', fullname)
raise SystemExit(str(geterror()))
image = image.convert()
return image

class AnimatedSprite(pygame.sprite.Sprite):
def __init__(self, images, fps = 10):
pygame.sprite.Sprite.__init__(self)
self._images = images
self.image = images[0]
self.rect = self.image.get_rect()
self.rect.midtop = (300,200)


# Track the time we started, and the time between updates.
# Then we can figure out when we have to switch the image.
self._start = pygame.time.get_ticks()
self._delay = 1000 / fps
self._last_update = 0
self._frame = 0
self.min = 0
self.max = 0
self.speed = 3

# Call update to set our first image.
self.animate(pygame.time.get_ticks())

def move(self, direction):
if direction == 1:
self.min = 0
self.max = 10
if direction == -1:
self.min = 11
self.max = 21
self.animate(pygame.time.get_ticks())
self.rect.move_ip(direction*self.speed, 0)
self.rect = self.rect.clamp(SCREENRECT)



def animate(self, t):
# Note that this doesn't work if it's been more that self._delay
# time between calls to update(); we only update the image once
# then, but it really should be updated twice.

if t - self._last_update > self._delay:
self._frame += 1
if (self._frame + self.min ) >= self.max: self._frame = 0
self.image = self._images[self._frame + self.min]
self._last_update = t


def main():
"""this function is called when the program starts.
it initializes everything it needs, then runs in
a loop until the function returns."""


#Initialize Everything
pygame.init()
screen = pygame.display.set_mode((600, 400))
pygame.display.set_caption('Game')
pygame.mouse.set_visible(0)


image1 = pygame.image.load('r1.png')
image2 = pygame.image.load('r2.png')
image3 = pygame.image.load('r3.png')
image4 = pygame.image.load('r4.png')
image5 = pygame.image.load('r5.png')
image6 = pygame.image.load('r6.png')
image7 = pygame.image.load('r7.png')
image8 = pygame.image.load('r8.png')
image9 = pygame.image.load('r9.png')
image10 = pygame.image.load('r10.png')
image11 = pygame.image.load('r11.png')
image12 = pygame.image.load('l1.png')
image13 = pygame.image.load('l2.png ')
image14 = pygame.image.load('l3.png')
image15 = pygame.image.load('l4.png')
image16 = pygame.image.load('l5.png')
image17 = pygame.image.load('l6.png')
image18 = pygame.image.load('l7.png')
image19 = pygame.image.load('l8.png')
image20 = pygame.image.load('l9.png')
image21 = pygame.image.load('l10.png')
image22 = pygame.image.load('l11.png')

images = [image1,
image2,
image3,
image4,
image5,
image6,
image7,
image8,
image9,
image10,
image11,
image12,
image13,
image14,
image15,
image16,
image17,
image18,
image19,
image20,
image21,
image22]



#Create The Backgound
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((250, 250, 250))

#Display The Background
screen.blit(background, (0, 0))
pygame.display.flip()

clock = pygame.time.Clock()
mega = AnimatedSprite(images)
allsprites = pygame.sprite.RenderPlain((mega))

#Main Loop
going = True
while going:

clock.tick(60)
for event in pygame.event.get():
if event.type == QUIT or \
(event.type == KEYDOWN and event.key == K_ESCAPE):
return

keystate = pygame.key.get_pressed()
if keystate[K_RIGHT] or keystate[K_LEFT]:
direction = keystate[K_RIGHT] - keystate[K_LEFT]
mega.move(direction)
else :
mega._frame = 0

#mega.animate(pygame.time.get_ticks())
screen.blit(background, (0,0))
allsprites.draw(screen)
pygame.display.flip()
pygame.quit


if __name__ == '__main__':
main()





My problem is this : My sprite's movement and animations are smooth in the left direction ( <----- ), but seem jittery in the right direction (-------> )
Also : The sprite clamps correctly to the left ( stops at the edge of the screen ), but not to the right.

I have a feeling these two problems are related.

Any help would be greatly appreciated, I've been staring at this code for about an hour without any luck.

:/
Captain P
Captain P
The clamping seems to work just fine. You may want to change the clamping rectangle to match the screen resolution though: currently there's a 10 pixel difference along the x-axis (SCREEN_RECT is 590 x 400, resolution is 600 x 400). Movement is a bit jittery indeed, both left and right. You're updating at a fixed time interval, but if you would measure the elapsed time, you'd notice that it's not always the same. Sometimes there's a spike or at least a little variation. One way to fix this would be to use the elapsed time to determine the actual movement for that frame. If one update takes longer than expected, the next update will take that into account by moving the sprite a little further. It's not perfect (read Fix your Timestep! to understand why), but at least it runs smoother.


Here's a few more tips: try using one list of images per animation sequence. You can use len(sequence) to determine the number of frames.
self.sequences = [[R1, R2, R3], [L1, L2, L3]]
image = self.sequences[currentSequence][currentFrame]

Or perhaps give sequences a name:
self.sequences = {'right': [R1, R2, R3], 'left': [L1, L2, L3]}

There's no need to use named variables to store the images in. Try using a list comprehension instead:
filenames = ['r1', 'r2', 'r3']
images = [pygame.image.load(filename + '.png') for filename in filenames]

Did you think about how to handle pausing your game? That's difficult to implement if you're using timestamps (get_tick). Try keeping track of how much time there's left until the next animation frame instead, while passing in a time delta instead of a timestamp. Pausing is then as easy as not updating, or passing a delta of 0.
ErikNavarro
ErikNavarro
When I run this program, clamping and movement is only glitchy in the right direction. ------------------>

Movement and clamping is perfectly fine in the left direction.

Also Note : I changed SCREENRECT to 590 in a desperate attempt to get the image to clamp correctly to the right. It was useless.

Do you see anything in this code that would cause the animation's and clamping to differ between left and right ?

This is driving me insane.
ErikNavarro
ErikNavarro
[color=#1C2837][size=2][color=#000088]class[color=#000000] [color=#660066]AnimatedSprite[color=#666600]([color=#000000]pygame[color=#666600].[color=#000000]sprite[color=#666600].[color=#660066]Sprite[color=#666600]):[color=#000000]
[color=#000088]def[color=#000000] __init__[color=#666600]([color=#000088]self[color=#666600],[color=#000000] images[color=#666600],[color=#000000] fps [color=#666600]=[color=#000000] [color=#006666]10[color=#666600]):[color=#000000]
pygame[color=#666600].[color=#000000]sprite[color=#666600].[color=#660066]Sprite[color=#666600].[color=#000000]__init__[color=#666600]([color=#000088]self[color=#666600])[color=#000000]
[color=#000088]self[color=#666600].[color=#000000]_images [color=#666600]=[color=#000000] images
[color=#000088]self[color=#666600].[color=#000000]image [color=#666600]=[color=#000000] images[color=#666600][[color=#006666]0[color=#666600]][color=#000000]
[color=#000088]self[color=#666600].[color=#000000]rect [color=#666600]=[color=#000000] [color=#000088]self[color=#666600].[color=#000000]image[color=#666600].[color=#000000]get_rect[color=#666600]() # <- This line of code is throwing off my clamping because my images differ [color=#000000]
[color=#000088]self[color=#666600].[color=#000000]rect[color=#666600].[color=#000000]midtop [color=#666600]=[color=#000000] [color=#666600]([color=#006666]300[color=#666600],[color=#006666]200[color=#666600]) #in dimension. Would this also cause my animation's to seem glitchy ? Why is this only # a problem in the right direction, and not in the left ?[color=#666600] [color=#666600]
Captain P
Captain P
Your code uses the first image's rect as the sprite's dimensions. If other images are smaller or larger, then it's quite obvious why clamping doesn't seem to work. It does work, it's just not using the dimension of the current image. Try replacing:
self.rect = self.rect.clamp(SCREENRECT)
with:
self.rect = self.image.get_rect().clamp(SCREENRECT)

However, keep in mind that the sprite's position may now change even though you're standing next to a wall, due to the changing dimension. Personally, I wouldn't use image dimensions directly for things like this - such bounding boxes are often too large to be useful anyway; sprites often have some empty space. See Tuning Canabalt to see why it's useful to tweak bounding-boxes apart from the visualization.


Movement is a little jittery in both directions for me, but I suppose having different images could make it look more jittery in one direction than the other. I simply created some equally sized colored rectangles, numbered from 1 to 11. If a sprite's position is it's top-left corner, then having images of different width will make the right side move erratically (unless you've taken this into account when creating your art - it depends a lot on the images you're using). The movement itself isn't any more or less jittery however. Try using equally sized images and see if it's still more jittery.
ErikNavarro
ErikNavarro
I replaced the line of code that you told me to change.

When I try to move, the Sprite is transported to the top right corner of the screen, and from there just runs(animates) in place.

Any ideas ?
Captain P
Captain P
Heh, of course. I forgot to take the sprite's position into account. You'll only want to update the width and height of the rect, not it's position, before clamping it.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.