# Scrolling and Obstacle Detection [PYTHON/PYGAME]

This topic is 2989 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

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()

#A - Action (broken into ALTER steps)

#A Assign values to key variables
goodSprites = pygame.sprite.Group(char)
itemSprites = pygame.sprite.Group(gold, gold1, gold2)
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:
last_key_pressed = "LEFT"
elif event.key == pygame.K_RIGHT:
if char.rect.centerx == char.start_x:
last_key_pressed = "RIGHT"
elif event.key == pygame.K_UP:
if char.rect.centery == char.start_y:
last_key_pressed = "UP"
elif event.key == pygame.K_DOWN:
if char.rect.centery == char.start_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:
#char.rect.centerx += char.speed
elif event.key == pygame.K_RIGHT:
#char.rect.centerx -= char.speed
elif event.key == pygame.K_UP:
#char.rect.centery += char.speed
elif event.key == pygame.K_DOWN:
#char.rect.centery -= char.speed

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)
elif last_key_pressed == "DOWN":
char.movecount += 1
char.movecount = char.movecount % len(charImages.character_array_front)
elif last_key_pressed == "LEFT":
char.movecount += 1
char.movecount = char.movecount % len(charImages.character_array_left)
elif last_key_pressed == "RIGHT":
char.movecount += 1
char.movecount = char.movecount % len(charImages.character_array_right)

######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

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)
infoSprites.clear(screen, background)

###Update the sprite group positions, etc.
goodSprites.update(last_key_pressed)
itemSprites.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)
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

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.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

##### Share on other sites
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

##### Share on other sites
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]

##### Share on other sites
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

##### Share on other sites
I'm glad you got it working, sorry I was not more help =p

##### Share on other sites
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...

##### Share on other sites
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

##### Share on other sites
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

##### Share on other sites
Quote:
 Original post by dustfilledhoboIn 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)

##### Share on other sites
Quote:
 Original post by Captain PChecking 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

##### Share on other sites
Quote:
 Original post by dustfilledhoboI 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.

Personally I'd use a predetermined rectangle instead of the bounding box of the current sprite. It's a bit more flexible, and you can be certain that your collision area never changes (e.g. it could suddenly become larger when you turn around, pushing you out of the wall, which may not be what you want when simply turning).

As for your collision test, the problem lies with the tile lookup code. Indeed, you're using only the center of the player, so only once the center comes into contact with a solid tile you're doing a rectangle-rectangle check. Those rectangles did already collide, but you skipped that test. If you're working with rectangles, you often need to check a range of tiles, not just one. For each corner, check what tile it is in. Those are the boundary tiles of the tile area that you need to perform collision tests on.

Say, you're controlling a huge elephant, and his left side just touches the 4th collumn. His right side touches the 8th collumn. That means he's touching tiles in 5 collumns! The same goes for the top and bottom. Let's say those are rows 6 - 9, 4 rows in total. The elephant is touching or overlapping 20 tiles. At the very least you will have to test against the border tiles of that area - not just one tile. The same applies to your game: even though the player is small, he can still touch 4 tiles at once.

##### Share on other sites
Captain P, it worked perfectly. I had never used topleft, topright, etc. before. Your solution should have been obvious to me, but it wasn't. So, thanks again for helping a struggling (and sometimes dense) newbie.

Dusty

##### Share on other sites
No problem - we all have to learn things. :)

To come back to the IDE question, you may want to try some of the tools mentioned here. There are some cross-platform and Mac programs mentioned, maybe there's one that suits your needs.

##### Share on other sites
Quote:
 Original post by Captain PTo come back to the IDE question, you may want to try some of the tools mentioned here. There are some cross-platform and Mac programs mentioned, maybe there's one that suits your needs.

