I'm trying to get my 2D platforming character moving left and right without him involuntarily leaving out of a slanted ground until he goes off a ledge or a jump button is pressed. All that while determining if he's colliding to a floor using two RayCast2D nodes with each placed on each side of the playable character, and a rectangle-shaped CollisionShape2D for colliding with any ground. So far, I've done it successfully, except it has some unintended behaviors...:
- The character would hop when moving on a joint that separates two different downward slopes, despite the collision mask clearly shows that both ends share the same Y coordinate
- When my character slows down quickly enough while escalating a slope, he hops on his own
- When my character lands on a slope, the character would slide downwards for a bit before entirely stopping. I don't want the vertical movement affecting the left & right velocity upon landing in a slanted ground.
How do I solve these problems? If these can't absolutely be fixed with the current setup, feel free to provide alternatives that can get the character sticking on the ground until he leaves off ledge or a jump input is triggered.
Picture of the Node tree:
Here's Level00.gd for altering the playable character's position using x and y motion calculated from Player.gd:
extends Node2D
func _physics_process(_delta):
$Player.position.x += $Player.motion.x
$Player.position.y += $Player.motion.y
And Player.gd for all player interactions with the environment:
extends KinematicBody2D
const TARGET_FPS = 60
const FRICTION = 3
const AIR_RESISTANCE = 0
const GRAVITY = 0.2
var JUMP_FORCE
var OFFLEDGE_TIMER = 6
var ACCELERATION
var MAX_SPEED = 3
var SPEED_MODIFIER = 1
var JUMP_MODIFIER = 1
var ACCELERATION_MODIFIER = 1
var motion = Vector2.ZERO
var motion_backup = Vector2.ZERO
var motion_noslide = Vector2.ZERO
var snap = Vector2.DOWN
onready var sprite = $Star
##onready var animationPlayer = $AnimationPlayer
##PHYSICS##
func _physics_process(delta):
var x_input = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
##GENERAL MOVEMENT
##CHECKS FOR SPEED MODIFIER (SUCH AS SUPERSPEED POWERUP HERE)
if Input.is_action_pressed("ui_superspeed"):
SPEED_MODIFIER = 1.5
JUMP_MODIFIER = 1.1
ACCELERATION_MODIFIER = 1.25
else:
SPEED_MODIFIER = 1
ACCELERATION_MODIFIER = 1
JUMP_MODIFIER = 1
##CHECKS FOR ANY MOVEMENT INPUT
if x_input != 0:
##IF THE RUN BUTTON IS HELD, CHARACTER WILL ACCELERATE AND MOVE QUICKER ALONGSIDE JUMPING HIGHER
if Input.is_action_pressed("ui_speed"):
##animationPlayer.play("Run")
ACCELERATION = ACCELERATION_MODIFIER * 0.1
MAX_SPEED = SPEED_MODIFIER * 3
JUMP_FORCE = JUMP_MODIFIER * 6.25
else:
##animationPlayer.play("Walk")
ACCELERATION = ACCELERATION_MODIFIER * 0.1
if MAX_SPEED > SPEED_MODIFIER * 2:
if $RayCast2D_Left.is_colliding() || $RayCast2D_Right.is_colliding():
MAX_SPEED -= SPEED_MODIFIER * 0.05
else:
MAX_SPEED = SPEED_MODIFIER * 2
JUMP_FORCE = JUMP_MODIFIER * 5.5
##ACCELERATING CHARACTER
motion.x += x_input * (ACCELERATION_MODIFIER * ACCELERATION) * delta * TARGET_FPS
motion.x = clamp(motion.x, -(SPEED_MODIFIER * MAX_SPEED), (SPEED_MODIFIER * MAX_SPEED))
motion_backup.x = motion.x
motion_noslide.x = motion.x
$Star.flip_h = x_input < 0
else:
JUMP_FORCE = JUMP_MODIFIER * 5
##animationPlayer.play("Stand")
##GRAVITY INTERACTION
##PREVENTING THE CHARACTER FROM FALLING TOO FAST, WHERE motion_noslide DOESN'T CALCULATE motion.y
if motion.y <= 5:
motion.y += GRAVITY * delta * TARGET_FPS
motion_backup.y = motion.y
##IF THE CHARACTER HITS ON GROUND
if $RayCast2D_Left.is_colliding() || $RayCast2D_Right.is_colliding():
OFFLEDGE_TIMER = 6
snap = Vector2.DOWN
if x_input == 0:
motion.x = lerp(motion.x, 0, FRICTION * delta)
motion_backup.x = motion.x
motion_noslide.x = motion.x
##MAKING CHARACTER TO STOP ONCE THE motion.x value GETS LOW-ENOUGH MOMENTUM
if motion.x < 0.075 && (motion.x) > -0.075:
motion.x = 0
motion_backup.x = 0
motion_noslide.x = 0
#IF JUMP BUTTON IS PRESSED WHILE ON GROUND, CHARACTER WILL JUMP ACCORDING TO HOW LONG IT IS HELD
if Input.is_action_just_pressed("ui_jump"):
motion.y = -(JUMP_MODIFIER * JUMP_FORCE)
motion_backup.y = motion.y
motion_noslide.y = motion.y
else:
##animationPlayer.play("Jump")
OFFLEDGE_TIMER += -1
snap = Vector2.ZERO
if Input.is_action_just_released("ui_jump"):
OFFLEDGE_TIMER = 0
if motion.y < -(JUMP_MODIFIER * (JUMP_FORCE/3)):
motion.y = -(JUMP_MODIFIER * (JUMP_FORCE/3))
motion_backup.y = motion.y
motion_noslide.y = motion.y
if x_input == 0:
motion.x = lerp(motion.x, 0, AIR_RESISTANCE * delta)
motion_backup.x = motion.x
motion_noslide.x = motion.x
if OFFLEDGE_TIMER > 0 and Input.is_action_just_pressed("ui_jump"):
motion.y = -(JUMP_MODIFIER * JUMP_FORCE)
motion_backup.y = motion.y
motion_noslide.y = motion.y
OFFLEDGE_TIMER = 0
if snap.y == 1:
motion = move_and_slide_with_snap(motion_noslide, snap, Vector2.UP, true, 4, deg2rad(52))
motion_noslide.y = motion.y
motion_backup = motion_noslide
else:
motion = move_and_slide(motion_backup, Vector2.UP)
motion_backup = motion
motion_noslide.y = motion_backup.y