0 votes

Hi,
I used walking speed acceleration, friction and variable jump height (the longer the jump button is pressed, the higher the jump), which worked fine as long it is on even ground, but causes problems on slopes:

  • the character could barely move uphills cause of the small starting speed when using acceleration. I used something like
    "motion.x = min(motion.x+ACCELERATION, MAXSPEEDWALK)"
  • due to the friction the character was sliding way too much after stoping movement. I used "motion.x = lerp(motion.x, 0, 0.2)" for it. Adjusting the weight works, but then you can not notice it on even ground (now I use a fixed value instead).
  • jumping works not as intended, when running there is barely a jump at all. Works fine on even ground.

So is there a way to tell the player that he/she is on a slope, like with using "isonfloor()"?
I have removed friction and acceleration for movement on ground, because I could not get it work on slopes (code I used is shown above)
But the problem with jumping still exists, jumping on slopes while running does barely work, there is only a mini-jump.

I hope this are not too much question and there is a solution to fix it, thanks so much!

Part of the code, I can not show all because I get an error with "Maximum length is 8000 characters":

const UP = Vector2(0, -1)
const GRAVITY = 20
const ACCEL = 15
const ACCELFLY = 15
const MAXSPEEDWALK = 100
const MAXSPEEDRUN = 200
const JUMP = 50
const HIGHJUMP = 350
var motion = Vector2()
var wait = 0


func _physics_process(delta):


# RUN STATE ---------------------------------------------------------------
elif states == run:

    if Input.is_action_pressed("ui_right") and not Input.is_action_pressed("ui_left"):
        if Input.is_action_pressed("ui_cancel"):

            motion.x = MAXSPEEDRUN
            $Sprite.flip_h = true
            $Sprite.play("run")
            if Input.is_action_pressed("ui_select"):
                states = runjump

        else:
            states = endrun

    elif Input.is_action_pressed("ui_left") and not Input.is_action_pressed("ui_right"):
        if Input.is_action_pressed("ui_cancel"):

            motion.x = -MAXSPEEDRUN
            $Sprite.flip_h = false
            $Sprite.play("run")
            if Input.is_action_pressed("ui_select"):
                states = runjump

        else: 
            states = endrun

    if Input.is_action_just_released("ui_left") or Input.is_action_just_released("ui_right"):
        states = endrun

# JUMP ----------------------------------------------------------------------
elif states == jump:
    if Input.is_action_pressed('ui_select'):
        motion.y = max (motion.y-JUMP, -HIGHJUMP)
        if motion.y == -HIGHJUMP:
            states = fall
    else: states = fall

    if is_on_ceiling():
        states = fall

    if motion.y < 0:
        $Sprite.play("jump")

    if motion.y > 0:
        states = fall

    if Input.is_action_pressed("ui_right") and not Input.is_action_pressed("ui_left"):
        $Sprite.flip_h = true
        if is_on_floor():
            motion.x = MAXSPEEDWALK
        else:
            motion.x = min(motion.x+ACCELFLY, MAXSPEEDWALK)

    elif Input.is_action_pressed("ui_left") and not Input.is_action_pressed("ui_right"):
        $Sprite.flip_h = false
        if is_on_floor():
            motion.x = -MAXSPEEDWALK
        else:
            motion.x = max(motion.x-ACCELFLY, -MAXSPEEDWALK) 
    else:
        motion.x = lerp(motion.x, 0, 0.05)

# RUN JUMP ----------------------------------------------------------------------
elif states == runjump:
    if Input.is_action_pressed('ui_select'):
        motion.y = max (motion.y-JUMP, -HIGHJUMP)
        if motion.y == -HIGHJUMP:
            states = runfall
    else: states = runfall

    if is_on_ceiling():
        states = fall

    if motion.y < 0:
        $Sprite.play("startrunjump")

    if motion.y > 0:
        states = runfall

    if Input.is_action_pressed("ui_right") and not Input.is_action_pressed("ui_left"):
        $Sprite.flip_h = true
        if is_on_floor():
            motion.x = MAXSPEEDRUN
        else:
            motion.x = min(motion.x+ACCELFLY, MAXSPEEDRUN)

    elif Input.is_action_pressed("ui_left") and not Input.is_action_pressed("ui_right"):
        $Sprite.flip_h = false
        if is_on_floor():
            motion.x = -MAXSPEEDRUN
        else:
            motion.x = max(motion.x-ACCELFLY, -MAXSPEEDRUN)
    else:
        motion.x = lerp(motion.x, 0, 0.05)


# FALL ------------------------------------------------------------
elif states == fall:
    if motion.y < 0:
        $Sprite.play("jump")

    if motion.y > 0:
        $Sprite.play("fall")

    if is_on_floor():
        states = hitground

    if Input.is_action_pressed("ui_right") and not Input.is_action_pressed("ui_left"):
        motion.x = min(motion.x+ACCELFLY, MAXSPEEDWALK)
        $Sprite.flip_h = true

    elif Input.is_action_pressed("ui_left") and not Input.is_action_pressed("ui_right"):
        motion.x = max(motion.x-ACCELFLY, -MAXSPEEDWALK)
        $Sprite.flip_h = false
    else:
        motion.x = lerp(motion.x, 0, 0.05)



motion.y += GRAVITY
motion = move_and_slide(motion, UP, 5, 4, deg2rad(50))
in Engine by (23 points)

1 Answer

+1 vote

This function should help to determine whether the player is on a "slope" vs a "floor".

const UP = Vector2(0, -1)
const DEFAULT_MAX_FLOOR_ANGLE = deg2rad(5)

# This function assumes that you are already using move_and_slide, and that a "slope" is a subtype of a "floor", so if is_on_slope() is true, then is_on_floor() must also be true.
# If there are simultaneous collisions with both a "floor" and a "slope", then this returns false.
func is_on_slope(max_floor_angle = DEFAULT_MAX_FLOOR_ANGLE):
    if is_on_floor():
        for i in range(get_slide_count()):
            var collision = get_slide_collision(i)
            # Is this a "floor" collision?
            if collision.normal.angle_to(UP) <= max_floor_angle:
                return false
        # We didn't find a "floor" collision, but is_on_floor() is true, so there must be a "slope" collision.
        return true
    # is_on_floor is false, so there cannot be a "slope" collision.
    return false
by (23 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.