I downloaded the TextMate trial, and I think that I fixed my mixing tabs and spaces problem (please let me know if I didn't).

Also, I have been trying to create the camera in my game based on Captain P's suggestions, just a few posts above this one.

My current code leaves the player centered with respect to the background, and the entire background shifts with the player, where I want the player to stay in the middle of the screen and have the background scroll. Sorry if my explanation is not clear. It seems like the scrolling is almost working in reverse.

I am not fully understanding the Vec2(0,0) part of Captain P's suggestion. I created the class below, but I believe that I am still using a list where it was suggested that a vector would be better.

Camera.py::::
import pygameclass CameraVector:    def __init__(self, resolution, map1):        self.bounding_rectangle = pygame.Rect(0, 0, resolution[0], resolution[1])#map1.numXTiles*map1.tilewidth, map1.numYTiles*map1.tileheight)        self.camera_vector = resolution        self.x = self.camera_vector[0]         self.y = self.camera_vector[1]        self.camera_rect = pygame.Rect(self.x, self.y,resolution[0], resolution[1])    def update(self, resolution, char):        self.x = char.rect.centerx - resolution[0]/2        self.y = char.rect.centery - resolution[1]/2        self.camera_rect.clamp(self.bounding_rectangle)

MapFunctions.py::::::
import pygame, mathfrom Map import ImageCacheclass Map():    def __init__(self, resolution, last_key_pressed):        self.tiles = []        self.images = []        self.collision = []         self.tilewidth = 40        self.tileheight = 40        self.resolution = resolution        self.last_key_pressed = last_key_pressed                 self.numXTiles = int(math.ceil(float(self.resolution[0]) / self.tilewidth)) + 1        self.numYTiles = int(math.ceil(float(self.resolution[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 load(self, map_file, resolution, char):        self.char = char        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 + ']'                        #print "Max: (" +str(self.maxHorzScrollBounds)+ ", " +str(self.maxVertScrollBounds)+ ")"                def draw(self, screen, char, camera):        startXTile = int(math.floor(camera.x/self.tilewidth))        startYTile = int(math.floor(camera.y/self.tileheight))        #print "camera coords: (" +str(camera.x)+", "+str(camera.y)+")"        #print "start tiles: (" +str(startXTile)+", "+str(startYTile)+")"                for x in range(startXTile, self.numXTiles + startXTile):            for y in range(startYTile, self.numYTiles + startYTile):                self.tiledBG.blit(self.images[self.tiles[y][x]], ((x) * self.tilewidth, (y) * self.tileheight))        screen.blit(self.tiledBG, (startXTile*self.tilewidth, startYTile*self.tileheight))                #Did we hit a wall????                ### The following if/else block checks the topleft, topright, bottomleft, and bottomright coordinates of the character's        ### rectangle to see if they collide with any walls.  If they collide the player is not allowed to advance, if there is no        ### collision, then the char_old variables are reset to the current position of the charactcer.                            if self.collision[int(math.floor((char.rect.topleft[1])/self.tileheight))][int(math.ceil((char.rect.topleft[0])/self.tilewidth))] == True: #checking topleft coordinate for collision            char.rect.center = (char.old_x, char.old_y)        elif self.collision[int(math.floor((char.rect.topright[1])/self.tileheight))][int(math.ceil((char.rect.topright[0])/self.tilewidth))] == True: #checking topright coordinate for collision            char.rect.center = (char.old_x, char.old_y)        elif self.collision[int(math.floor((char.rect.bottomright[1])/self.tileheight))][int(math.ceil((char.rect.bottomright[0])/self.tilewidth))] == True: #checking bottomright coordinate for collision            char.rect.center = (char.old_x, char.old_y)        elif self.collision[int(math.floor((char.rect.bottomleft[1])/self.tileheight))][int(math.ceil((char.rect.bottomleft[0])/self.tilewidth))] == True: #checking bottomleft coordinate for collision            char.rect.center = (char.old_x, char.old_y)                        else:            #Didn't hit a wall            char_old_x = char.rect.centerx            char_old_y = char.rect.centery

Thanks in advance for any help.

Dusty

##### Share on other sites
I am still having trouble with the code in my previous post. I think that it might have something to do with the way I am attempting to snap to my bounding rectangle, but I can't figure it out. Sorry for the re-post, but I keep attempting to solve this and nothing I try seems to work. Thanks in advance for any help that you can offer.

Dusty

##### Share on other sites
I don't have much time now, but if you want to snap the camera to a certain rectangular area, you'll need to keep the size of the screen in mind as well. What it comes down to is keeping one rectangle inside another.

The logic is fairly easy: if the inner rectangle's left side is further to the left than the outer rectangle's left side, then set it's left side to the left side of the outer rectangle. Same goes for all four sides. In your case, the inner rectangle is the camera position combined with the screen dimension, and the outer rectangle is the map boundary.

As for vectors, using tuples or lists will work just as well, they're just a little more obscure (camera.x is more descriptive than camera[0]). Same goes for rectangles. The above approach is easier to implement when you've got a Rectangle class that provides left(), right(), top() and bottom() functions (besides just containing an x, y, width and height).

##### Share on other sites
I'm still having trouble with the scrolling/obstacle detection of my game. Currently my game scrolls exactly how I want it to (the player stays in the center of the screen unless he reaches one of the outer bounds of the map). My problem lies in the obstacle detection. Here are some things I have tried:

(1) I have tried shifting the walls based on my camera's x and y coordinates, but this always allowed me to go partially into the wall, or it restricted me from passing when I was far away from a wall.

(2) I tried creating a list that contained rectangles for each tile that was not walkable, but failed when I didn't know how to determine which rectangle to test for a collision. Also, the way I was doing this I was still using the same list to look up for the collision as (1), so I think even if I got this to work I would have had similar results as (1)

(3) I even tried defining each pixel as being walkable or not. This was my last resort, and was way too slow (obviously) to do anything with.

My current code allows scrolling and it leaves the walls in their original position on the screen, so if Im in the top left portion of the map my upper and left walls work, but everything else does not, and I know this is because I don't have any code to allow the walls to shift. Captain P has given me many great suggestions, but I am not fully understanding how to implement them with my code. So, I am asking for help once again. Thank You!!!

But I think this is all you will need:

Game.py::::
#Change the version number and put your name after you edit#V Whatever#Whoever# KEEP THE CODE ORGANIZED# make changes in the right section# comments will help others (and YOU) understand# IDEA/ALTER model#I - Import and initializeimport pygameimport randomimport mathimport CharacterSpritesimport EnemySpritesimport ItemSpritesimport HUDsimport MapFunctionsimport ImagePathsimport Camerafrom Map import ImageCachefrom pygame.locals import *######initializing global variables###############initialize pygame#######pygame.init()#D - Display configurationresolution = (800,600)screen = pygame.display.set_mode(resolution)last_key_pressed = "DOWN"charImages = ImagePaths.CharImagePaths()fps = 30######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))    last_key_pressed = "DOWN"    # Assign sprite classes and other classes to variables    char = CharacterSprites.Char(charImages, fps, resolution, last_key_pressed)    info = HUDs.HUD()    info.center = (100, 50)    map1 = MapFunctions.Map(resolution, last_key_pressed)    map1.load('Map/map.txt', resolution, char)    boundingRectangle = Camera.BoundingRectangle(map1)    camera = Camera.Camera(boundingRectangle, char)    wiz = EnemySprites.Wiz(screen)    wiz1 = EnemySprites.Wiz(screen)    wiz2 = EnemySprites.Wiz(screen)    gold = ItemSprites.Gold()    gold1 = ItemSprites.Gold()    gold2 = ItemSprites.Gold()    cache = ImageCache.ImageCache()        #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(fps) #setting frame rate number = fps        #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        # 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:                    char.moveWest = True                    last_key_pressed = "LEFT"                elif event.key == pygame.K_RIGHT:                    char.moveEast = True                    last_key_pressed = "RIGHT"                elif event.key == pygame.K_UP:                    char.moveNorth = True                    last_key_pressed = "UP"                elif event.key == pygame.K_DOWN:                    char.moveSouth = True                    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:                    char.moveWest = False                    char.image = char.charImages.character_images_left[0]                elif event.key == pygame.K_RIGHT:                    char.moveEast = False                    char.image = char.charImages.character_images_right[0]                elif event.key == pygame.K_UP:                    char.moveNorth = False                    char.image = char.charImages.character_images_back[0]                elif event.key == pygame.K_DOWN:                    char.moveSouth = False                    char.image = char.charImages.character_images_front[0]                     ######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, pygame.time.get_ticks(), camera, boundingRectangle)        itemSprites.update()        badSprites.update()        infoSprites.update()        camera.update(char, boundingRectangle, map1)        ###Draw new sprite groups        map1.draw(screen, char, camera)        goodSprites.draw(screen)        itemSprites.draw(screen)        badSprites.draw(screen)        infoSprites.draw(screen)        ####Switch the screen to the new information        pygame.display.flip()            # End main game loopif __name__ == "__main__":    main()

MapFunctions.py::::
import pygame, mathfrom Map import ImageCacheclass Map():    def __init__(self, resolution, last_key_pressed):        self.tiles = []        self.images = []        self.collision = []         self.shift_wall_x = 0        self.shift_wall_y = 0        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()                 self.resolution = resolution        self.last_key_pressed = last_key_pressed        self.advanceVelocity_x = 0        self.advanceVelocity_y = 0                 self.numXTiles = int(math.ceil(float(self.resolution[0]) / self.tilewidth)) + 1        self.numYTiles = int(math.ceil(float(self.resolution[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 load(self, map_file, resolution, char):        self.char = char        self.resolution = resolution                        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 + ']'                        #print "Max: (" +str(self.maxHorzScrollBounds)+ ", " +str(self.maxVertScrollBounds)+ ")"                def draw(self, screen, char, camera):        self.startXTile = int(math.floor(float(camera.x) / self.tilewidth))        self.startYTile = int(math.floor(float(camera.y) / self.tileheight))                              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, (0, 0), (camera.x - (self.startXTile * self.tilewidth), (camera.y - (self.startYTile * self.tileheight))) + self.resolution)        #Did we hit a wall????                ### The following if/else block checks the topleft, topright, bottomleft, and bottomright coordinates of the character's        ### rectangle to see if they collide with any walls.  If they collide the player is not allowed to advance, if there is no        ### collision, then the char_old variables are reset to the current position of the charactcer.        if self.collision[int(math.floor((char.rect.topleft[1])/self.tileheight))][int(math.ceil((char.rect.topleft[0])/self.tilewidth))]: #checking topleft coordinate for collision            char.rect.center = (char.old_x, char.old_y)            camera.x = camera.old_x            camera.y = camera.old_y        elif self.collision[int(math.floor((char.rect.topright[1])/self.tileheight))][int(math.ceil((char.rect.topright[0])/self.tilewidth))]: #checking topright coordinate for collision            char.rect.center = (char.old_x, char.old_y)            camera.x = camera.old_x            camera.y = camera.old_y        elif self.collision[int(math.floor((char.rect.bottomright[1])/self.tileheight))][int(math.ceil((char.rect.bottomright[0])/self.tilewidth))]: #checking bottomright coordinate for collision            char.rect.center = (char.old_x, char.old_y)            camera.x = camera.old_x            camera.y = camera.old_y        elif self.collision[int(math.floor((char.rect.bottomleft[1])/self.tileheight))][int(math.ceil((char.rect.bottomleft[0])/self.tilewidth))]: #checking bottomleft coordinate for collision            char.rect.center = (char.old_x, char.old_y)            camera.x = camera.old_x            camera.y = camera.old_y        else:            #Didn't hit a wall            char_old_x = char.rect.centerx            char_old_y = char.rect.centery            camera.old_x = camera.x            camera.old_y = camera.y

Camera.py::::
import pygame, mathclass BoundingRectangle:    def __init__(self, map1):        self.max_right_bound = map1.tilewidth * len(map1.tiles[0]) - map1.resolution[0] - 1        self.max_left_bound = 0        self.max_top_bound = 0        self.max_bottom_bound = map1.tileheight * len(map1.tiles) - map1.resolution[1] - 1                   def right(self):        return self.max_right_bound        def left(self):        return self.max_left_bound        def top(self):        return self.max_top_bound        def bottom(self):        return self.max_bottom_boundclass Camera:    def __init__(self, boundingRectangle, char):        self.x = 0          self.y = 0        self.advanceVelocity_x = 0        self.advanceVelocity_y = 0        self.scrollVelocity = char.speed        self.wall_shift_x = 0        self.wall_shift_y = 0        self.old_x = self.x        self.old_y = self.y        self.max_bound = False    def update(self, char, boundingRectangle, map1):        #Snap scrolling window to the Bounding Rectangle        max_bound = False        if self.x <= boundingRectangle.left():            self.x = boundingRectangle.left()            self.max_bound = True        if self.x >= boundingRectangle.right():            self.x = boundingRectangle.right()            self.max_bound = True        if self.y <= boundingRectangle.top():            self.y = boundingRectangle.top()            self.max_bound = True        if self.y >= boundingRectangle.bottom():            self.y = boundingRectangle.bottom()            self.max_bound = True                #shift wall positions (x,y)        self.wall_shift_x = int(math.floor(self.x / map1.tilewidth))        self.wall_shift_y = int(math.floor(self.y / map1.tileheight))        #print "wall shifts: (" +str(self.wall_shift_x)+ ", " +str(self.wall_shift_y)+ ")"         #print "Camera Coordinates: (" +str(self.x)+ ", " +str(self.y)+ ")"

CharacterSprites.py::::
import pygame, math, Map, ImagePathsfrom Map import ImageCacheclass Char(pygame.sprite.Sprite):    def __init__(self, charImages, fps, resolution, last_key_pressed):        pygame.sprite.Sprite.__init__(self)        self.charImages = charImages        self.start = pygame.time.get_ticks()        self.delay = 1000 / fps        self.last_update = 0        self.frame = 0        self.last_key_pressed = last_key_pressed        self.image = self.charImages.character_images_front[self.frame]                if self.last_key_pressed == "UP":            self.image = self.charImages.character_images_back[self.frame]        if self.last_key_pressed == "DOWN":            self.image = self.charImages.character_images_front[self.frame]        if self.last_key_pressed == "RIGHT":            self.image = self.charImages.character_images_right[self.frame]        if self.last_key_pressed == "LEFT":            self.image = self.charImages.character_images_left[self.frame]        self.resolution = resolution                self.image = self.image.convert()        self.rect = self.image.get_rect()        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        self.moveNorth = False        self.moveSouth = False        self.moveEast = False        self.moveWest = False             def reset(self):        self.rect.centerx = self.start_x        self.rect.centery = self.start_y    def update(self, last_key_pressed, t, camera, boundingRectangle):     # Put the player in the new spot        self.last_key_pressed = last_key_pressed        #if abs(self.start_x - self.rect.centerx) < self.speed:            #self.rect.centerx = self.start_x                            if self.moveNorth:            self.animate(self.charImages.character_images_back, t)            if camera.y == boundingRectangle.top() or self.rect.centery > self.start_y:                self.rect.centery -= self.speed            if self.rect.centery == self.start_y:                camera.y -= self.speed                                                if self.moveSouth:            self.animate(self.charImages.character_images_front, t)            if camera.y == boundingRectangle.bottom() or self.rect.centery < self.start_y:                self.rect.centery += self.speed            if self.rect.centery == self.start_y:                camera.y += self.speed                                                if self.moveEast:            self.animate(self.charImages.character_images_right, t)            if camera.x == boundingRectangle.right() or self.rect.centerx < self.start_x:                self.rect.centerx += self.speed            if self.rect.centerx == self.start_x:                camera.x += self.speed                                                if self.moveWest:            self.animate(self.charImages.character_images_left, t)            if camera.x == boundingRectangle.left() or self.rect.centerx > self.start_x:                self.rect.centerx -= self.speed            if self.rect.centerx == self.start_x:                camera.x -= self.speed                                if self.moveNorth == False and self.moveSouth == False and self.moveEast == False and self.moveWest == False:            if self.last_key_pressed == "UP":                self.image = self.charImages.character_images_back[0]            if self.last_key_pressed == "DOWN":                self.image = self.charImages.character_images_front[0]            if self.last_key_pressed == "RIGHT":                self.image = self.charImages.character_images_right[0]            if self.last_key_pressed == "LEFT":                self.image = self.charImages.character_images_left[0]            self.frame = 0        #print "Frame: " + str(self.frame)        #print "last_key_pressed: " + self.last_key_pressed        #print self.image        self.rect.center = (self.rect.centerx, self.rect.centery)       def animate(self, image_array, t):                if t - self.last_update > self.delay:                self.frame += 1                if self.frame >= len(image_array):                    self.frame = 0                self.image = image_array[self.frame]                self.colorkey = self.image.get_at((0, 0))                self.image.set_colorkey(self.colorkey)                self.last_update = t        #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