Scrolling and Obstacle Detection [PYTHON/PYGAME]

Started by
15 comments, last by dustfilledhobo 14 years, 4 months ago
What I'm trying to do is implement scrolling into my top-view game. I would like the player to stay in the middle of the screen until they reach the out boundaries. Once the screen has hit the boundary the play is free to move to the outer boundary, then when they return to the middle, the screen will continue to scroll. PROBLEMS:::::: (1) The scrolling appears to be working until I reach a boundary, once this happens the player cannot go past the center of the screen, and the screen does not scroll anymore. (2) The collisions between the player and the walls are being detected, but unless the wall s part of the outer boundary, the player walks through the wall. (3) The scrolling doesn't seem consistent. Sometimes it works, sometimes my player flies across the screen really fast. THANK YOU in advance for any help or suggestions. The entire game folder (.zip file) can be downloaded here: http://trovna.googlecode.com/files/Game%28fixing%20scrolling%29.zip But I think that the following parts of my code are all that you will need to help me. Game.py:::

######initializing global variables########
movecount = 0
map1 = Map.Map()
charImages = ImagePaths.CharImagePaths(movecount)
last_key_pressed = "DOWN"



#######initialize pygame#######
pygame.init()



#D - Display configuration
resolution = (800,600)
screen = pygame.display.set_mode(resolution)





