Johnface
Johnface

Reputation: 21

Pygame Player teleports on top of rectangle

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

Answers (1)

Rabbid76
Rabbid76

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

Related Questions