Posts: 26
Threads: 7
Joined: Sep 2022
import pygame
# Initialize pygame
pygame.init()
# Set the screen size and caption
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("My Mario Game")
class Mario():
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.color = (255, 0, 0) # red color
self.y_velocity = 0
self.jumping = False
def draw(self, screen):
pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height))
def check_collision(self, floor):
# check if bottom of Mario object is at or below top of Floor object
if self.y + self.height >= floor.y:
# check if left and right edges of Mario object are within left and right edges of Floor object
if self.x >= floor.x and self.x + self.width <= floor.x + floor.width:
return True
return False
def handle_collision(self, floor):
self.y = floor.y - self.height
self.y_velocity = 0
self.jumping = False
if self.x < floor.x + floor.width and self.x > floor.x: # Check if collision is occurring on the left edge
if self.x < screen.get_width() - self.width:
self.x = floor.x + floor.width
else:
self.x = floor.x + floor.width
class Floor():
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.color = (0, 200, 0) #green color
def draw(self, screen):
pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height))
floors = [Floor(0, 550, 800, 50), Floor(200, 450, 400, 50), Floor(600, 350, 200, 50)]
# Create a Mario object
mario = Mario(100, 400, 50, 100)
# Main game loop
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
if mario.jumping == False:
mario.y_velocity = -1
mario.jumping = True
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
if mario.x > 0: # Check if Mario is within the left boundary
mario.x -= 0.5
if keys[pygame.K_RIGHT]:
if mario.x < screen.get_width() - mario.width: # Check if Mario is within the right boundary
mario.x += 0.5
mario.y_velocity += 0.003
mario.y += mario.y_velocity
for floor in floors:
if mario.check_collision(floor):
mario.handle_collision(floor)
if mario.x < 0: # Check if Mario is within the left boundary
mario.x = 0
elif mario.x > screen.get_width() - mario.width: # Check if Mario is within the right boundary
mario.x = screen.get_width() - mario.width
if mario.y < 0: # Check if Mario is within the top boundary
mario.y = 0
elif mario.y > screen.get_height() - mario.height: # Check if Mario is within the bottom boundary
mario.y = screen.get_height() - mario.height
screen.fill((0, 0, 0))
mario.draw(screen)
for floor in floors:
floor.draw(screen)
pygame.display.flip()
# Clean up before exiting
pygame.quit() When the player falls, it teleports to the right edge of the platform. How do I fix this?
The only stupid person in the world, is the person that doesn't ask questions.
-Someone smart
Posts: 6,799
Threads: 20
Joined: Feb 2020
Once you land on the floor you start doing this:
def handle_collision(self, floor):
self.y = floor.y - self.height
self.y_velocity = 0
self.jumping = False
if (
self.x < floor.x + floor.width and self.x > floor.x
): # Check if collision is occurring on the left edge
if self.x < screen.get_width() - self.width:
self.x = floor.x + floor.width
else:
self.x = floor.x + floor.width This forces you to go to floor.x + floor.width
Posts: 26
Threads: 7
Joined: Sep 2022
Jan-25-2023, 10:56 AM
(This post was last modified: Jan-25-2023, 10:56 AM by BliepMonster.)
(Jan-24-2023, 09:59 PM)deanhystad Wrote: Once you land on the floor you start doing this:
def handle_collision(self, floor):
self.y = floor.y - self.height
self.y_velocity = 0
self.jumping = False
if (
self.x < floor.x + floor.width and self.x > floor.x
): # Check if collision is occurring on the left edge
if self.x < screen.get_width() - self.width:
self.x = floor.x + floor.width
else:
self.x = floor.x + floor.width This forces you to go to floor.x + floor.width And how do I solve this? I can remove it, but then it doesn't check the y-coordinates.
The only stupid person in the world, is the person that doesn't ask questions.
-Someone smart
Posts: 6,799
Threads: 20
Joined: Feb 2020
You do the same thing if the condition is true or false, that is obviously wrong.
Posts: 26
Threads: 7
Joined: Sep 2022
nevermind I solved the problem
The only stupid person in the world, is the person that doesn't ask questions.
-Someone smart
Posts: 6,799
Threads: 20
Joined: Feb 2020
Jan-26-2023, 10:12 PM
(This post was last modified: Jan-26-2023, 10:12 PM by deanhystad.)
You should post your solution so others can benefit.
Pygame has lots of support for detecting collisions between things like players and platforms. In the code below I made the player and the platform Sprites This lets me use one line of code to check for a collision between the player and all the platforms: collision = pygame.sprite.spritecollide(self, objects, False).
import pygame
GRAVITY = 0.1
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
MAP = ( # Walls, floor and assorted barriers
(-20, -100, 20, SCREEN_HEIGHT + 100),
(SCREEN_WIDTH, -100, 20, SCREEN_HEIGHT + 100),
(0, SCREEN_HEIGHT, SCREEN_WIDTH, 20),
(500, SCREEN_HEIGHT - 100, 20, 100),
(0, 100), (300, 200), (500, 300),
(200, 400), (400, 500), (500, 600),
)
class EnhancedSprite(pygame.sprite.Sprite):
"""Add Rect x, y, right and bottom properties to sprite. Add draw method"""
def __init__(self, image):
super().__init__()
self.image = image
self.rect = image.get_rect()
self._x = 0
self._y = 0
def draw(self, surface):
surface.blit(self.image, self.rect)
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = value
self.rect.x = value
@property
def y(self):
return self._y
@y.setter
def y(self, value):
self._y = value
self.rect.y = value
@property
def right(self):
return self._x + self.rect.width
@right.setter
def right(self, value):
self._x = value - self.rect.width
self.rect.x = self._x
@property
def bottom(self):
return self._y + self.rect.height
@bottom.setter
def bottom(self, value):
self._y = value - self.rect.height
self.rect.y = self._y
class Barrier(EnhancedSprite):
"""A stationary sprite for platform game"""
def __init__(self, x, y, wide=200, high=20, color="green"):
image = pygame.Surface((wide, high))
image.fill(color)
super().__init__(image)
self.x = x
self.y = y
class Ball(EnhancedSprite):
"""A player for the platform game"""
def __init__(self, radius=15, speed=3, jump=6, color="red"):
image = pygame.Surface((radius * 2, radius * 2))
image.fill("black")
pygame.draw.circle(image, color, (radius, radius), radius)
super().__init__(image)
self.speed = speed
self.jump_speed = jump
self.jumping = False
self.x_velocity = 0
self.y_velocity = 0
def jump(self):
"""Jump up in the air if standing on ground or platform"""
if not self.jumping:
self.y_velocity = -self.jump_speed
self.jumping = True
def move(self, direction, barriers=None):
"""Move player, detect collisions with barriers"""
# Move in x direction
if not self.jumping:
# No changing direction while in the air.
speed = self.speed * direction
if speed > self.x_velocity:
self.x_velocity = min(speed, self.x_velocity + GRAVITY)
else:
self.x_velocity = max(speed, self.x_velocity - GRAVITY)
self.x += self.x_velocity
if barriers:
collision = pygame.sprite.spritecollide(self, barriers, False)
if collision: # Bumped into something.
collision = collision[0]
if self.x_velocity > 0:
self.right = collision.x
else:
self.x = collision.right
self.x_velocity = -self.x_velocity / 2
# Move in y direciton
self.y_velocity += GRAVITY
self.y += self.y_velocity
if barriers:
collision = pygame.sprite.spritecollide(self, barriers, False)
if collision: # Bumped into something
collision = collision[0]
if self.y_velocity >= 0:
# Fell onto platform
self.bottom = collision.y
self.jumping = False
else:
# Jumped up into platform
self.y = collision.bottom + 1
self.y_velocity = 0
def main():
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
clock = pygame.time.Clock()
player = Ball()
barriers = pygame.sprite.Group()
for barrier in MAP:
barriers.add(Barrier(*barrier))
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
player.jump()
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player.move(-1, barriers)
elif keys[pygame.K_RIGHT]:
player.move(1, barriers)
else:
player.move(0, barriers)
clock.tick(100)
screen.fill("black")
player.draw(screen)
barriers.draw(screen)
pygame.display.flip()
pygame.quit()
main() I really like how pygame Rect works. Rect.right = Rect.y + Rect.width. Rect.bottom = Rect.y + Rect.height. I made a new Sprite class that can act like a Rect. It makes the collision correction code easier to write and understand.
I added sliding, which acts like jumping. When move keys are pressed the player accelerates instead of starting and stopping at full speed. I also added a bounce when the running into something.
I removed special code for stopping at the edges or the bottom of the screen. I get the same behavior by making side and bottom platforms that are just off the edge of the screen.
|