0

so my issue is with my player class, I'm still trying to understand classes. So, basically, I'm using this player movement code from one of Pyganim's examples but I can't seem to implement it into this player class of mine, probably because I don't really understand classes.

For starters. My player never gets displayed now, every thing worked before I tried to add classes. I've probably just over complicated things trying to use this movement. My code is:

 import pygame, sys, random, pyganim
 from pygame.locals import *

 class Scene(object):
     screen = pygame.display.set_mode((800, 600))

 class Intro(Scene):
     def __init__(self):
         self.c = (32, 32, 100)

     def draw(self):
         Scene.screen.fill(self.c)

     def update(self):
         # since scenes are classes, they have a state that we can modify
         r,g,b = self.c
         r += 1
         g += 1
         b += 2
         if r > 255: r = 0
         if g > 255: g = 0
         if b > 255: b = 0
         self.c = r, g, b

     def handle(self, event):
         # move to Menu-scene when space is pressed
         if event.type == pygame.KEYDOWN:
             if event.key == pygame.K_m:
                 # returning a scene from handle or update changes the current scene
                 return Menu()

 class Menu(Scene):
     def draw(self):
         # draw menu
         Scene.screen.fill((200, 200, 100))

     def update(self):
         pass
         # do something

     def handle(self, event):
         # handle menu input
         if event.type == pygame.KEYDOWN:
             if event.key == pygame.K_a:
                 return Game()
             if event.key == pygame.K_b:
                 return Intro()

 class Game(Scene):
     def draw(self):
         Scene.screen.fill((0,0,0))
         bg = pygame.image.load('C:\\Users\\PAx\\Desktop\\stuff\\fort.png')
         Scene.screen.blit(pygame.transform.scale(bg,(400,300)),(0,0))


     def update(self):
         pass

     def handle(self, event):
         if event.type == pygame.KEYDOWN:
             if event.key == pygame.K_m:
                 return meun()

 class Player(pygame.sprite.Sprite):


     def __init__(self):
         self.UP = 'up'
         self.DOWN = 'down'
         self.LEFT = 'left'
         self.RIGHT = 'right'
         self.direction = DOWN # player starts off facing down (front)
         # load the "standing" sprites (these are single images, not animations)
         self.playerWidth, playerHeight = front_standing.get_size()
         # creating the PygAnimation objects for walking/running in all directions
         self.animTypes = 'back_run back_walk front_run front_walk left_run left_walk'.split()
         self.animObjs = {}
         for animType in animTypes:
             self.imagesAndDurations = [('C:\\Users\PAx\\Desktop\\stuff\\gameimages\\crono_%s.%s.gif' % (animType, str(num).rjust(3, '0')), 1) for num in range(6)]
             self.animObjs[animType] = pyganim.PygAnimation(imagesAndDurations)
         # create the right-facing sprites by copying and flipping the left-facing sprites
         self.animObjs['right_walk'] = animObjs['left_walk'].getCopy()
         self.animObjs['right_walk'].flip(True, False)
         self.animObjs['right_walk'].makeTransformsPermanent()
         self.animObjs['right_run'] = animObjs['left_run'].getCopy()
         self.animObjs['right_run'].flip(True, False)
         self.animObjs['right_run'].makeTransformsPermanent()
         # have the animation objects managed by a conductor.
         # With the conductor, we can call play() and stop() on all the animtion
         # objects at the same time, so that way they'll always be in sync with each
         # other.
         self.moveConductor = pyganim.PygConductor(animObjs)
         self.x = 100
         self.y = 100
         self.WALKRATE = 10
         self.RUNRATE = 18
         self.pygame.sprite.Sprite.__init__(self) #init the Pygame sprite
         #load all images
         #load the player image
         self.front_standing = pygame.image.load('C:\\Users\PAx\\Desktop\\stuff\\gameimages\\crono_front.gif')
         self.back_standing = pygame.image.load('C:\\Users\PAx\\Desktop\\stuff\\gameimages\\crono_back.gif')
         self.left_standing = pygame.image.load('C:\\Users\PAx\\Desktop\\stuff\\gameimages\\crono_left.gif')
         self.right_standing = pygame.transform.flip(left_standing, True, False)
         self.running = moveUp = moveDown = moveLeft = moveRight = False

     def update(self):
         for event in pygame.event.get():
             if event.key == KEYDOWN:
                 if event.key in (K_LSHIFT, K_RSHIFT):
                         # player has started running
                         running = True
                 if event.key == K_UP:
                     moveUp = True
                     moveDown = False
                     if not moveLeft and not moveRight:
                         # only change the direction to up if the player wasn't moving left/right
                         direction = UP
                 elif event.key == K_DOWN:
                     moveDown = True
                     moveUp = False
                     if not moveLeft and not moveRight:
                         direction = DOWN
                 elif event.key == K_LEFT:
                     moveLeft = True
                     moveRight = False
                     if not moveUp and not moveDown:
                         direction = LEFT
                 elif event.key == K_RIGHT:
                     moveRight = True
                     moveLeft = False
                     if not moveUp and not moveDown:
                         direction = RIGHT

             elif event.type == KEYUP:
                 if event.key in (K_LSHIFT, K_RSHIFT):
                     # player has stopped running
                     running = False
                 if event.key == K_UP:
                     moveUp = False
                     # if the player was moving in a sideways direction before, change the direction the player is facing.
                     if moveLeft:
                         direction = LEFT
                     if moveRight:
                         direction = RIGHT
                 elif event.key == K_DOWN:
                     moveDown = False
                     if moveLeft:
                         direction = LEFT
                     if moveRight:
                         direction = RIGHT
                 elif event.key == K_LEFT:
                     moveLeft = False
                     if moveUp:
                         direction = UP
                     if moveDown:
                         direction = DOWN
                 elif event.key == K_RIGHT:
                     moveRight = False
                     if moveUp:
                         direction = UP
                     if moveDown:
                         direction = DOWN
         if moveUp or moveDown or moveLeft or moveRight:
                 # draw the correct walking/running sprite from the animation object
                 moveConductor.play() # calling play() while the animation objects are already playing is okay; in that case play() is a no-op
                 if running:
                     if direction == UP:
                         animObjs['back_run'].blit(screen, (x, y))
                     elif direction == DOWN:
                         animObjs['front_run'].blit(screen, (x, y))
                     elif direction == LEFT:
                         animObjs['left_run'].blit(screen, (x, y))
                     elif direction == RIGHT:
                         animObjs['right_run'].blit(screen, (x, y))
                 else:
                     # walking
                     if direction == UP:
                         animObjs['back_walk'].blit(screen, (x, y))
                     elif direction == DOWN:
                         animObjs['front_walk'].blit(screen, (x, y))
                     elif direction == LEFT:
                         animObjs['left_walk'].blit(screen, (x, y))
                     elif direction == RIGHT:
                         animObjs['right_walk'].blit(screen, (x, y))


                 # actually move the position of the player
                 if running:
                     rate = RUNRATE
                 else:
                     rate = WALKRATE
                 if moveUp:
                     y -= rate
                 if moveDown:
                     y += rate
                 if moveLeft:
                     x -= rate
                 if moveRight:
                     x += rate

         else:
                 # standing still
                 moveConductor.stop() # calling stop() while the animation objects are already stopped is okay; in that case stop() is a no-op
                 if direction == UP:
                     Scene.screen.blit(back_standing, ((x, y)))
                 elif direction == DOWN:
                     Scene.screen.blit(front_standing, ((x, y)))
                 elif direction == LEFT:
                     screen.blit(left_standing, ((x, y)))
                 elif direction == RIGHT:
                     screen.blit(right_standing, (x, y))

             # make sure the player does move off the screen
                 if x < 0:
                     x = 0
                 if x > WINDOWWIDTH - playerWidth:
                     x = WINDOWWIDTH - playerWidth
                 if y < 0:
                     y = 0
                 if y > WINDOWHEIGHT - playerHeight:
                     y = WINDOWHEIGHT - playerHeight


 pygame.init()
 clock = pygame.time.Clock()
 Scene.screen = pygame.display.set_mode((800, 600))

 scene = Intro()
 while True:
     if pygame.event.get(pygame.QUIT): break
     for e in pygame.event.get(): 
         scene = scene.handle(e) or scene
     scene = scene.update() or scene
     scene.draw()
     Player.update(scene)
     pygame.display.flip()
     clock.tick(20)

