Why, oh why won't my sprite rotate?

Started by
8 comments, last by Zahlman 16 years, 8 months ago
Hi again! After successfully viewing my sprite on the screen I go to the next step; to be able to rotate the sprite based on keyboard input. I have followed deviangels tutorial on rotating sprites, and I've checked my code against his numerous times. I don't understand how he makes the update function work since it is never called in his script (as far as I can see at least). Could you please help me out on this one? Thanks in advance!
import pygame
pygame.init()

class Pacman(pygame.sprite.Sprite):
    """ The class that creates Pacman """
    
    def __init__(self, posX, posY):
        """ Creates the creature """
        pygame.sprite.Sprite.__init__(self)
        self.imageMaster = pygame.image.load("data/pacman.gif").convert()
        self.image = self.imageMaster
        self.rect = self.image.get_rect()
        self.rect.center = (posX, posY)
        self.FacingDir = 0
        
    def Update(self):
        oldCenter = self.rect.center
        self.image = pygame.transform.rotate(self.imageMaster, self.FacingDir)
        self.rect = self.image.get_rect()
        self.rect.center = oldCenter
        
    def FaceUp(self):
        FacingDeg = 90
        
    def FaceDown(self):
        FacingDeg = 270
        
    def FaceLeft(self):
        FacingDeg = 180
        
    def FaceRight(self):
        FacingDeg = 0

def main():
    # set up the display
    screen = pygame.display.set_mode((390, 390))
    pygame.display.set_caption("Pacman clone")

    # set up the background
    background = pygame.Surface(screen.get_size())
    background.fill((0, 0, 0))

    hero = Pacman(100, 150)
    allSprites = pygame.sprite.Group(hero)

    # set up tha main loop
    keepGoing = True
    clock = pygame.time.Clock()
    pygame.mouse.set_visible(False)

    while keepGoing:
        clock.tick(30)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                keepGoing = False
                
            elif event.type == pygame.KEYDOWN:
                
                if event.key == pygame.K_LEFT:
                    hero.FaceLeft()
                
                elif event.key == pygame.K_RIGHT:
                    hero.FaceRight()
                    
                elif event.key == pygame.K_UP:
                    hero.FaceUp()
                    
                elif event.key == pygame.K_DOWN:
                    hero.FaceDown()

        allSprites.clear(screen, background)
        allSprites.update()
        allSprites.draw(screen)

        pygame.display.flip()

    pygame.mouse.set_visible(True)

if __name__ == "__main__":
    main()

Advertisement
I just noticed I hade used a variable called FacingDeg instead of FacingDir. I changed this without any effect at the moment.
In Python you must explicitly have "self." before any variables that are members of the class. Namely, "FacingDir" in the Face*() functions are referencing _local variables_, not FacingDir variable of Pacman. Hence, you should replace those with "self.FacingDir".
Okay, finally I understand the use of self a little better :) Thank you. But this still doesn't make my Update function work. I tried to change the name of the Update function to update (with a lowercase "U") and it made my "game" work just like it should. Why? Do I override the update function of pygame.sprite.Sprite this way?
Yes, the way pygame sprites work, the group update method just calls the update method of all the sprites (the default implementation does nothing). Python is case sensitive.
Quote:Original post by Zyndrof
Okay, finally I understand the use of self a little better :) Thank you. But this still doesn't make my Update function work. I tried to change the name of the Update function to update (with a lowercase "U") and it made my "game" work just like it should. Why? Do I override the update function of pygame.sprite.Sprite this way?

Yes, that's exactly what we are doing overriding the inherited sprite class update method since by default it does nothing.

Sprite.update

method to control sprite behavior
Sprite.update(*args):

The default implementation of this method does nothing; it's just a convenient "hook" that you can override. This method is called by Group.update - call the update method on contained Sprites with whatever arguments you give it.

There is no need to use this method if not using the convenience method by the same name in the Group class.

And if you are used to a case-insenstive language like VB Python does take some extra work to get used to.
A good Python ide like EasyEclipse I just started using for my Python programming would help out with such things.

[size="2"]Don't talk about writing games, don't write design docs, don't spend your time on web boards. Sit in your house write 20 games when you complete them you will either want to do it the rest of your life or not * Andre Lamothe
Well, I'm working mainly in PHP at the moment, so case-sensitivity isn't any problem. It's just that I have my own way of writing code, and function names allways start with an uppercase letter, whilst variables never do.
If function names always start with an uppercase letter, and variables never start with an uppercase letter, how would you pass a function as a parameter to another function? Temporarily allow a function to start with a lowercase letter? Technically there isn't even a difference between variables that contain functions and variables that contain other types, and Python actually treats member functions of an object as member variables of that object's class. It is possible (although not recommended in most circumstances) to replace a function of a class with an entirely different function at any time. Maybe it's best not to think about that too much...
class MyClass(object):  def talk(self):    print "Hello"o = MyClass()o.talk() # prints "Hello"def f(self): print("Goodbye")g = o.talkMyClass.talk = fo.talk() # prints "Goodbye"g() #prints "Hello"

A bit confusing, but entirely legal in python. Don't do this sort of thing unless you really know what you're doing (and even then, think it over a few more times).

And then all functions and classes in python are objects and therefore both are stored in global variables anyway, and the standard python libraries sometimes use different conventions, and sometimes you don't even care if something is a function object or a function or a class...so I guess using what works for you is ok.

[Edited by - Vorpy on July 20, 2007 11:21:56 AM]
Quote:Original post by Vorpy
If function names always start with an uppercase letter, and variables never start with an uppercase letter, how would you pass a function as a parameter to another function?

Parameters are not variables:
object.Function(SomeOtherFunction)

Parameter values may be held in variables for function implementation:
def Function(func):    ...    func(self.someVar)    ...

Really, there is no conflict. func isn't a function, as far as Function is concerned; it is an object that implements __call__ - an instance, a variable.

The real problem is that Zyndrof's convention of functions-start-with-uppercase is incompatible with the library he is using (PyGame), and indeed with most Python libraries. His options are to adjust his code to match the library, wrap the library for consistency with his own code, or come to terms with the inconsistency and let usage describe type rather than visual signifiers.

Quote:Original post by Vorpy
And then all functions and classes in python are objects and therefore both are stored in global variables anyway...

False. Functions and classes are scoped:
>>> class SomeClass:...     class OtherPrivateClass:...         def __init__(self, var):...             self.value = var...             ...     def __init__(self, x):...         self.value = OtherPrivateClass(x)...             >>> b = SomeClass(12)        ...NameError: global name 'OtherPrivateClass' is not defined

self.OtherPrivateClass works. SomeClass.OtherPrivateClass works. Also, dir() reveals that OtherPrivateClass is not a symbol in the default/global namespace, but it is in SomeClass.
Quote:Original post by Zyndrof
Well, I'm working mainly in PHP at the moment, so case-sensitivity isn't any problem. It's just that I have my own way of writing code, and function names allways start with an uppercase letter, whilst variables never do.


I guess you could alias it:

Pacman.update = Pacman.Update


Ah, the beauty of "everything is an object" :)

This topic is closed to new replies.

Advertisement