######main game loop#######
def main():
#E - Entities (things moving about on screen)
    pygame.display.set_caption("THE GAME")

    background = pygame.Surface(screen.get_size())
    background.fill((50,255,50)) # what color the background is in RGB
    screen.blit(background, (0, 0))
    framecount = 0
    last_key_pressed = "DOWN"

    # Assign sprite classes and other classes to variables
    info = HUDs.HUD()
    info.center = (100, 50)
    char = CharacterSprites.Char(movecount, charImages, map1)
    wiz = EnemySprites.Wiz(screen)
    wiz1 = EnemySprites.Wiz(screen)
    wiz2 = EnemySprites.Wiz(screen)
    gold = ItemSprites.Gold()
    gold1 = ItemSprites.Gold()
    gold2 = ItemSprites.Gold()
    cache = ImageCache.ImageCache()
    map1.load('Map/map.txt')

    #A - Action (broken into ALTER steps)

      #A Assign values to key variables
    goodSprites = pygame.sprite.Group(char)
    itemSprites = pygame.sprite.Group(gold, gold1, gold2)
    badSprites = pygame.sprite.Group(wiz, wiz1, wiz2)
    infoSprites = pygame.sprite.Group(info)
    
    clock = pygame.time.Clock() #initializing the clock
    
    keepGoing = True #initialally we want to Keep Going

        # Main caption
    pygame.display.set_caption("THE GAME")


    #L - Set up main loop
    while keepGoing:
        
        #T - Timer to set frame rate
        clock.tick(30) #setting frame rate number = fps
        #UPDATE = pygame.USEREVENT
        #pygame.time.set_timer(UPDATE, int(1000.0/30))
        
        
        #for animation######
        framecount += 1 
        framecount = framecount % 4 #lower the number to speed up animation
        #The aboove code is for animation

        #pygame.mouse.set_visible(True)

        #E - Event handling
        
        #saving the old position, before we change it, just incase we hit a wall.
        char.old_x = char.rect.centerx
        char.old_y = char.rect.centery
        map1.old_vp_x = map1.vpCoordinate_x
        map1.old_vp_y = map1.vpCoordinate_y
        # The above is for wall collisions
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                keepGoing = False
        
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    if char.rect.centerx == char.start_x:
                        map1.advanceVelocity_x += -char.speed
                        map1.vpCoordinate_x += map1.advanceVelocity_x
                    last_key_pressed = "LEFT"
                elif event.key == pygame.K_RIGHT:
                    if char.rect.centerx == char.start_x:
                        map1.advanceVelocity_x += char.speed
                        map1.vpCoordinate_x += map1.advanceVelocity_x
                    last_key_pressed = "RIGHT"
                elif event.key == pygame.K_UP:
                    if char.rect.centery == char.start_y:
                        map1.advanceVelocity_y += -char.speed
                        map1.vpCoordinate_y += map1.advanceVelocity_y
                    last_key_pressed = "UP"
                elif event.key == pygame.K_DOWN:
                    if char.rect.centery == char.start_y:
                        map1.advanceVelocity_y += char.speed
                        map1.vpCoordinate_y += map1.advanceVelocity_y
                    last_key_pressed = "DOWN"
     
                elif event.key == pygame.K_ESCAPE:
                    pygame.event.post(pygame.event.Event(pygame.QUIT, {}))
     
            elif event.type == pygame.KEYUP:
                if event.key == pygame.K_LEFT:
                    map1.advanceVelocity_x += char.speed
                    #char.rect.centerx += char.speed
                elif event.key == pygame.K_RIGHT:
                    map1.advanceVelocity_x += -char.speed
                    #char.rect.centerx -= char.speed
                elif event.key == pygame.K_UP:
                    map1.advanceVelocity_y += char.speed
                    #char.rect.centery += char.speed
                elif event.key == pygame.K_DOWN:
                    map1.advanceVelocity_y += -char.speed
                    #char.rect.centery -= char.speed
     
            #map1.vpCoordinate_x += map1.advanceVelocity_x
            #map1.vpCoordinate_y += map1.advanceVelocity_y
            if map1.vpCoordinate_x < map1.minHorzScrollBounds:
                map1.vpCoordinate_x = map1.minHorzScrollBounds
                print "minHorz"
            if map1.vpCoordinate_x > map1.maxHorzScrollBounds:
                map1.vpCoordinate_x = map1.maxHorzScrollBounds
                print "maxHorz"
            if map1.vpCoordinate_y < map1.minVertScrollBounds:
                map1.vpCoordinate_y = map1.minVertScrollBounds
                print "minVert"
            if map1.vpCoordinate_y > map1.maxVertScrollBounds:
                map1.vpCoordinate_y = map1.maxVertScrollBounds
                print "maxVert"

            if last_key_pressed == "LEFT":
                if map1.vpCoordinate_x == map1.minHorzScrollBounds:
                    char.rect.centerx -= char.speed
                if map1.vpCoordinate_x == map1.maxHorzScrollBounds:
                    if char.rect.centerx > char.start_x:
                        char.rect.centerx -= char.speed
                        
                
            if last_key_pressed == "RIGHT":
                if map1.vpCoordinate_x == map1.maxHorzScrollBounds:
                    char.rect.centerx += char.speed
                if map1.vpCoordinate_x == map1.minHorzScrollBounds:
                    if char.rect.centerx < char.start_x:
                        char.rect.centerx += char.speed    

                    
            if last_key_pressed == "UP":
                if map1.vpCoordinate_y == map1.minVertScrollBounds:
                    char.rect.centery -= char.speed
                if map1.vpCoordinate_y == map1.maxVertScrollBounds:
                    if char.start_y < char.rect.centery:
                        char.rect.centery -= char.speed
                        
                    
            if last_key_pressed == "DOWN":
                if map1.vpCoordinate_y == map1.maxVertScrollBounds:
                    char.rect.centery += char.speed
                if map1.vpCoordinate_y == map1.minVertScrollBounds:
                    if char.start_y > char.rect.centery:
                        char.rect.centery += char.speed
                     

            #######directional controls
            

            #This is for the character animation
            #When we switch directions we switch which pictures are animated
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT or event.key == pygame.K_DOWN or event.key == pygame.K_UP:    
                    if framecount == 0:
                        if last_key_pressed == "UP": 
                            char.movecount += 1
                            char.movecount = char.movecount % len(charImages.character_array_back)
                            char.image = pygame.image.load(charImages.character_array_back[char.movecount])
                        elif last_key_pressed == "DOWN": 
                            char.movecount += 1
                            char.movecount = char.movecount % len(charImages.character_array_front)
                            char.image = pygame.image.load(charImages.character_array_front[char.movecount])
                        elif last_key_pressed == "LEFT": 
                            char.movecount += 1
                            char.movecount = char.movecount % len(charImages.character_array_left)
                            char.image = pygame.image.load(charImages.character_array_left[char.movecount])
                        elif last_key_pressed == "RIGHT": 
                            char.movecount += 1
                            char.movecount = char.movecount % len(charImages.character_array_right)
                            char.image = pygame.image.load(charImages.character_array_right[char.movecount])
 
        ######Check for sprites colliding with other sprites######
        hitItem = pygame.sprite.spritecollide(char, itemSprites, False)
        if hitItem:
            for theItem in hitItem:
                theItem.reset() #resets location
                info.gold += 1 #adds one to gold

        hitBad = pygame.sprite.spritecollide(char, badSprites, False)
        if hitBad:
            for theBad in hitBad:
                char.reset()#resets location
                info.life -= 1# ads one to kills
                if info.life <= 0:
                    keepGoing = False





                    
        
        #R - Refresh display "blit" means printing an image

        ###Clear old sprite groups
        goodSprites.clear(screen, background)
        itemSprites.clear(screen, background)
        badSprites.clear(screen, background)
        infoSprites.clear(screen, background)

        ###Update the sprite group positions, etc.
        goodSprites.update(last_key_pressed)
        itemSprites.update()
        badSprites.update()
        infoSprites.update()

        ###Draw new sprite groups
        map1.startXTile = int(math.floor(float(map1.vpCoordinate_x) / map1.tilewidth))
        map1.startYTile = int(math.floor(float(map1.vpCoordinate_y) / map1.tileheight))

        #print "tile width = " + str(map1.tilewidth)
        #print "tile height = " + str(map1.tileheight)
              
        
        map1.draw(screen)
        goodSprites.draw(screen)
        itemSprites.draw(screen)
        badSprites.draw(screen)
        infoSprites.draw(screen)

        #print "length of map1.tiles:"+str(len(map1.tiles))
        #print "length of map1.tiles[0]:"+str(len(map1.tiles[0]))
        #print "length of map1.images:"+str(len(map1.images))

        #print "map1.startXTile = " + str(map1.startXTile)
        #print "map1.startYTile = " + str(map1.startYTile)

        #print "map1.numXTiles = " + str(map1.numXTiles)
        #print "map1.numYTiles = " + str(map1.numYTiles)
        if (char.rect.centerx != char.old_x) or (char.rect.centery != char.old_y):
            print "Character Position: (" + str(char.rect.centerx) + ", " + str(char.rect.centery) + ")"

        ####Switch the screen to the new information
        pygame.display.flip()
            
