Search code examples
spritepygamecollisionrect

Pygame sprite clamping isse


So Ive been having issues with getting a sprite to stay withing the bounds of the screen. I got it to work with a simple rect(0,0,16,16), but i cant seem to get it to work with a sprite being blit onto the screen. What do i need to change in order to keep my sprite clamped within the screen res? I only just started today using classes to orgonize code so any input is appreciated and helpful.

import pygame
from pygame.locals import *
from pygame import Color


class Game():
    """ Lets try to get this going by simple steps
    One by one. First step, lets figure how to make a class
    that can do the display stuff. Lord have mercy on my soul"""

    def __init__(self, wi=256, hi=224, multii=3):
        """Initialization"""
        pygame.init()
        self.runGame    = True
        self.width      = wi*multii
        self.height     = hi*multii
        self.spritesize = 16*multii
        self.clock      = pygame.time.Clock()
        self.fps        = self.clock.get_fps()
        self.screen     = pygame.display.set_mode((self.width, self.height))
        self.kl         = []
        self.walk       = [0, 0]
        self.speed      = multii*1.5
        self.x,self.y   = self.width/2, self.height/2
        self.playerSpr  = pygame.image.load('images/'+'link1.png').convert_alpha()
        self.playerRec  = Rect(self.playerSpr.get_rect())


    def mainLoop(self):
        """Loop through the main game routines
        1. Drawing  2. Input handling  3. Updating
        Then loop through it until user quits"""
        while self.runGame:
            self.clock.tick(60)
            self.events()
            self.draw()


    def events(self):
        """Time to handle some events"""
        for e in pygame.event.get():
            if (e.type == pygame.QUIT) or (e.type == KEYDOWN and e.key == K_ESCAPE):
                self.runGame = False
                break                            
            if e.type==KEYDOWN:     
                if e.key==pygame.K_a: self.kl.append(1)
                if e.key==pygame.K_d: self.kl.append(2)
                if e.key==pygame.K_w: self.kl.append(3)
                if e.key==pygame.K_s: self.kl.append(4)             
            if e.type==pygame.KEYUP:
                if e.key==pygame.K_a: self.kl.remove(1)            
                if e.key==pygame.K_d: self.kl.remove(2)
                if e.key==pygame.K_w: self.kl.remove(3)             
                if e.key==pygame.K_s: self.kl.remove(4)

            if   self.kl[-1:]==[1]: self.walk=[-self.speed, 0]
            elif self.kl[-1:]==[2]: self.walk=[ self.speed, 0]
            elif self.kl[-1:]==[3]: self.walk=[0,-self.speed]
            elif self.kl[-1:]==[4]: self.walk=[0, self.speed]
            else:                   self.walk=[0, 0]

        self.x+=self.walk[0]
        self.y+=self.walk[1]


    def draw(self):
        """Draw and update the main screen"""
        self.fps = self.clock.get_fps()
        self.screen.fill(Color('purple'))
        #print self.screen.get_rect()
        #print player_rect
        self.playerSpr.clamp_ip(self.screen.get_rect())
        #pygame.draw.rect(self.screen, (255, 255, 255), self.playerrect)
        self.screen.blit(self.playerSpr, (self.x,self.y), self.playerRec)
        pygame.display.set_caption('Grid2. FPS: '+str(self.fps))
        pygame.display.update()



game = Game()
game.mainLoop()

Solution

  • Why not use playerRec to keep track of the position of your player instead of the additional x and y attributes?

    I suggest also using the move method (or move_ip):

    def events(self):
        for e in pygame.event.get():
           ...
    
        self.playerRec.move_ip(*self.walk) # instead of self.x+=self.walk[0] / self.y+=self.walk[1]
    
    def draw(self):
        ...
    
        # probably do this right after 'move_ip'
        self.playerRec.clamp_ip(self.screen.get_rect())
    
        # note that 'blit' accepts a 'Rect' as second parameter
        self.screen.blit(self.playerSpr, self.playerRec) 
    

    as a side note: You should consider using a Sprite, since it basically combines an Image and a Rect.