I am programming a platformer in PyGame, and when I added the code for platform gravity (which I'm not even sure works), the window went blank after having functioned properly for all the remaining code.
Here is my minimal, reproducible example:
import pygame
pygame.init()
win = pygame.display.set_mode((500,480))
platform = pygame.image.load('platform.png')
sprite = pygame.image.load('player.png')
platforms = []
class Platform(object):
def __init__(self, x, y):
self.x = x
self.y = y
def draw(self, win):
win.blit(platform, (self.x, self.y))
class Player(object):
def __init__(self, x, y):
self.x = x
self.y = y
self.hitbox = (self.x, self.y, 25, 25)
self.speedY = 0
def draw(self, win):
win.blit(sprite, (self.x, self.y))
pygame.draw.rect(win, (255, 0, 0), self.hitbox, 2)
#Checks whether the player is on a platform or below it
#If they are, then they stay
for platform in platforms:
while self.hitbox[1] + self.hitbox[3] >= platform.y + 36:
check = 0
while self.hitbox[1] + self.hitbox[3] < platform.y:
check = 1
#Keeps player on top
def touch_ground(self):
while self.hitbox[1] + self.hitbox[3] > platform.y:
self.speedY -= 1
self.y += self.speedY
#Makes player fall down until touching platform
def fall(self):
while check == 1:
self.speedY += 1
self.y += self.speedY
touch_ground()
I expected the player to fall when they weren't touching the platform and stay when they did, but instead I got a blank window, which, after 5 seconds, stopped responding. There were no error messages.
Here's the main code:
def redrawGameWindow():
win.blit(bg, (0,0))
bla.draw(win)
goblin.draw(win)
for platform in platforms:
platform.draw(win)
pygame.display.update()
run = True
while run:
clock.tick(27)
if level == 1:
p1 = platforms.append(Platform(150, 375, 'medium'))
p2 = platforms.append(Platform(300, 325, 'short'))
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
redrawGameWindow()
pygame.quit()
An issue is:
for platform in platforms: while self.hitbox[1] + self.hitbox[3] >= platform.y + 36: check = 0 while self.hitbox[1] + self.hitbox[3] < platform.y: check = 1
The conditions in the while loops will never change while the loops are running. If the condition is False, then the code in the loops is never executed, or if it evaluates to True, then the loops will never terminate.
It is unclear what this code is intended to do. The code snippet changes the state of a variable check, but this variables is evaluated in another loop:
def fall(self): while check == 1: self.speedY += 1 self.y += self.speedY touch_ground()
At the end this is an endless loop, too. The reason is the same as before. While the loop is running, the state of check doesn't change.
I recommend to read about pygame.sprite.Sprite respectively pygame.sprite.Group. See a simple example, which may do what you want.
The main idea of the code is the method fall.The method limits the fall to the bottom of the window. Further the method finds the platforms "under" the player and limits the fall to the top of the platform. Since the platforms which are under the player are identified first, then the fall is performed, and finally the fall is limited, the algorithm avoids "fall through" of the Player, even if the player falls down by a distance which is much grater than the sum of the height of the platform and the player.
class Player(pygame.sprite.Sprite):
# [...]
def fall(self, win, platforms):
# find platforms under the player
pl = [p for p in platforms if p.rect.left < self.rect.right and
p.rect.right > self.rect.left and
p.rect.top >= self.rect.bottom]
# fall down
self.speedY += 1
self.rect.y += self.speedY
if self.rect.bottom >= win.get_height():
# limit to the ground
self.rect.bottom = win.get_height()
self.speedY = 0
else:
# limit to the top of the platforms
for p in pl:
if self.rect.bottom >= p.rect.top:
self.rect.bottom = min(p.rect.top, self.rect.bottom)
self.speedY = 0
Full example which uses a Sprite for the platforms and the player. The Sprites are organized in Groups:
import pygame
pygame.init()
win = pygame.display.set_mode((500,480))
clock = pygame.time.Clock()
class Platform(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.image.load('player.png')
self.rect = self.image.get_rect(topleft = (x, y))
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.image.load('platform.png')
self.rect = self.image.get_rect(topleft = (x, y))
self.speedY = 0
def fall(self, win, platforms):
# find platforms under the player
pl = [p for p in platforms if p.rect.left < self.rect.right and
p.rect.right > self.rect.left and
p.rect.top >= self.rect.bottom]
# fall down
self.speedY += 1
self.rect.y += self.speedY
if self.rect.bottom >= win.get_height():
# limit to the ground
self.rect.bottom = win.get_height()
self.speedY = 0
else:
# limit to the top of the platforms
for p in pl:
if self.rect.bottom >= p.rect.top:
self.rect.bottom = min(p.rect.top, self.rect.bottom)
self.speedY = 0
p1 = Platform(150, 375)
p2 = Platform(300, 325)
platforms = pygame.sprite.Group([p1, p2])
player = Player(180, 0)
all_sprites = pygame.sprite.Group()
all_sprites.add(player)
all_sprites.add(platforms)
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
player.fall(win, platforms)
win.fill(0)
all_sprites.draw(win)
pygame.display.update()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With