player just randomly teleporting to the edge of a platform in pygame - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: Game Development (https://python-forum.io/forum-11.html) +--- Thread: player just randomly teleporting to the edge of a platform in pygame (/thread-39278.html) |
player just randomly teleporting to the edge of a platform in pygame - BliepMonster - Jan-24-2023 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? RE: player just randomly teleporting to the edge of a platform in pygame - deanhystad - Jan-24-2023 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.widthThis forces you to go to floor.x + floor.width RE: player just randomly teleporting to the edge of a platform in pygame - BliepMonster - Jan-25-2023 (Jan-24-2023, 09:59 PM)deanhystad Wrote: Once you land on the floor you start doing this:And how do I solve this? I can remove it, but then it doesn't check the y-coordinates. RE: player just randomly teleporting to the edge of a platform in pygame - deanhystad - Jan-25-2023 You do the same thing if the condition is true or false, that is obviously wrong. RE: player just randomly teleporting to the edge of a platform in pygame - BliepMonster - Jan-25-2023 nevermind I solved the problem RE: player just randomly teleporting to the edge of a platform in pygame - deanhystad - Jan-26-2023 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. |