# End main game loop
if __name__ == "__main__":
    main()


Map.py:::

import pygame, math, ImageCache

class Map:
    def __init__(self):
	self.tiles = []
	self.images = []
	self.collision = []	
	self.tilewidth = 0
	self.tileheight = 0
	self.shift_wall_x = 0
        self.shift_wall_y = 0
	
    def load(self, map_file):
	cache = ImageCache.ImageCache()
	self.images.append(cache.getImage('Images/Scenery/ocean.png'))
	self.images.append(cache.getImage('Images/Scenery/pathway.png'))
	self.images.append(cache.getImage('Images/Scenery/brick.png'))

		
	self.tilewidth = self.images[0].get_width()
	self.tileheight = self.images[0].get_height()
		
	for line in open(map_file, 'r'):
	    characters = line.strip().split(',')
		
	    if len(characters) > 0:
                self.tiles.append([])
                self.collision.append([])
			
		# Run through all the tile characters
		for character in characters:
		    if character == 'OCN':
			# [-1] means: the last element of
			# I'm pushing 0 here, because 'red' is the 0th element in self.images
			self.tiles[-1].append(0)
			self.collision[-1].append(True)
		    elif character == 'PTH':
			self.tiles[-1].append(1)
			self.collision[-1].append(False)
		    elif character == 'BRK':
			self.tiles[-1].append(2)
			self.collision[-1].append(True)
		    else:
			# Right now this makes each row one tile shorter, because
			# we're not storing any data for this tile.
			print 'Wrong tile: [' + character + ']'

            self.vpRenderOffset = (0,0)
            self.vpStatsOffset_x = (80,540)
            self.vpStatsOffset_y = (80, 555)
             
            self.vpCoordinate_x = 0
            self.vpCoordinate_y = 0
            self.vpDimensions = (800, 600)

            self.minHorzScrollBounds = 0
            self.maxHorzScrollBounds = 400
            self.minVertScrollBounds = 0
            self.maxVertScrollBounds = 400

            self.advanceVelocity_x = 0
            self.advanceVelocity_y = 0
             
            self.numXTiles = int(math.ceil(float(self.vpDimensions[0]) / self.tilewidth)) + 1
            self.numYTiles = int(math.ceil(float(self.vpDimensions[1]) / self.tileheight)) + 1
            self.tiledBG = pygame.Surface((self.numXTiles * self.tilewidth, self.numYTiles * self.tileheight)).convert()
            self.wallsBG = pygame.Surface((self.numXTiles * self.tilewidth, self.numYTiles * self.tileheight)).convert()




            
    def draw(self,screen):
        for x in range(self.startXTile, self.startXTile + self.numXTiles):
            for y in range(self.startYTile, self.startYTile + self.numYTiles):
                #print map1.images[map1.tiles[y][x]]
            
                self.tiledBG.blit(self.images[self.tiles[y][x]], ((x - self.startXTile) * self.tilewidth, (y - self.startYTile) * self.tileheight))
        screen.blit(self.tiledBG, self.vpRenderOffset, (self.vpCoordinate_x - (self.startXTile * self.tilewidth), (self.vpCoordinate_y - (self.startYTile * self.tileheight))) + self.vpDimensions)
      

