Climb on moving walls?

Godot Version

4.2.1 stable

Question

Hey y’all, so the feature I’m having trouble with is wall climbing. It currently works by setting velocity according to if certain conditions are met and raycasts are colliding but this completely falls apart when I try to climb on a moving wall. For example if the wall is moving towards you it works fine but if it is moving away the character will just fall off obviously because there is no logic in place for this case. Is there a better way to have the character stick to walls as a whole instead of arbitrarily setting velocity, or should I just amend the current way to include this edge case, but then if I do keep it this way and just add to it I’m afraid that certain features won’t work like how Godot adds the velocity of the moving platform you’re on when you jump off. Any suggestions are welcome thank you all

I would create an Area2d, call it “ClimbArea” for instance. Add a signal to detect whevener the player has touched it. Place as many as you want around the map.

In the player set a var to store the current_climb_area. When the area detects the player, set that node as value for current_climb_area.

In the player script, if current_climb_area is not null, then update the player position with climbArea position.

There are many tweaks to make it look fine (like a release button, take into account player size…) but is it a initial posible solution.

This sounds good because I would be able to keep the player inside the area2d even if the wall is moving away except I forgot to mention I’m trying to avoid solutions which involve editing the map itself as I will have randomly generated terrain so I want a solution which can be more flexible

You can use the same approach. Your player has a var attached_to: Node2D, when you ray cast “wall detector” collides, store the result of get_collider() in attached_to.

Then the same, if attached_to not null, player position equals attached_to position.

This is very close, I just had some time to try the code and I found that I tried something very similar to what you suggested but I had gotten stuck and I can’t figure it out. I keep getting errors for position on index ‘nil’. I tried to cast the body variable as things such as PhysicsBody2D, CollisoinObject2D, Node2D, but I’m not sure what to do.

var body : CollisionObject2D
if MiddleLeft.is_colliding():
	body = MiddleLeft.get_collider()
elif MiddleRight.is_colliding():
	body = MiddleRight.get_collider()
var prev_pos = body.position
var dir = prev_pos - body.position
if dir != Vector2.ZERO:
	Player.position += dir

What you need is the collision point so you know where to stick your player. Also you were asuming body has always value.

Small correction to your code. I renamed body to climb_target to be more semantic. If collides, stores the collision point and assign that point to the player every frame.

var climb_target: Vector2

func _physics_process(delta):
	
	if MiddleLeft.is_colliding():
		climb_target = MiddleLeft.get_collision_point()
	elif MiddleRight.is_colliding():
		climb_target = MiddleRight.get_collision_point()

	if climb_target:
		Player.position = climb_target