user1758231
user1758231

Reputation: 1001

pygame -- wall jumping

Ok so I have my code up and running, right now when the player collides with the wall while the user is holding right or left the player will slowly slide down the wall, if the player releases the direction (left or right) the player continues to fall normally.

What I want to do it make it so that when the player hits the wall he "sticks" to it, meaning he still slides down and will slide down it until he hits the ground (the user doesnt have to hold a direction) or the user can jump off the wall. (Think super meat boy for those who have played it or seen gameplay or megaman). Can anyone suggest a good way to approach this?

import pygame, time
from pygame import *


WIN_WIDTH = 800
WIN_HEIGHT = 640
HALF_WIDTH = int(WIN_WIDTH / 2)
HALF_HEIGHT = int(WIN_HEIGHT / 2)

DISPLAY = (WIN_WIDTH, WIN_HEIGHT)
DEPTH = 32
FLAGS = 0

def main():
    pygame.init()
    screen = pygame.display.set_mode(DISPLAY, FLAGS, DEPTH)
    pygame.display.set_caption("Use arrows to move!")
    timer = pygame.time.Clock()

    up = down = left = right = space = False
    bg = Surface((32,32))
    bg.convert()
    bg.fill(Color("#000000"))
    entities = pygame.sprite.Group()
    player = Player(32, 32)
    platforms = []

    space_num = 0

    x = y = 0
    level = [
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "P                              E           P",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "P                           PPPPPP         P",
        "P                                          P",
        "P                                          P",
        "PPPPP                                      P",
        "P                                          P",
        "P         PPPPPPP                          P",
        "P                                          P",
        "P                     PPPPPP               P",
        "P                                          P",
        "P   PPPPPPPPPPP                            P",
        "P                                          P",
        "P                 PPPPPPPPPPP              P",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "P                                          P",
        "PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP",]
    # build the level
    for row in level:
        for col in row:
            if col == "P":
                p = Platform(x, y)
                platforms.append(p)
                entities.add(p)
            if col == "E":
                e = ExitBlock(x, y)
                platforms.append(e)
                entities.add(e)
            x += 32
        y += 32
        x = 0

    total_level_width = len(level[0]) * 32
    total_level_height = len(level) * 32
    camera = Camera(complex_camera, total_level_width, total_level_height)
    entities.add(player)

    while 1:
        timer.tick(60)

        for e in pygame.event.get():
            if e.type == QUIT: raise SystemExit, "QUIT"
            if e.type == KEYDOWN and e.key == K_ESCAPE:
                raise SystemExit, "ESCAPE"
            if e.type == KEYDOWN and e.key == K_UP:
                up = True
            if e.type == KEYDOWN and e.key == K_DOWN:
                down = True
            if e.type == KEYDOWN and e.key == K_LEFT:
                left = True
            if e.type == KEYDOWN and e.key == K_RIGHT:
                right = True
            if e.type == KEYDOWN and e.key == K_SPACE:
                if space_num < 6:
                    space = True
                    space_num += 1

            if e.type == KEYUP and e.key == K_UP:
                up = False
            if e.type == KEYUP and e.key == K_DOWN:
                down = False
            if e.type == KEYUP and e.key == K_LEFT:
                left = False
            if e.type == KEYUP and e.key == K_RIGHT:
                right = False
            if e.type == KEYUP and e.key == K_SPACE:
                space = False

        # draw background
        for y in range(20):
            for x in range(25):
                screen.blit(bg, (x * 32, y * 32))

        camera.update(player)

        # update player, draw everything else
        player.update(up, down, left, right, platforms, space)
        for e in entities:
            screen.blit(e.image, camera.apply(e))
        pygame.display.update()

class Camera(object):
    def __init__(self, camera_func, width, height):
        self.camera_func = camera_func
        self.state = Rect(0, 0, width, height)

    def apply(self, target):
        return target.rect.move(self.state.topleft)

    def update(self, target):
        self.state = self.camera_func(self.state, target.rect)

