I used someone else's code as an example to start my game and move my character around. I understood the majority of it but there's a couple of parts I don't get.

I want my character to move Up when the up arrow is pressed, but smoothly! My code right now will move him and switch the images to make it look like he's walking, but it blinks between every frame because I reload the background to clear the old character off of the screen. I can't figure out any other way to do it though.

I know my code design right now is horrible and confusing, I'm sorry. I would like someone else's opinion on how this whole project should be structured, if you would be so kind.

The zip file below is my entire project as of now. Not much. :P

Recommended Answers

All 21 Replies

Sweet sprites! It looks fine on my computer. I'm guessing it would be to do with the time it takes to redraw the scene? Have a look into dirty-rectangles and dirty-sprites. These only update the parts of the screen or the sprites that need updating, without redrawing the whole scene.

Dirty Rectangles:
http://www.pygame.org/docs/ref/display.html#pygame.display.flip (PyGame Doc)
http://muagames.com/tutorials/pygame-3-pong/pygame-3-pong-step-1/ (An example I found, do page search for "dirty" or "dirty rectangles")
http://www.pygame.org/docs/tut/newbieguide.html (Another example)

Dirty Sprites:
http://www.pygame.org/docs/ref/sprite.html#pygame.sprite.DirtySprite (PyGame Doc)
Couldn't find so much for this one. Have a look round yourself if your interested.

I'd say dirty rectangles would be the best way to go for now.

I guess it's just my old computer then, if it looked fine on yours. I'm looking through those now. Thank you for the links.

I don't believe I'm understanding it correctly...I've got it to where a green square is drawn where the sprite is. Now all I need to do is use pygame.display.update() on that rectangle right? It doesn't work...He leaves a trail of his previous selves. :|

Can you tell what is wrong? I'm still looking into it.

if self.Dir == "North" and keys.Is("up"):
                self.Rect   = self.WalkNorth[self.CurrentFrame].get_rect()
                self.screen.blit(self.WalkNorth[self.CurrentFrame],(self.X,self.Y))
                self.Y     -= self.Speed

                #print self.Rect
                dirty = pygame.rect.Rect([self.X, self.Y, self.Rect[2], self.Rect[3]])
                #print dirty
                pygame.draw.rect(self.screen, (0, 255, 0), dirty) #Comment out

                pygame.display.update(dirty) #Update only that area?? Doesn't work.
                pygame.display.flip()
                
            else:
                self.Rect = self.StandNorth.get_rect()
                self.screen.blit(self.StandNorth, (self.X, self.Y))

                dirty = pygame.rect.Rect([self.X, self.Y, self.Rect[2], self.Rect[3]]) #Comment out
                pygame.display.update(dirty)

                pygame.draw.rect(self.screen, (0, 255, 0), dirty)
            pygame.display.flip() 
            pygame.time.delay(50)

No, it's not just the sprite. The dirty rectangle should be around the sprite, AND around the area the sprite was last in. If you only update the character, the rest of the screen won't be updated, hence you will get this trail.

So close, I know it. I've got the rectangles to draw over the correct areas to be updated to test it. It works, but when I take out drawing the rectangles he still leaves a trail behind him.

if self.Dir == "North" and keys.Is("up"):
                self.Rect   = self.WalkNorth[self.CurrentFrame].get_rect()
                self.PrevX  = self.X
                self.PrevY  = self.Y
                
                self.screen.blit(self.WalkNorth[self.CurrentFrame],(self.X,self.Y))
                self.Y     -= self.Speed

                dirty = []

                dirty.append(pygame.rect.Rect([self.X, self.Y, self.Rect[2], self.Rect[3]])) #Current Location
                dirty.append(pygame.rect.Rect([self.PrevX, self.PrevY, self.Rect[2], self.Rect[3]])) #Previous Location

                pygame.display.update(dirty)
                
            else:
                self.Rect = self.StandNorth.get_rect()
                self.screen.blit(self.StandNorth, (self.X, self.Y))

                dirty = pygame.rect.Rect([self.X, self.Y, self.Rect[2], self.Rect[3]])
                pygame.display.update(dirty)
                
            pygame.display.flip() 
            pygame.time.delay(50)

What do you mean when you take out drawing the rectangles? Of course if you don't draw them a trail will be left.

I drew the rectangles on screen to see if they covered the areas they're supposed to. My background is a 1024x768 PNG image, not a rectangle drawn on the screen.

I've made my code much more readable...

