Python Forum
player just randomly teleporting to the edge of a platform in pygame
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
player just randomly teleporting to the edge of a platform in pygame
#1
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
Reply
#2
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
Reply
#3
(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
Reply
#4
You do the same thing if the condition is true or false, that is obviously wrong.
Reply
#5
nevermind I solved the problem
The only stupid person in the world, is the person that doesn't ask questions.
-Someone smart
Reply
#6
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.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [PyGame] Sprites just randomly appear and dissapear in my pygame.sprite.GoupeSingle trueShadoWrr 2 1,983 Feb-13-2023, 09:34 AM
Last Post: Vadanane
  [PyGame] Players not falling from the platform, and some other errors. urmom33 1 1,617 Jan-23-2023, 10:28 PM
Last Post: deanhystad
  [PyGame] pygame, help with making a function to detect collision between player and enemy. Kris1996 3 3,331 Mar-07-2020, 12:32 PM
Last Post: Kris1996
  Randomly selecting sprite from group? michael1789 5 4,116 Nov-14-2019, 10:43 PM
Last Post: michael1789
  [PyGame] Rectangle keeps teleporting? keyfive 1 3,207 Jun-27-2018, 11:49 PM
Last Post: sonnekrieger7
  [PyGame] move randomly sprites reutB 4 8,234 Mar-29-2017, 01:12 PM
Last Post: metulburr

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020