CharacterSprites.py:::

import pygame, math
from Images import ImagePaths
from Map import Map, ImageCache

class Char(pygame.sprite.Sprite):
    def __init__(self, movecount, charImages, map1):
        pygame.sprite.Sprite.__init__(self)

        self.map1 = map1
        self.movecount = movecount
        self.image = charImages.character_front_image
        self.image = self.image.convert()
        self.rect = self.image.get_rect()

        # Transparent
        self.colorkey = self.image.get_at((0, 0))
        self.image.set_colorkey(self.colorkey)
        # end transparent

        self.rect.centerx = 400
        self.rect.centery = 300
        self.speed = 7

        self.old_x = self.rect.centerx
        self.old_y = self.rect.centery

        self.start_x = self.rect.centerx
        self.start_y = self.rect.centery
         
    def reset(self):

        self.rect.centerx = 400
        self.rect.centery = 300

    def update(self, last_key_pressed):    
     # Put the player in the new spot
        
        self.rect.center = (self.rect.centerx, self.rect.centery)

        self.last_key_pressed = last_key_pressed

        cal_x = 0
        cal_y = 0
        
        if self.last_key_pressed == "LEFT":
            cal_x = -10
            cal_y = 0
        if self.last_key_pressed == "RIGHT":
            cal_x = 5
            cal_y = 0
        if self.last_key_pressed == "UP":
            cal_x = 0
            cal_y = -11
        if self.last_key_pressed == "DOWN":
            cal_x = 0
            cal_y = 10
        else:
            pass



        

        
        #######%$$*^%^&*%^$#%^#&%$*&%
        #Did we hit a wall???????????
        #######$#$%^#^%#$^%#^%$#%$#%$

        if self.map1.old_vp_x != self.map1.vpCoordinate_x or self.map1.old_vp_y != self.map1.vpCoordinate_y:
            print "vpCoordinates = (" + str(self.map1.vpCoordinate_x) + ", " + str(self.map1.vpCoordinate_y) +")"
            if self.last_key_pressed == "UP" or self.last_key_pressed == "DOWN":
                self.map1.shift_wall_y = int(math.ceil((self.map1.vpCoordinate_y)/40))
            if self.last_key_pressed == "RIGHT" or self.last_key_pressed == "LEFT":
                self.map1.shift_wall_x = int(math.ceil((self.map1.vpCoordinate_x)/40))
            print "map1.shift_wall = (" + str(self.map1.shift_wall_x) + ", " + str(self.map1.shift_wall_y) + ")"  
        
        if self.map1.collision[self.map1.shift_wall_y + int(math.ceil((self.rect.centery)/40))][self.map1.shift_wall_x + int(math.ceil((self.rect.centerx)/40))] == True:
            print "shift_wall = (" + str(self.map1.shift_wall_x) + ", " + str(self.map1.shift_wall_x) + ")"
            print "[y][x] = [" + str(int(math.floor((self.rect.centery+cal_y)/40))) + "][" + str(int(math.ceil((self.rect.centerx+cal_x)/40))) + "]" 
            self.rect.center = (self.old_x, self.old_y)
            
        else:
            #Didn't hit a wall
            self.old_x = self.rect.centerx
            self.old_y = self.rect.centery


Thanks again. Dusty
Advertisement
You probably need a locked frame rate for your code to be consistent as far as moving the character.

Unless you change your moving to go by velocity, then you can define a character moves X ammount of pixels per Y amount of milliseconds.

If you set it up that way no matter what frame rate your game is running at you character will still move at a consistent speed.


And here why are you dividing by 40? wouldn't you just want to move the character back 1 space if he hits a wall?
if self.last_key_pressed == "UP" or self.last_key_pressed == "DOWN":                self.map1.shift_wall_y = int(math.ceil((self.map1.vpCoordinate_y)/40))            if self.last_key_pressed == "RIGHT" or self.last_key_pressed == "LEFT":                self.map1.shift_wall_x = int(math.ceil((self.map1.vpCoordinate_x)/40))



