0

I have been trying to create a 2D platformer in pygame, and I have encountered a problem with the collision of the player sprite with the platform. I hope to implement full collision for the platforms, so that the player sprite will stop when it hits the platform from any direction. Currently, the sprite stops when it hits the top of the platforms, but if it collides with the bottom or sides of a platform it instantly jumps to the top of the platform. I have tried various things to solve this, but to no avail. Any help would be appreciated.

I have seperated my code into 3 files. This is my main file:

import pygame
from settings import *
from sprites import *


#Game Class
class Game:                   

    def __init__(self):
        pygame.init()
        pygame.mixer.init()
        self.gameDisplay = pygame.display.set_mode((displayWidth, displayHeight))
        self.clock = pygame.time.Clock()
        self.gameRunning = True


    #Stars the game
    def new(self):
        self.allSprites = pygame.sprite.Group()
        self.platforms  = pygame.sprite.Group()
        self.player = Player(self)
        self.allSprites.add(self.player)
        floor = Platform(0, 680, displayWidth, 40)
        plat2 = Platform( 500, 400, 100, 40)
        self.allSprites.add(floor, plat2)
        self.platforms.add(floor, plat2)
        self.run()

    #Game Loop
    def run(self):
        self.gameRunning = True
        while self.gameRunning == True:
            self.clock.tick(FPS)
            self.events()
            self.update()
            self.draw()

    #Updates the screen
    def update(self):     
        self.allSprites.update()

        hits = pygame.sprite.spritecollide(self.player, self.platforms, False)

        if hits:
            self.player.pos.y = hits[0].rect.top
            self.player.spd.y = 0
            self.player.rect.midbottom = self.player.pos

        if self.player.rect.left >= displayHeight - 200:
            self.player.pos.x -= abs(self.player.spd.x)
            for plat in self.platforms:
                plat.rect.x -= abs(self.player.spd.x)
        if self.player.rect.right <= displayHeight / 4:
            self.player.pos.x += abs(self.player.spd.x)
            for plat in self.platforms:
                plat.rect.x += abs(self.player.spd.x)


    #Events loop
    def events(self):       
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP:
                    self.player.jump()


    #Draws things to the screen
    def draw(self):         
        self.gameDisplay.fill(LIGHT_BLUE)
        self.allSprites.draw(self.gameDisplay)

        pygame.display.update()


def runGame():    
    game = Game()
    game.new()
runGame()

Sprites file:

import pygame
from settings import *
vec = pygame.math.Vector2

#Player Class
class Player(pygame.sprite.Sprite):

    def __init__(self, game):
        pygame.sprite.Sprite.__init__(self)
        self.game = game
        self.image = pygame.Surface([40, 40])
        self.image.fill(DARK_BLUE)
        self.rect = self.image.get_rect()
        self.rect.center = (displayWidth / 2, displayHeight / 2)
        self.pos = vec(displayWidth / 2, displayHeight / 2)
        self.spd = vec(0,0)
        self.acc = vec(0,0)


    def update(self):
        self.acc = vec(0, playerGrav)
        keysPressed = pygame.key.get_pressed()
        if keysPressed[pygame.K_LEFT]:
            self.acc.x = - playerAcc
        if keysPressed[pygame.K_RIGHT]:
            self.acc.x = playerAcc


        self.acc.x += self.spd.x *  playerFric
        self.spd += self.acc
        self.pos += self.spd + 0.5 * self.acc

        self.rect.midbottom = self.pos



    def jump(self):
        self.rect.y +=1
        hits = pygame.sprite.spritecollide(self, self.game.platforms, False)
        self.rect.y -= 1
        if hits:
            self.spd.y = -20


class Platform(pygame.sprite.Sprite):

    def __init__(self, x, y, w, h):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((w, h))
        self.image.fill((GREEN))
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

Settings File:

import pygame

pygame.font.init()

#Setup
FPS = 60
displayWidth = 1280
displayHeight = 720
pygame.display.set_caption("2D Platformer")
gameDisplay = pygame.display.set_mode((displayWidth, displayHeight))
clock = pygame.time.Clock()

#Player
playerAcc = 0.5
playerFric = -0.1
playerGrav = 0.5


#Colour Pallette
BLACK      = (0,   0,   0  )
WHITE      = (255, 255, 255)
RED        = (200, 0,   0  )
GREEN      = (0,   200, 0  )
BLUE       = (0,   0,   200)
LIGHT_BLUE = (0,   191, 255)
DARK_BLUE  = (0,   50,   150)

#Score
score = 0

This is the code that is responsible for collision:

hits = pygame.sprite.spritecollide(self.player, self.platforms, False)

if hits:
    self.player.pos.y = hits[0].rect.top
    self.player.spd.y = 0
    self.player.rect.midbottom = self.player.pos

I understand that the reason why the sprite jumps to the top of the platform is due to these lines of code:

if hits:
    self.player.pos.y = hits[0].rect.top

However, I don't know how to implement full collision.

  • see [1.4 Platformer examples](http://programarcadegames.com/index.php?chapter=example_code&lang=pl#section_38) on [Program Arcade Games With Python And Pygame](http://programarcadegames.com/). There is example [platform_jumper.py](http://programarcadegames.com/python_examples/show_file.php?file=platform_jumper.py) (PL: powodzenia) – furas Feb 15 '20 at 17:41
  • [A link](https://stackoverflow.com/questions/59957214/collision-detection-against-player-and-blocks-in-the-map) to a brilliant answer to one of my questions. Take a look at Rabbid76's answer –  Feb 17 '20 at 00:06

0 Answers0