I'm not putting down the runnable code (~1.7K lines), just the piece that relates to the collision. I keep many functions in a file called auxfuncs.py
. The code runs in main.py
. There are many variables and objects here, but the main idea is that if there's masked collision between an obstacle and the moving ship, the direction in which the ship came from and the speed are used to move it back at the same distance and opposite direction.
The problem is, this code for some reason only works in about 75% of times.
import auxfuncs
...
#check masked collision
for ws in wall_sprite_group:
offset = (hero.rect.x - ws.rect.x, hero.rect.y - ws.rect.y)
diff = ws.wall_mask.overlap(hero.hero_mask, offset)
if diff:
auxfuncs.push_back(hero, sec)
The player's movement is
# fighter movement
if hero.direct == "left" and hero.rect.x > 0 and not hero.collide_list[2]:
hero.rect.x -= hero.set_speed * sec
elif hero.direct == "right" and hero.rect.right < SCREEN_SIZE[0] and not hero.collide_list[3]:
hero.rect.x += hero.set_speed * sec
elif hero.direct == "up" and hero.rect.y > 0 and not hero.collide_list[0]:
hero.rect.y -= hero.set_speed * sec
elif hero.direct == "down" and hero.rect.bottom < SCREEN_SIZE[1] and not hero.collide_list[1]:
hero.rect.y += hero.set_speed * sec
elif hero.direct == "northwest" and hero.rect.top > 0 and hero.rect.left > 0 and not hero.collide_list[
0] and not hero.collide_list[2]:
hero.rect.x -= hero.set_speed * sec
hero.rect.y -= hero.set_speed * sec
elif hero.direct == "northeast" and hero.rect.top > 0 and hero.rect.right < SCREEN_SIZE[0] and not \
hero.collide_list[0] and not hero.collide_list[3]:
hero.rect.x += hero.set_speed * sec
hero.rect.y -= hero.set_speed * sec
elif hero.direct == "southwest" and hero.rect.bottom < SCREEN_SIZE[1] and hero.rect.left > 0 and not \
hero.collide_list[1] and not hero.collide_list[2]:
hero.rect.x -= hero.set_speed * sec
hero.rect.y += hero.set_speed * sec
elif hero.direct == "southeast" and hero.rect.bottom < SCREEN_SIZE[1] and hero.rect.right < SCREEN_SIZE[
0] and not hero.collide_list[1] and not hero.collide_list[3]:
hero.rect.x += hero.set_speed * sec
hero.rect.y += hero.set_speed * sec
Finally, the auxfuncs.push_back
function that moves the ship back in the direction it came from is
def push_back(charact, sec):
if charact.direct == "left":
charact.rect.x += charact.set_speed * sec
charact.collide_list[2] = True
elif charact.direct == "right":
charact.rect.x -= charact.set_speed * sec
charact.collide_list[3] = True
elif charact.direct == "down":
charact.rect.y -= charact.set_speed * sec
charact.collide_list[1] = True
elif charact.direct == "up":
charact.rect.y += charact.set_speed * sec
charact.collide_list[0] = True
elif charact.direct == "northwest":
charact.rect.x += charact.set_speed * sec
charact.rect.y += charact.set_speed * sec
charact.collide_list[0], charact.collide_list[2] = True, True
elif charact.direct == "northeast":
charact.rect.x -= charact.set_speed * sec
charact.rect.y += charact.set_speed * sec
charact.collide_list[0], charact.collide_list[3] = True, True
elif charact.direct == "southwest":
charact.rect.x += charact.set_speed * sec
charact.rect.y -= charact.set_speed * sec
charact.collide_list[1], charact.collide_list[2] = True, True
elif charact.direct == "southeast":
charact.rect.x -= charact.set_speed * sec
charact.rect.y -= charact.set_speed * sec
charact.collide_list[1], charact.collide_list[3] = True, True
EDIT: In the hero class there are variables that point to the directions in which the collisions occurred:
self.collide_up = False
self.collide_down = False
self.collide_left = False
self.collide_right = False
self.collide_list = [self.collide_up, self.collide_down, self.collide_left, self.collide_right]