Edit: I should mention that I know nothing of python so take this with a grain of salt =p
The reason why I divided by 40 is because I wanted to find tile position, and since my tiles are 40X40 I needed to take the position and divide it by 40 and then round it to an integer. I should have divided the the x by my tile width and the y by my tile length to make my code more universal. Discussing this made me think of something else, that is probably wrong in my code. Thanks.

I changed the following piece of code from my Game.py file

map1.advanceVelocity_y += char.speedmap1.vpCoordinate_y += map1.advanceVelocity_y


to this:

map1.advanceVelocity_y = char.speedmap1.vpCoordinate_y += map1.advanceVelocity_y



I was unknowingly incrementing my scrolling twice for every 1 character move.

The scrolling appears to be working now, but I am still having trouble with the walls. Thanks again.

Dusty


Dusty

[Edited by - dustfilledhobo on December 5, 2009 10:38:14 AM]
I fixed my walls by adding the last two lines of the following code to my CharacterSprites.py file:

if self.map1.collision[self.map1.shift_wall_y + int(math.ceil((self.rect.centery)/40))][self.map1.shift_wall_x + int(math.ceil((self.rect.centerx)/40))] == True:            print "shift_wall = (" + str(self.map1.shift_wall_x) + ", " + str(self.map1.shift_wall_x) + ")"            print "[y][x] = [" + str(int(math.floor((self.rect.centery+cal_y)/40))) + "][" + str(int(math.ceil((self.rect.centerx+cal_x)/40))) + "]"             self.rect.center = (self.old_x, self.old_y)            self.map1.vpCoordinate_x = self.map1.old_vp_x            self.map1.vpCoordinate_y = self.map1.old_vp_y


I was binding my character's position when he encountered a wall (which was already bound to the center of the screen), but I was not binding the scrolling, so he scrolled right over the walls. Thanks.

Dusty
I'm glad you got it working, sorry I was not more help =p
Here I am again. ;) I took a look at your code, and here's some comments. Enjoy. :)

- You're still mixing tabs and spaces. Take a look at the following article, specifically the part about spaces and tabs: PEP 8 - style Guide for Python Code. Granted, it's a style guide, but it's a good read nonetheless. :) Either way, since you're mixing those, and since you seem to be using a different tab size than me (I'm using 4, you're using 8?), it's pretty hard to identify scope - and therefore it's hard to determine how your code actually runs.

- After figuring out the above, I found out that your Map.load() function runs a bunch of code for every line found in the map file - lines 48 - 67. That code only needs to be executed once. Also, those variables are better stored in the map file itself, for more flexibility. Currently every map is limited to having the same size.

- Your input handling and player movement code is kinda messy. There's a little bit of everything all over the place. Have you considered simplifying it to something like this:
class Character:    def __init__(self, ... ):        self.moveNorth = False        self.moveSouth = False        # east, west, and the rest of the initialization    def update(self, delta):        if self.moveNorth:            self.position.y -= self.speed * delta        if self.moveSouth:            self.position.y += self.speed * delta        # and the same for east and west.        # NOTE: no elif! This makes it possible to press the up and down keys        # at the same time - this stops movement - and once one of the keys is        # released, the player will continue to move in the direction of the key        # that is still held down.        # All that's left is setting moveNorth to True when the up key is pressed,        # and setting it to False when that key is released. Same goes for the        # other keys.

One of the things that will be fixed is the choppy movement. The player now keeps moving while a key is held down, instead of only moving a bit when a key is pressed or when some other event happens (because you're only changing the player position inside your event handling code). Event handling should at most set some flags, change some data. Updating the game logic should do the actual work of reacting to those changes.

- Pass the map rendering offset to the draw function for more control. No member variable that needs to be kept in sync. In fact, do this for all draw functions - this allows you to use a single camera variable. Don't mix this with player position (due to map boundaries but also because you shouldn't mix responsibilities). A camera is a separate thing, even though it might follow the player most of the time.

Personally, I would dump the use of sprite groups. Draw order is not defined, you can't pass a drawing offset... I just think they're not very practical.

- Don't divide by '40'. Magic numbers are bad, because it's not clear what they mean, and when that something changes, the magic numbers don't change along with it. Instead, divide by map.tilewidth or map.tileheight, whatever you needed at that point. Use the actual variables that hold the values you need, don't sprinkle numbers throughout your code like that.

