Reputation: 21
I am currently trying to get accustomed with pygame and therefore building a platformer game. I have searched for this problem, but I couldn't find anything related. The problem is that my player teleports on top of my platform rectangle when they collide on either the left or right. I've tried to implement multiple fixes, such as alternating the players y-position, which creates other problems, as well as only triggering the collision effect if the player hits either side, not the top, but nothing seems to forego the teleportation of the player. This leads to the collision not triggering or the player colliding with an invisible wall on either the top left or the top right of the platform. Here is the code of the relevant file (pg = pygame):
from pygame.locals import *
from settings import *
vec = pg.math.Vector2
platforms = pg.sprite.Group()
grounds = pg.sprite.Group()
all_except_player = pg.sprite.Group()
class Player(pg.sprite.Sprite):
def __init__(self):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((20, 20))
self.image.fill(blue)
self.rect = self.image.get_rect()
self.pos = vec((10, 780))
self.vel = vec(0, 0)
self.acc = vec(0, 0)
def update(self):
platforms.add(plat1)
grounds.add(ground)
all_except_player.add(plat1, ground)
self.acc = vec(0, 0.5)
hits = pg.sprite.spritecollide(p, all_except_player, False)
if p.vel.y > 0:
if hits:
self.pos.y = hits[0].rect.top + 1
self.vel.y = 0
# this is where I assume the problem lies
wall_hits = pg.sprite.spritecollide(p, platforms, False)
if p.vel.x > 0:
if wall_hits:
self.pos.x = wall_hits[0].rect.left - 10
self.vel.x = 0
if p.vel.x < 0:
if wall_hits:
self.pos.x = wall_hits[0].rect.right + 10
self.vel.x = 0
keys = pg.key.get_pressed()
if keys[pg.K_a]:
self.acc.x -= acc
if keys[pg.K_d]:
self.acc.x += acc
if keys[pg.K_SPACE]:
self.jump()
self.acc.x += self.vel.x * fric
self.vel += self.acc
self.pos += self.vel + 0.5 * self.acc
if self.pos.x > width:
self.pos.x = 0
if self.pos.x < 0:
self.pos.x = width
self.rect.midbottom = self.pos
def jump(self):
hits = pg.sprite.spritecollide(self, all_except_player, False)
if hits:
self.vel.y -= 15
class Ground(pg.sprite.Sprite):
def __init__(self):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((width, 20))
self.image.fill(green)
self.rect = self.image.get_rect(center=(width/2, height - 10))
class Platform(pg.sprite.Sprite):
def __init__(self):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((100, 300))
self.image.fill(gray)
self.rect = self.image.get_rect(center=(width/2, height - 10))
plat1 = Platform()
p = Player()
ground = Ground()
I would greatly appreciate if someone could help me and point out my mistake.
Upvotes: 2
Views: 300
Reputation: 210889
Split it in 2 separate problems. First handle the collision with the sides of the platform. The player collides with the left side of the platform when moving to the right, colliding but the left side of the player does not collide with the platform. It collides with the right side of the platform when moving to the right, colliding but the right side does not collide with the platform. If the player collides sideways, correct his position so that he does not collide further. After that, do a new collision test and handle the collision with the top of the platform:
# handle sideways collision
self.rect.midbottom = self.pos
hits = pg.sprite.spritecollide(p, all_except_player, False)
if hits:
if p.vel.x > 0 and self.rect.left < hits[0].rect.left:
self.rect.right = hits[0].rect.left
self.pos = self.rect.midbottom
self.vel.y = 0
elif p.vel.x < 0 and self.rect.right > hits[0].rect.right:
self.rect.left = hits[0].rect.right
self.pos = self.rect.midbottom
self.vel.y = 0
# handel vertical collision
hits = pg.sprite.spritecollide(p, all_except_player, False)
if hits and p.vel.y > 0:
self.rect.bottom = hits[0].rect.top + 1
self.rect.midbottom = self.pos
self.vel.y = 0
Upvotes: 1