|
|
|
 |
Attention |
Topic was automatically imported from the old Question2Answer platform. |
 |
Asked By |
JohnMaddenGodot |
I have an enemy that crawls along walls and ceilings. When it hits a corner, an Area2D on its side detects it, changes its gravity to push it against the wall, changes its speed to move along the wall, and rotates itself. When it steps off a corner, an Area2D on its bottom corner detects that it has left a tile, changes its gravity to push it against the wall, changes it speed to move along the wall, and rotates itself. It mostly works fine, however sometimes when I test it, it will hit a wall/leave a corner and not rotate itself, and either keep pushing against the wall or fall backwards if it has left a corner because of gravity not changing. But sometimes when I test it without changing anything, it behaves as it should. Additionally, adding/removing a tile on its path will make it behave as it should. What could be causing this?
I’ve done some more testing, it appears to only happen when it is traversing a L-shaped segment that is two tiles on each side. That is, if it turns onto a platform that is two tiles long, and then traverses up a wall that is two tiles long, when it turns at the top of the platform it will fall back down to the bottom, as it appears that gravity has switched before its hitbox reached the next platform.
I seem to have fixed it, made it check for movement speed to be greater/less than or equal to 0 instead of just greater/less than.
JohnMaddenGodot | 2022-05-30 21:38
|
|
|
 |
Reply From: |
BigTuna675 |
Hi there, it’s going to be a little tough to help without seeing some more details about the scenes/collision shapes, but my initial question to you is what kind of collision shapes are you using? If you are using all rectangle-based shapes, you might get some weird edge case scenarios when one rectangle collider meets the edge of two adjacent rectangle shapes.
For example/illustrative purposes, if you have a grid-based cube world like minecraft, and you have a player which is a cube based collider, it might act weird or get stuck/bumpy sometimes when sliding over other cubes, since it is potentially colliding at multiple points where the edges meet. Using a capsule or circle collider in this example would help fix the issue.
Is it an option to change the collision shape of your enemy to a circle or a capsule? That might help with some of the edge detection. Good luck!
Could you happen to share your wall crawling code here? I’ve been trying to figure this out all day using a Characterbody2D, and I haven’t been able to get it working yet.
I know this is an old post, but it’s the one that kept coming up for me when I was searching out how to make a metroid style wall crawler enemy.
Here is how I did it, gonna share the script for anyone else who is trying to figure this out. Feel free to use/edit the script however you like. This enemy only travels to the right, so if you wan’t to change direction you’ll have to make some edits.
Hope this helps someone.
extends CharacterBody2D
# --- Properties ---
var SPEED = 80
const TURN_RADIANS = PI / -2.0 # -90 degrees (Counter-Clockwise)
const NUDGE_DISTANCE = 1.0
const NUDGE_LIMIT = 20
# --- State Variables ---
var has_turned_on_ledge = false
# --- Node References ---
# need two raycasts one to detect the wall we need to climb and one to detect if there is no floor below us
@onready var ray_wall = $SurfaceRayCastFront
@onready var ray_floor = $SurfaceRayCastLedge
# -----------------------------------------------------------------------------
# Ledge Nudge Logic - so we don't spin forever when we reach a ledge
# -----------------------------------------------------------------------------
func _nudge_to_surface(forward_vector: Vector2):
# 1. Rotate 90 degrees clockwise (the opposite of TURN_RADIANS)
rotation -= TURN_RADIANS
# 2. Reset velocity before nudge
velocity = Vector2.ZERO
# 3. Nudge forward until the raycast hits the floor
var nudge_count = 0
while not ray_floor.is_colliding() and nudge_count < NUDGE_LIMIT:
# Move the character one pixel forward (local forward)
global_position += forward_vector * NUDGE_DISTANCE
nudge_count += 1
if nudge_count >= NUDGE_LIMIT:
print("Warning: Ledge Nudge hit safety limit. Something is terribly wrong")
func _physics_process(delta):
# 1. Calculate Relative Vectors
var forward_vector = Vector2.RIGHT.rotated(rotation)
var down_vector = Vector2.DOWN.rotated(rotation)
# 2. Check and Execute Turns
# Reset Ledge Flag: If the enemy is safe, reset the flag for the next potential drop.
if ray_floor.is_colliding():
has_turned_on_ledge = false
# A) WALL COLLISION: Rotate 90 degrees counter-clockwise
if ray_wall.is_colliding():
rotation += TURN_RADIANS
velocity = Vector2.ZERO
has_turned_on_ledge = false
# B) LEDGE/GAP: ONLY execute if the raycast fails AND we haven't already turned for this ledge
elif not ray_floor.is_colliding() and not has_turned_on_ledge:
_nudge_to_surface(forward_vector)
has_turned_on_ledge = true
# Apply Movement Force
velocity = forward_vector * SPEED
# 4. Final Slide
move_and_slide()
# 5. ROTATION NORMALIZATION
# wrapf limits the angle between -PI and PI, keeping the number clean and low.
rotation = wrapf(rotation, -PI, PI)
2 Likes