- I would place map collision detection inside the Map class - simply because it's likely that other kind of objects will need to check for collisions also, and you don't want to duplicate such code. Duplicated code is harder to maintain (it's easy to fix something in one place and to forget about the other places...).

- Checking tile collision values alone works fine for games that allow per-tile movement, but your characters move with a finer granularity. Doing an array lookup like this is still useful for determining what tiles you need to look at, but once that's done, I would use a rectangle-rectangle collision check to see if the character is running into a wall. If so, check how far the rectangle sticks into the wall, and only allow it to move up to that point.


Well, I hope all of that was useful to you, even though it doesn't point out any direct problems with the collision code (it's late here, no interest in digging up off-by-one errors and all that). ;)


EDIT: Ugh, I suppose I should bundle all these posts into a tutorial of sorts...
Create-ivity - a game development blog Mouseover for more information.
Captain P, thanks again for analyzing my code. I haven't had a chance to try any of your suggestions yet, but I have read through them and they make sense (I'm sure I'll have questions later). In a previous post you mentioned that there are advanced editors that allow you too see whitespace characters, which program do you recommend? I am running Mac OS X 10.5 (if that makes a difference). Thanks again.

Dusty
Captain P,

If I understood your previous post correctly, you stated that I needed to make a camera variable that is not tied to the player's movement. The only way I can think of using a camera variable would be to tie it to the player's movement. Could you please elaborate on this suggestion a little more (it seems like it won't be that hard, but I can't think how to do it). Also, I am currently in the process and everything you have suggested is working great, thanks again.

Dusty
Quote:Original post by dustfilledhobo
In a previous post you mentioned that there are advanced editors that allow you too see whitespace characters, which program do you recommend? I am running Mac OS X 10.5 (if that makes a difference).

Alas, the OS makes a difference. :( I'm on a Mac too now at work and I certainly miss some tools - but I haven't had much time to look for Mac counterparts to them. I did notice that IDLE is available if you install Python yourself, it doesn't seem to be included with the Python bundles that are shipped with Mac OS. But that's for interactive Python programming, not really an IDE for big programs. So yeah, if you find something, do tell. ;)

Quote:If I understood your previous post correctly, you stated that I needed to make a camera variable that is not tied to the player's movement. The only way I can think of using a camera variable would be to tie it to the player's movement.

Here you go:
# Let's create separate variables for each# (assume that Vec2 is a class that contains an x and y variable,# it's a bit more descriptive than using a tuple or list)camera = Vec2(0, 0)player = Character( ... )# As long as the camera is following the player, you'd do something like this every frame# (perhaps with some sort of offset, like half the screen width and height):camera.x = player.position.x - half_screen_widthcamera.y = player.position.y - half_screen_height# Oh, and to keep the camera 'inside' the map, store a bounding rectangle# and snap the camera to those value ranges. The max() and min() functions# should come in handy there.# Note: creating cut-scenes that center on other objects or positions is# doable now - you're no longer limited to always following a player. :)# For rendering, you'd pass the camera along, not the player position:map.draw(screen, camera)# And the map draws everything relative to the camera (not automatically,# of course... you'll have to add the camera position to the sprite draw# positions, but that's an easy thing to do)
Create-ivity - a game development blog Mouseover for more information.
Quote:Original post by Captain P
Checking tile collision values alone works fine for games that allow per-tile movement, but your characters move with a finer granularity. Doing an array lookup like this is still useful for determining what tiles you need to look at, but once that's done, I would use a rectangle-rectangle collision check to see if the character is running into a wall. If so, check how far the rectangle sticks into the wall, and only allow it to move up to that point.


I tried to follow your suggestion, but I must be missing something. Here is what I tried (the black rectangle was for debugging purposes). I thought it might be because I use the center of my character's rectangle, or the fact that my character's left and right images have different widths than its up and down images, but I was unable to figure out how these problems affected my code, because no matter what I tried, my character still was able to go half-way through each wall.

Here's my collision detection code:

if self.collision[int(math.ceil((char.rect.centery)/self.tileheight))][int(math.ceil((char.rect.centerx)/self.tilewidth))] == True:            self.rec_check_x = int(math.floor((char.rect.centerx)/self.tilewidth))            self.rec_check_y = int(math.floor((char.rect.centery)/self.tileheight))            wall = pygame.draw.rect(screen, (0, 0, 0), (self.tilewidth*self.rec_check_x, self.tileheight*self.rec_check_y, self.tilewidth, self.tileheight))            if char.rect.colliderect(wall) == True:                char.rect.center = (char.old_x, char.old_y)


The full source code is here: http://trovna.googlecode.com/files/Game%28fixing%20walls%29.zip

Just run Game.py

Dusty

This topic is closed to new replies.

Advertisement