I am making a platformer in PyGame which will involve there being an obstacle which the player has to maneuver through. I've set up how to make the base 'floor' of the game but I am having trouble getting the collisions to work properly when it comes to actual 'boxes' or obstacles. The code is split over 4 files which I'll upload but the bulk of the code is in the main game loop file and the file which contains the class for the player itself. The collision logic happens within the player class and is run as a function in the main loop. I've tried an assortment of methods in getting the collisions to work but something has always gone wrong. I want it so that jumping on the obstacle will cause the player to stand on it and run head-on into the obstacle won't allow the character to pass. Although I don't have the logic for standing on the obstacles, I do have some logic for preventing the player from running through them. But even then there are bugs. For example, running into the right side of an obstacle moves me over to the left side when it should be 'pushing back' against the player and negating his xVel to prevent further movement past the obstacle. There a couple more bugs with running into the obstacles which you can find out by running the program but any help with improving the horizontal collisions and developing the vertical collisions would be much appreciated. Main Game Loop:
import pygame
import character as c
import levels
pygame.init()
WINWIDTH = 1200
WINHEIGHT = 700
win = pygame.display.set_mode((WINWIDTH,WINHEIGHT))
pygame.display.set_caption('Game')
all_sprites = pygame.sprite.Group()
terrainSprites = pygame.sprite.Group()
obstacleSprites = pygame.sprite.Group()
player = c.Player(win, WINWIDTH, WINHEIGHT)
all_sprites.add(player)
terrainSprites.add(levels.level1Terrain)
obstacleSprites.add(levels.level1Obstacles)
mainloop = True
clock = pygame.time.Clock()
while mainloop:
for event in pygame.event.get():
if event.type == pygame.QUIT:
mainloop = False
all_sprites.update()
terrainSprites.update()
obstacleSprites.update()
player.collision(player.rect.x, player.rect.y)
win.fill((0,0,0))
terrainSprites.draw(win)
obstacleSprites.draw(win)
pygame.draw.rect(win, (255, 0, 0), obstacleSprites.sprites()[0].rect, 2)
pygame.draw.rect(win, (255, 0, 0), player.rect, 2) # (player.rect.x + 4, player.rect.y + 5, 43, 50)
all_sprites.draw(win)
pygame.display.flip()
clock.tick(60)
pygame.quit()
Character File Which Contains the Player Class and the Collision Logic:
import pygame
class Player(pygame.sprite.Sprite):
def __init__(self, surface, WINWIDTH, WINHEIGHT):
pygame.sprite.Sprite.__init__(self)
self.framecounter = 1
self.images = []
self.idleframes = []
self.surface = surface
self.width = 40
self.height = 60
self.WINWIDTH = WINWIDTH
self.WINHEIGHT = WINHEIGHT
self.xVel = 5
self.yVel = 5
self.jumpActive = False
self.jumpCounter = 12
self.walking = False
self.grounded = True
#LOAD WALKCYCLE
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/1.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/2.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/3.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/4.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/5.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/6.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/7.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/8.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/9.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/10.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/11.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/12.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/13.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/14.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/15.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/16.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/17.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/18.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/19.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/20.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/21.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/22.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/23.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/24.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/25.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/26.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/27.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/28.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/29.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/30.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/31.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/32.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/33.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/34.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/35.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/36.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/37.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/38.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/39.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/40.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/41.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/42.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/43.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/44.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/45.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/46.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/47.png"))
self.images.append(pygame.image.load("D:/PythonProjects/game/Assets/WalkCycleLeft - Copy/48.png"))
# LOAD JUMP UP - Idx. 48
self.images.append(pygame.image.load("D:\PythonProjects\game\Assets\Pixel Adventure 1\Free\Main Characters\Virtual Guy\Jump (32x32).png"))
# LOAD JUMP FALL - Idx. 49
self.images.append(pygame.image.load("D:\PythonProjects\game\Assets\Pixel Adventure 1\Free\Main Characters\Virtual Guy\Fall (32x32).png"))
#LOAD IDLE FRAMES - Idx. >49
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/1.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/1.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/1.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/1.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/2.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/2.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/2.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/2.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/3.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/3.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/3.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/3.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/4.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/4.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/4.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/4.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/5.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/5.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/5.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/5.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/6.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/6.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/6.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/6.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/7.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/7.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/7.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/7.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/8.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/8.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/8.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/8.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/9.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/9.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/9.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/9.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/10.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/10.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/10.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/10.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/11.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/11.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/11.png"))
self.idleframes.append(pygame.image.load("D:/PythonProjects/game/Assets/Idle/11.png"))
self.framecounter = 1
self.idlecounter = 1
self.image = self.images[self.framecounter]
self.image = pygame.transform.scale(self.image, (50,50))
self.rect = self.image.get_rect()
self.rect.x = 200
self.rect.y = 640
self.rect.width = 50
self.rect.height = 50
self.facing = None
def update(self):
self.walking = False
keys = pygame.key.get_pressed()
if keys[pygame.K_a]:
self.rect.x -= self.xVel
self.walkcycle()
self.facing = 'left'
self.walking = True
elif keys[pygame.K_d]:
self.rect.x += self.xVel
self.walkcycle('right')
self.facing = 'right'
self.walking = True
else:
self.walking = False
if self.jumpActive == False and self.grounded == True:
if keys[pygame.K_SPACE]:
self.jumpActive = True
else:
if self.jumpCounter >= -12:
self.jumpUPAnim()
neg = 1
if self.jumpCounter < 0:
self.fallAnim()
neg = -1
self.rect.y -= int((self.jumpCounter ** 2) * 0.25 * neg)
self.jumpCounter -= 1
else:
self.jumpCounter = 12
self.jumpActive = False
if self.rect.x >= (self.WINWIDTH - 40):
self.rect.x = int(self.WINWIDTH - 40)
elif self.rect.x <= 0:
self.rect.x = 0
if self.rect.y >= (self.WINHEIGHT - 55):
self.rect.y = int(self.WINHEIGHT - 55)
self.grounded = True
elif self.rect.y <= 0:
self.rect.y = 0
self.idleAnim(self.facing)
self.gravity()
def walkcycle(self, facing = None):
self.image = self.images[self.framecounter]
self.image = pygame.transform.scale(self.image, (50,50))
if facing == 'right':
self.image = pygame.transform.flip(self.image, True, False)
self.framecounter += 1
if self.framecounter == 48:
self.framecounter = 1
def jumpUPAnim(self):
self.image = self.images[48]
self.image = pygame.transform.scale(self.image, (50,50))
if self.facing == 'left':
self.image = pygame.transform.flip(self.image, True, False)
def fallAnim(self):
self.image = self.images[49]
self.image = pygame.transform.scale(self.image, (50,50))
if self.facing == 'left':
self.image = pygame.transform.flip(self.image, True, False)
def idleAnim(self, facing):
if self.jumpActive == False and self.walking == False:
self.image = self.idleframes[self.idlecounter]
self.image = pygame.transform.scale(self.image, (50,50))
if facing == 'left':
self.image = pygame.transform.flip(self.image, True, False)
self.idlecounter += 1
if self.idlecounter == 44:
self.idlecounter = 1
def collision(self, store_x, store_y):
from main import terrainSprites
from main import obstacleSprites
old_pos = self.rect.x, self.rect.y
for i in terrainSprites:
if pygame.sprite.spritecollide(self, terrainSprites, False):
if self.rect.y < i.rect.top:
self.rect.bottom = i.rect.top
return True
else:
return False
for i in obstacleSprites:
if pygame.sprite.spritecollide(self, obstacleSprites, False):
if self.rect.bottom < i.rect.top:
self.yVel = 0
else:
self.yVel = 5
self.rect.y = store_y
if pygame.sprite.spritecollide(self, obstacleSprites, False):
if self.rect.right < i.rect.left:
self.xVel = 0
else:
self.xVel = 5
self.rect.x = store_x
def gravity(self):
self.rect.y += self.yVel
Entire project folder containing all the files including the terrain file which has the class for generating terrain, the obstacle file, which has the class for generating obstacles, and the levels file which builds a level using the obstacle and terrain classes. The project also includes assets: https://drive.google.com/drive/folders/13XirZjMSAB_p3TJFFDFYtRG-oIE0XjAz?usp=sharing