I am currently working on an abstraction layer for pygame, and have come across a problem when trying to check collisions with the maps. I am able to load and display the map, as well as store rectangles which are collidable. When I print the list of rectangles, I see that everything is in place, but when I iterate over every rect and try to check collision with another rect, it always returns true even when the rects do not collide. Also, when I try to debug all the rects by drawing a red-outlined rectangle over each one of them, nothing gets drawn even though when I print the rectangle, it prints a rectangle which exists.
Here are a few snippets from the framework:
class Tilemap(object):
"""This is the tilemap object, it takes an array of strings as its object, and places a surface where you have it in the strings. It only supports one surface per map, so you have to make multiple maps for floor, walls, etc."""
def __init__(self, level_surface,level_string = None, string_char = "#", surface = None, surface_dim = Vector2(50, 50),surface_color = (255, 255, 255)):
self.level = level_string
self.char = string_char
self.surface = surface
if self.surface is None:
self.surface = pygame.Surface(surface_dim)
self.surface.fill(surface_color)
self.surface_width = self.surface.get_rect().w
self.surface_height = self.surface.get_rect().h
self.collision_list = []
for y in xrange(len(self.level)):
for x in xrange(len(self.level[y])):
if self.level[y][x] is self.char:
self.collision_list.insert(len(self.collision_list), Rect((x) * self.surface_width,(y) * self.surface_height, self.surface_width, self.surface_height))
print self.collision_list
for y in xrange(len(self.level)):
for x in xrange(len(self.level[y])):
if self.level[y][x] is self.char:
level_surface.blit(self.surface.convert_alpha(), (self.surface_width * x, self.surface_height * y))
def replace_char_with(self, level_surface,char = ".", surface = None):
for y in xrange(len(self.level)):
for x in xrange(len(self.level[y])):
if self.level[y][x] is char:
level_surface.blit(surface.convert_alpha(), (surface.get_width() * x, surface.get_height() * y))
def check_col(self, rect):
for tilerect in self.collision_list:
if rect.x + rect.w > tilerect.x or rect.y + rect.h > tilerect.y or rect.x < tilerect.x + tilerect.w or rect.y < tilerect.y + tilerect.h:
return True
else:
return False
def debug_draw(self, screen):
for rect in self.collision_list:
pygame.draw.rect(screen, (255, 0, 0), rect, 2)
Snippet # 2, The testing code:
def main():
from pygame.locals import K_w, K_a, K_s, K_d
pygame.init()
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
player = Sprite(pygame.image.load("trapdoor_tile.png"), Vector2(100, 100))
floor = ["########################################",
"########################################",
"#####...##.#.#..###.#.###..#############",
"#####.######.#.#.####.##.#.#############",
"######.###.#.##..##.#.###.##############",
"#####.####.########.####################",
"#####.#.##.###.#.##.#.##.#.#############",
"########################################",
"#######################################",
"########################################",
"########################################",
"########################################",
"########################################",
"########################################"
"########################################",
"########################################",
"########################################",
"########################################",
"########################################",
"########################################",
"########################################",
"########################################",
"########################################",
"########################################",
"########################################",
"########################################",
"########################################",
"########################################",
"########################################",
"########################################"]
walls = ["########################################",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"########################################"]
level_surf = pygame.Surface((640, 480))
floor_map = Tilemap(level_surf, floor, "#", pygame.image.load("ground_tile.png").convert_alpha())
floor_map.replace_char_with(level_surf, ".", pygame.image.load("trapdoor_tile.png").convert_alpha())
wall_map = Tilemap(level_surf, walls, "#", pygame.image.load("wall_tile.png").convert_alpha())
while True:
screen.fill((0, 0, 0))
milliseconds = clock.tick(60) / 10.
for event in pygame.event.get():
if event.type == pygame.locals.QUIT:
pygame.quit()
raise SystemExit
wall_map.debug_draw(screen);
screen.blit(level_surf, Vector2(0, 0))
if wall_map.check_col(player.dummyrect):
player.colliding = True
print "why!"
else:
player.colliding = False
player.update(milliseconds)
player.draw(screen)
keystate = pygame.key.get_pressed()
player.apply_drag()
if keystate[K_w]:
player.set_accel_y(-5)
elif keystate[K_s]:
player.set_accel_y(5)
elif keystate[K_a]:
player.set_accel_x(-5)
elif keystate[K_d]:
player.set_accel_x(5)
pygame.display.flip()
The sprite class from which the player is created:
class Sprite(object):
def __init__(self, surface = None, initial_position = (100, 100)):
self.surface = surface
self.rect = self.surface.get_rect(center = initial_position)
self.acceleration = Vector2(0, 0)
self.delta_time = None
self.dummyrect = self.rect
self.colliding = False
def update(self, delta_time):
self.dummyrect = self.rect.move(self.acceleration.x * delta_time, self.acceleration.y * delta_time)
if not self.colliding:
self.rect = self.dummyrect
else:
self.dummyrect = self.rect
self.delta_time = delta_time
def draw(self, screen):
screen.blit(self.surface, self.rect)
def draw_to_cam(self, screen,camera):
screen.blit(self.surface, camera.to_camera_coords(Vector2(self.rect.x, self.rect.y)))
def collide(self, rectangle):
if self.rect.x + self.rect.w > rectangle.x:
self.rect.x -= 1;
if self.rect.x < rectangle.x + rectangle.w:
self.rect.x += 1
if self.rect.y < rectangle.y + rectangle.h:
self.rect.y += 1;
if self.rect.y + self.rect.h > rectangle.y:
self.rect.y -= 1;
def set_accel_x(self, new_val):
self.acceleration.x = new_val
def set_accel_y(self, new_val):
self.acceleration.y = new_val
def apply_drag(self, drag_mul = 1):
if self.acceleration.x > 0:
self.acceleration.x -= self.delta_time * drag_mul
else:
self.acceleration.x += self.delta_time * drag_mul
if self.acceleration.y > 0:
self.acceleration.y -= self.delta_time * drag_mul
else:
self.acceleration.y += self.delta_time * drag_mul
if self.acceleration.x < 0.1 or self.acceleration.x > -0.1:
self.acceleration.x = 0
if self.acceleration.x < 0.1 or self.acceleration.x > -0.1:
self.acceleration.x = 0
if self.acceleration.y < 0.1 or self.acceleration.y > -0.1:
self.acceleration.y = 0
if self.acceleration.y < 0.1 or self.acceleration.y > -0.1:
self.acceleration.y = 0
def get_center(self):
return Vector2(self.rect.centerx, self.rect.centery)
Those are the three main snippets involved, I have no idea why a collision is returned every time, but it seems to do so. If anyone has an answer, or explanation at least, as to why this occurs, please Help a brother out!