This is the new and working code. I changed handle and update and added a lot of self where needed. Wasn't sure how to add in draw() this could probably be cleaned up and written better but at least it works.

 import pygame, sys, random, pyganim
 from pygame.locals import *

 class Scene(object):
     screen = pygame.display.set_mode((800, 600))

 class Intro(Scene):
     def __init__(self):
         self.c = (32, 32, 100)

     def draw(self):
         Scene.screen.fill(self.c)

     def update(self):
         # since scenes are classes, they have a state that we can modify
         r,g,b = self.c
         r += 1
         g += 1
         b += 2
         if r > 255: r = 0
         if g > 255: g = 0
         if b > 255: b = 0
         self.c = r, g, b

     def handle(self, event):
         # move to Menu-scene when space is pressed
         if event.type == pygame.KEYDOWN:
             if event.key == pygame.K_m:
                 # returning a scene from handle or update changes the current scene
                 return Menu()

 class Menu(Scene):
     def draw(self):
         # draw menu
         Scene.screen.fill((200, 200, 100))

     def update(self):
         pass
         # do something

     def handle(self, event):
         # handle menu input
         if event.type == pygame.KEYDOWN:
             if event.key == pygame.K_a:
                 return Game()
             if event.key == pygame.K_b:
                 return Intro()

 class Game(Scene):
     def draw(self):
         Scene.screen.fill((0,0,0))
         bg = pygame.image.load('C:\\Users\\PAx\\Desktop\\stuff\\fort.png')
         Scene.screen.blit(pygame.transform.scale(bg,(400,300)),(0,0))


     def update(self):
         pass

     def handle(self, event):
         if event.type == pygame.KEYDOWN:
             if event.key == pygame.K_m:
                 return Menu()

 class Player(pygame.sprite.Sprite):
     def __init__(self):
         pygame.sprite.Sprite.__init__(self)

         self.UP = 'up'
         self.DOWN = 'down'
         self.LEFT = 'left'
         self.RIGHT = 'right'

         self.front_standing = pygame.image.load('C:\\Users\PAx\\Desktop\\stuff\\gameimages\\crono_front.gif')
         self.back_standing = pygame.image.load('C:\\Users\PAx\\Desktop\\stuff\\gameimages\\crono_back.gif')
         self.left_standing = pygame.image.load('C:\\Users\PAx\\Desktop\\stuff\\gameimages\\crono_left.gif')
         self.right_standing = pygame.transform.flip(self.left_standing, True, False)
         self.running = self.moveUp = self.moveDown = self.moveLeft = self.moveRight = False


         self.direction = self.DOWN # player starts off facing down (front)
         # load the "standing" sprites (these are single images, not animations)
         self.playerWidth, self.playerHeight = self.front_standing.get_size()
         # creating the PygAnimation objects for walking/running in all directions
         self.animTypes = 'back_run back_walk front_run front_walk left_run left_walk'.split()
         self.animObjs = {}
         for self.animType in self.animTypes:
             self.imagesAndDurations = [('C:\\Users\PAx\\Desktop\\stuff\\gameimages\\crono_%s.%s.gif' % (self.animType, str(num).rjust(3, '0')), 1) for num in range(6)]
             self.animObjs[self.animType] = pyganim.PygAnimation(self.imagesAndDurations)
         # create the right-facing sprites by copying and flipping the left-facing sprites
         self.animObjs['right_walk'] = self.animObjs['left_walk'].getCopy()
         self.animObjs['right_walk'].flip(True, False)
         self.animObjs['right_walk'].makeTransformsPermanent()
         self.animObjs['right_run'] = self.animObjs['left_run'].getCopy()
         self.animObjs['right_run'].flip(True, False)
         self.animObjs['right_run'].makeTransformsPermanent()
         # have the animation objects managed by a conductor.
         # With the conductor, we can call play() and stop() on all the animtion
         # objects at the same time, so that way they'll always be in sync with each
         # other.
         self.moveConductor = pyganim.PygConductor(self.animObjs)
         self.x = 100
         self.y = 100
         self.WALKRATE = 10
         self.RUNRATE = 18
         self.WINDOWWIDTH = 640
         self.WINDOWHEIGHT = 480

         #load all images
         #load the player image





     def update(self, scene):
         if self.moveUp or self.moveDown or self.moveLeft or self.moveRight:
                 # draw the correct walking/running sprite from the animation object
                 self.moveConductor.play() # calling play() while the animation objects are already playing is okay; in that case play() is a no-op
                 if self.running:
                     if self.direction == self.UP:
                         self.animObjs['back_run'].blit(Scene.screen, (self.x, self.y))
                     elif self.direction == self.DOWN:
                         self.animObjs['front_run'].blit(Scene.screen, (self.x, self.y))
                     elif self.direction == self.LEFT:
                         self.animObjs['left_run'].blit(Scene.screen, (self.x, self.y))
                     elif self.direction == self.RIGHT:
                         self.animObjs['right_run'].blit(Scene.screen, (self.x, self.y))
                 else:
                     # walking
                     if self.direction == self.UP:
                         self.animObjs['back_walk'].blit(Scene.screen, (self.x, self.y))
                     elif self.direction == self.DOWN:
                         self.animObjs['front_walk'].blit(Scene.screen, (self.x, self.y))
                     elif self.direction == self.LEFT:
                         self.animObjs['left_walk'].blit(Scene.screen, (self.x, self.y))
                     elif self.direction == self.RIGHT:
                         self.animObjs['right_walk'].blit(Scene.screen, (self.x, self.y))

                 # actually move the position of the player
                 if self.running:
                     rate = self.RUNRATE
                 else:
                     rate = self.WALKRATE
                 if self.moveUp:
                     self.y -= rate
                 if self.moveDown:
                     self.y += rate
                 if self.moveLeft:
                     self.x -= rate
                 if self.moveRight:
                     self.x += rate

         else:
                 # standing still
                 self.moveConductor.stop() # calling stop() while the animation objects are already stopped is okay; in that case stop() is a no-op
                 if self.direction == self.UP:
                     Scene.screen.blit(self.back_standing, ((self.x, self.y)))
                 elif self.direction == self.DOWN:
                     Scene.screen.blit(self.front_standing, ((self.x, self.y)))
                 elif self.direction == self.LEFT:
                     Scene.screen.blit(self.left_standing, ((self.x, self.y)))
                 elif self.direction == self.RIGHT:
                     Scene.screen.blit(self.right_standing, (self.x, self.y))

             # make sure the player does move off the screen
                 if self.x < 0:
                     self.x = 0
                 if self.x > self.WINDOWWIDTH - self.playerWidth:
                     self.x = self.WINDOWWIDTH - self.playerWidth
                 if self.y < 0:
                     self.y = 0
                 if self.y > self.WINDOWHEIGHT - self.playerHeight:
                     self.y = self.WINDOWHEIGHT - self.playerHeight


     def handle(self, event):
             if event.type == KEYDOWN:
                 if event.key in (K_LSHIFT, K_RSHIFT):
                         # player has started running
                         running = True
                 if event.key == K_UP:
                     self.moveUp = True
                     self.moveDown = False
                     if not self.moveLeft and not self.moveRight:
                         # only change the direction to up if the player wasn't moving left/right
                         self.direction = self.UP
                 elif event.key == K_DOWN:
                     self.moveDown = True
                     self.moveUp = False
                     if not self.moveLeft and not self.moveRight:
                         self.direction = self.DOWN
                 elif event.key == K_LEFT:
                     self.moveLeft = True
                     self.moveRight = False
                     if not self.moveUp and not self.moveDown:
                         self.direction = self.LEFT
                 elif event.key == K_RIGHT:
                     self.moveRight = True
                     self.moveLeft = False
                     if not self.moveUp and not self.moveDown:
                         self.direction = self.RIGHT

             elif event.type == KEYUP:
                 if event.key in (K_LSHIFT, K_RSHIFT):
                     # player has stopped running
                     self.running = False
                 if event.key == K_UP:
                     self.moveUp = False
                     # if the player was moving in a sideways direction before, change the direction the player is facing.
                     if self.moveLeft:
                         self.direction = self.LEFT
                     if self.moveRight:
                         self.direction = self.RIGHT
                 elif event.key == K_DOWN:
                     self.moveDown = False
                     if self.moveLeft:
                         self.direction = self.LEFT
                     if self.moveRight:
                         self.direction = self.RIGHT
                 elif event.key == K_LEFT:
                     self.moveLeft = False
                     if self.moveUp:
                         self.direction = self.UP
                     if self.moveDown:
                         self.direction = self.DOWN
                 elif event.key == K_RIGHT:
                     self.moveRight = False
                     if self.moveUp:
                         self.direction = self.UP
                     if self.moveDown:
                         self.direction = self.DOWN


 pygame.init()
 clock = pygame.time.Clock()
 Scene.screen = pygame.display.set_mode((800, 600))
 player = Player()
 scene = Intro()
 while True:
     if pygame.event.get(pygame.QUIT): break
     for e in pygame.event.get(): 
         scene = scene.handle(e) or scene
         player.handle(e) or scene
     scene = scene.update() or scene
     scene.draw()
     player.update(scene)
     pygame.display.flip()
     clock.tick(20)