class Player():
        def __init__(self):
            self.screen       = gfx.screen

            # Values with NONE are set later
            self.X            = 355        # Current X Coords
            self.Y            = 265        # Current Y Coords
            self.PrevX        = None       # Previous X Coords
            self.PrevY        = None       # Previous Y Coords
            self.Speed        = 13         # How many pixels to move
            self.CurrentFrame = 0          # Which image is being displayed
            self.Direction    = "North"    # Which direction they're facing
            self.Standing     = True       # Are they still or moving?
            self.Rect         = None       # Current rectangle
            self.PrevRect     = None       # Previous rectangle
            self.DirtyRects   = []         # Rectangles to be updated

            # Load sprites
            self.StandNorth = pygame.image.load("./Characters/Player/Standing/N.png").convert_alpha()

            self.WalkNorth  = [None] * 5
            for i in range (1, 5):
                self.WalkNorth[i] = pygame.image.load("./Characters/Player/Walking/N_" + str(i) + ".png").convert_alpha()

        def Move(self):
            # Set variables according to key pressed

            if keys.Is("up"):
                self.Direction      = "North"
                self.Standing       = False
                self.CurrentFrame  += 1

            elif keys.Is("down"):
                self.Direction      = "South"
                self.Standing       = False
                self.CurrentFrame  +=1

            elif keys.Is("left"):
                self.Direction      = "West"
                self.Standing       = False
                self.CurrentFrame  +=1

            elif keys.Is("right"):
                self.Direction      = "East"
                self.Standing       = False
                self.CurrentFrame  +=1

            else: self.Standing = True

            # Set frames back to beginning if too far
            if self.CurrentFrame > 4: self.CurrentFrame = 1

            # Moving logic
            if self.Direction == "North" and keys.Is("up"):
                # Blit the current frame to the screen
                self.screen.blit(self.WalkNorth[self.CurrentFrame],(self.X,self.Y))

                # Set Prev values
                self.PrevX = self.X
                self.PrevY = self.Y

                self.Y -= self.Speed # Move it

                # Make dirty rectangles
                self.PrevRect = [self.PrevX, self.PrevY, 48, 48]
                self.Rect     = [self.X, self.Y, 48, 48]

                # Add to list
                self.DirtyRects.append(self.PrevRect)
                self.DirtyRects.append(self.Rect)


            elif self.Standing:
                self.screen.blit(self.StandNorth, (self.X, self.Y))


            # Updating logic
            if self.DirtyRects:
                pygame.display.update(self.DirtyRects)
                self.DirtyRects = [] # Reset so rectangles don't pile up

            pygame.display.flip()
            pygame.time.delay(50)

Only thing that makes sense and will do what I want is blitting the background again so the old sprite is removed, but that was too slow and will probably cause problems later. This is sort of what the Newbie Guide to pygame said to do, but it said take a piece of the background and blit it over the sprite's previous location. Will this finally do it? How do I even do that with a .PNG file?

OK, so you need your background image to be replaced in the dirty areas that have been updated? If you made a new pygame surface and blitted the background image onto it, you could use that. BUT, you must make sure that when you blit it, you blit the background image with negative x and y coordinates, so that it lines up properly with where you want it to go.

eg.

- Updated rectangle (5, 5, 10, 10)
- Make new 5*5 surface (surf)
- Blit background to surf (-5, -5)
- Blit surf to screen, BEFORE blitting the character.

Problem solved yet?

Hmmm...nope. Still trying it though

What's your current problem?
You could upload your game files in a zip and I could have a look and try to get it working.

commented: Very nice to offer +1

Thank you, but I think I'll spend one more day with it before I give up and upload it.

OK. Just keep us updated :)

And I give. :sad: Line 95 in Handlers.py is where I draw the background, then it moves whichever direction he's supposed to go(Up down left and right work now) and blits the current frame to the screen, then updates.

Maybe it's something simple I haven't set right, because it's slow again but not flickering or clearing the old sprites.

Firstly, I am getting this error when I run into the top of the screen. It crashes the program.

Traceback (most recent call last):
  File "C:\Users\Mark\Downloads\game\Game.py", line 34, in <module>
    GameMain()
  File "C:\Users\Mark\Downloads\game\Game.py", line 30, in GameMain
    player.Move()
  File "C:\Users\Mark\Downloads\game\Handlers.py", line 95, in Move
    gfx.BlitBackground(self.X, self.Y) #Blit background again
  File "C:\Users\Mark\Downloads\game\Handlers.py", line 13, in BlitBackground
    self.surf = pygame.surface.Surface((X, Y))
error: Invalid resolution for Surface

Still looking through...

It doesn't have any code to handle when the player goes off of the screen

OK. I still can't figure out how to get your code working :/ I'll keep looking around though.

Hey don't worry about it. I've finally made it sort-of work! :cool:

Okay. It's pretty much solved. There are no longer any trails left when he moves around. There's still a few kinks here and there with moving around but I should be able to work those out. Thank you for your help.

:) Please upvote my helpful posts. Thanks.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.