Hello!
I am trying to make an autoscroller and I want the player to always move at the same speed on the x axis but whenever it hits an incline it slows down. I’ve been stuck on this for a bit, thanks for reading!
Could you modify the velocity based on the normal value of the floor?
extends CharacterBody2D
const SPEED = 700
const JUMP_VELOCITY = -400.0
func _ready() -> void:
floor_constant_speed = true
floor_block_on_wall = false
func _physics_process(delta: float) -> void:
# Add the gravity.
if not is_on_floor():
velocity += get_gravity() * delta
# Handle jump.
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
#Your old code:
# position.x += SPEED * delta
#New code for constant velocity
#Set constant speed in x direction
velocity.x = SPEED
#scale the constant speed based on the angle of the surface
#if you want, you could check if the floor normal is not Vector2.UP
#and set a constant slope velocity
if is_on_floor():
velocity.x *= get_floor_normal().x
elif is_on_wall():
velocity.x *= get_wall_normal().x
move_and_slide()
print(get_real_velocity())
Hey!
Thanks so much for the reply. This is much better than before, I can get decently close to the same speed using this idea, I’d still like to get a more exact constant speed but this was very helpful
A more exact constant speed, you say… Would this help?
extends CharacterBody2D
const SPEED = 700
const JUMP_VELOCITY = -400.0
#new constants
const SLOPE_VELOCITY = 500
func _ready() -> void:
floor_constant_speed = true
floor_block_on_wall = false
func _physics_process(delta: float) -> void:
# Add the gravity.
if not is_on_floor():
velocity += get_gravity() * delta
# Handle jump.
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
#Set constant speed in x direction
velocity.x = SPEED
#Get the normal value of the current surface
var normal: Vector2
if is_on_floor():
normal = get_floor_normal()
elif is_on_wall():
normal = get_wall_normal()
#If not on a perfectly flat floor
#Set the sideways velocity
#Might need to use is_equal_approx() instead of == for precision
if not normal == Vector2.UP:
velocity.x = SLOPE_VELOCITY
move_and_slide()
print(get_real_velocity())
If you want, you can even compare the angles of the normal value to have a different speed for going up slopes versus going down slopes.
PS. As with the previous code, this is untested and may not work. If it does not work, let me know and I will try to help fix it.
This does work but it’s the same as the previous code where it’s not quite constant. The velocity seems to bounce around a little when on inclines, but I understand it’s likely inconsequential outside of the one frame where it drops 30 velocity shown in the output below. Thanks for the continued help with this
extends CharacterBody2D
const SPEED = 700
const JUMP_VELOCITY = -400.0
const SLOPE_VELOCITY = 762
func _ready() -> void:
floor_constant_speed = true
floor_block_on_wall = false
func _physics_process(delta: float) -> void:
# Add the gravity.
if not is_on_floor():
velocity += get_gravity() * delta
# Handle jump.
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
velocity.x = SPEED
var normal: Vector2
if is_on_floor():
normal = get_floor_normal()
elif is_on_wall():
normal = get_wall_normal()
if not normal == Vector2.UP:
velocity.x = SLOPE_VELOCITY
move_and_slide()
print(get_real_velocity())
I think this is because detection of the slope is a frame late (it uses the collision data from the last frame). I think you could use a well-placed raycast to check if the floor in front of the player is a slope. Maybe something similar to this?
extends CharacterBody2D
#Path to a raycast node pointed a little
#down and in the direction of movement
@onready var raycast:Raycast2D = $raycast
const SPEED = 700
const JUMP_VELOCITY = -400.0
const SLOPE_VELOCITY = 762
func _ready() -> void:
floor_constant_speed = true
floor_block_on_wall = false
func _physics_process(delta: float) -> void:
# Add the gravity.
if not is_on_floor():
velocity += get_gravity() * delta
# Handle jump.
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
velocity.x = SPEED
var player_normal: Vector2
if is_on_floor():
player_normal = get_floor_normal()
elif is_on_wall():
player_normal = get_wall_normal()
#Set default to not trigger the if statement
var raycast_normal:Vector2 = Vector2.UP
#Get normal value of the raycast collision
if raycast:
if raycast.is_colliding():
raycast_normal = raycast.get_collision_normal()
#Check floor normal and raycast normal
if (not player_normal == Vector2.UP) or\
(not raycast_normal == Vector2.UP):
velocity.x = SLOPE_VELOCITY
move_and_slide()
print(get_real_velocity())
Hm I’ve tried placing the raycast in a variety of ways but it seems to always be 662 or 719 velocity on the first frame it touches the slope, I’ve also tried having the slopes not be collision bodies and just have the player moved up when on them which does fix the speed issue but it kinda just bounces the player up along the slope.
extends CharacterBody2D
#Path to a raycast node pointed a little
#down and in the direction of movement
@onready var raycast:RayCast2D = $RayCast2D
const SPEED = 700
const JUMP_VELOCITY = -400.0
const SLOPE_VELOCITY = 762
func _ready() -> void:
floor_constant_speed = true
floor_block_on_wall = false
func _physics_process(delta: float) -> void:
# Add the gravity.
if not is_on_floor():
velocity += get_gravity() * delta
# Handle jump.
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
velocity.x = SPEED
var player_normal: Vector2
if is_on_floor():
player_normal = get_floor_normal()
elif is_on_wall():
player_normal = get_wall_normal()
#Set default to not trigger the if statement
var raycast_normal:Vector2 = Vector2.UP
#Get normal value of the raycast collision
if raycast:
if raycast.is_colliding():
raycast_normal = raycast.get_collision_normal()
#Check floor normal and raycast normal
if ((not player_normal == Vector2.UP) or\
(not raycast_normal == Vector2.UP)) and is_on_floor():
velocity.x = SLOPE_VELOCITY
move_and_slide()
print(get_real_velocity())
Moving player up version
extends CharacterBody2D
#Path to a raycast node pointed a little
#down and in the direction of movement
@onready var raycast:RayCast2D = $RayCast2D
const SPEED = 700
const JUMP_VELOCITY = -400.0
const SLOPE_VELOCITY = 762
func _ready() -> void:
floor_constant_speed = true
floor_block_on_wall = false
func _physics_process(delta: float) -> void:
# Add the gravity.
if not is_on_floor():
velocity += get_gravity() * delta
# Handle jump.
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
velocity.x = SPEED
if raycast.is_colliding():
velocity.y -= 50
move_and_slide()
print(get_real_velocity())