GospelBG
  • 93
  • 1
  • 14
Doppel
  • 7
  • 3
  • put all classes before `pygame.init()` to make code more readable. – furas Jan 02 '17 at 04:58
  • you never create instance of `Player()` so what do you want to move ? – furas Jan 02 '17 at 05:01
  • sorry i guess that's part of my problem was like how to display the Player. i think this is correct? Player.update(scene) but now i get this error telling me "local variable 'moveUp' referenced before assignment. I'm still confused about using variables in classes maybe you see something i don't? – Doppel Jan 02 '17 at 05:48
  • `Player` is class name - first you need instance ie. `player = Player()`. And then use `player.update(scene)` – furas Jan 02 '17 at 05:50
  • BTW: you should split `player.update(scene)` into three functions `player.event_handler(event)`, `player.update()` and `player.draw(scene)` and execute them in different places. – furas Jan 02 '17 at 05:52
  • `moveUp` is local variable which is created in `for event` loop - but sometimes it is not created - ie. when `event.type` is not `KEYDOWN` but later you check `if mouseUp:`. Better create `mouseUp` at the beginning of function update() with default value and later you will not have problem with `referenced before assignment`. BTW: you may have the same problem with other variables. And you use local variables `x`, `y` but you should use instance variables `self.x` and `self.y` – furas Jan 02 '17 at 06:00
  • BTW: you compare `KEYDOWN` with `event.key` but you have to compare with `event.type` – furas Jan 02 '17 at 06:01
  • i changed a few things now its saying, player.update(scene) "type error update() takes 1 position argument but 2 were given". also i was trying to do that at one point but i got overwhelmed by it, i wasn't sure how to split it up if maybe you could show me an example? – Doppel Jan 02 '17 at 06:01
  • in class `Player` you have `update(self)` so it doesn't expect argument `screen` - it has to be `update(self, screen)` – furas Jan 02 '17 at 06:03
  • the whole differnet types of variables is a little confusing. im not allways sure when to put self, the x and y i just forgot to change to self.x and self.y – Doppel Jan 02 '17 at 06:04
  • in class variable without `self` exist only in one function and is destroyed when you leave this function (so you loose this information). Variable with `self` created in one function will be accessible in other functions and you don't loose it when you leave function. variable with `self` and without `self` are two different variables so `self.x` is not `x` and you can use both in one function. If you create variable in `__init__` then mostly it need `self` and you have to use it with `self` in all other functions. – furas Jan 02 '17 at 06:12
  • honestly you have been a lot of help. I'm a little busy now but ill come back to this. thanks – Doppel Jan 02 '17 at 06:23
  • example with some Player and functions `update()`, `handle_event(event)`, `draw(screen)` and it shows where in mainloop uses this functions: https://github.com/furas/python-examples/blob/master/pygame/__template__/1__simple__.py – furas Jan 02 '17 at 06:38

0 Answers0