#def simple_camera(camera, target_rect):
#    l, t, _, _ = target_rect
#    _, _, w, h = camera
#    return Rect(-l+HALF_WIDTH, -t+HALF_HEIGHT, w, h)

def complex_camera(camera, target_rect):
    l, t, _, _ = target_rect
    _, _, w, h = camera
    l, t, _, _ = -l + HALF_WIDTH, -t+HALF_HEIGHT, w, h

    l = min(0, l)                           # stop scrolling left
    l = max(-(camera.width-WIN_WIDTH), l)   # stop scrolling right
    t = max(-(camera.height-WIN_HEIGHT), t) # stop scrolling bottom

    return Rect(l, t, w, h)

class Entity(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)

class Player(Entity):
    def __init__(self, x, y):
        Entity.__init__(self)
        self.xvel = 0
        self.yvel = 0
        self.onGround = False
        self.onWall = False
        self.image = Surface((32,32))
        self.image.fill(Color("#0000FF"))
        self.image.convert()
        self.rect = Rect(400, 400, 32, 32)

    def update(self, up, down, left, right, platforms, space):
        if up:
            if self.onGround: self.yvel -= 10 # only jump if on the ground
        if down:
            pass
        if left:
            self.xvel = -8
        if right:
            self.xvel = 8
        if not self.onGround:
            self.yvel += 0.3 # only accelerate with gravity if in the air
            if self.yvel > 40: self.yvel = 40 # max falling speed
        if not(left or right):
            self.xvel = 0


        self.rect.left += self.xvel # increment in x direction
        self.collide(self.xvel, 0, platforms) # do x-axis
        self.rect.top += self.yvel # increment in y direction
        self.onGround = False; # assuming we're in the air
        self.onWall = False
        self.collide(0, self.yvel, platforms) # do y-axis collisions


    def collide(self, xvel, yvel, platforms):
        for p in platforms:
            if pygame.sprite.collide_rect(self, p):
                if isinstance(p, ExitBlock):
                    pygame.event.post(pygame.event.Event(QUIT))

                if xvel > 0:
                    self.rect.right = p.rect.left
                    self.onWall = True

                if xvel < 0:
                    self.rect.left = p.rect.right
                    self.onWall = True

                if yvel > 0:
                    self.rect.bottom = p.rect.top
                    self.onGround = True
                    self.onWall = False
                    self.yvel = 0
                if yvel < 0: self.rect.top = p.rect.bottom

                if self.onWall:
                    self.yvel = 3


class Platform(Entity):
    def __init__(self, x, y):
        Entity.__init__(self)
        self.image = Surface((32, 32))
        self.image.convert()
        self.image.fill(Color("#F0FFFF"))
        self.rect = Rect(x, y, 32, 32)

    def update(self):
        pass

class ExitBlock(Platform):
    def __init__(self, x, y):
        Platform.__init__(self, x, y)
        self.image.fill(Color("#00ff00"))

if __name__ == "__main__":
    main()

Upvotes: 2

Views: 1660

Answers (2)

Southpaw Hare
Southpaw Hare

Reputation: 1593

Giving the player class a boolean that is set when they touch or stop touching a wall is probably as complicated as you need to get. Just watch out for the typical issues in keeping that boolean in-sync with what is actually going on in the game world: you should check for changing this value in the same place every update cycle, most likely after character movement, and no where else. Additionally, if walls or terrain itself can move, you have to take that into consideration.

Upvotes: 1

yasith
yasith

Reputation: 9511

This is just a rough idea, based on some code I have written.

onCollision(wall, player):
  player.stuck = true
  player.wall_jump = true

onCollision(floor, player):
  player.stuck = false
  player.wall_jump = false # If you slide to the bottom of the floor, you can't walljump

onInput():

  player = getPlayer()
  if jump_key.state and player.wall_jump: # assuming you set jump_key.state to true, when jump key is pressed
    # set player direction to opposite
    # set player's horizontal and vertical velocity
    player.stuck = false;

Upvotes: 0

Related Questions