Problems trying to implement context-based steering

I’m running Godot 4.5, but upgrading to 4.7 doesn’t seem to help.

I’m making a 3D game and I’ve implemented a version of context-based steering, where a set of vectors are set up in a circle, we determine how close those directions are to the direction of what we’re trying to move towards (“interest”), then raycasts are sent in different directions in a circle, and we then take into account whether they collide with an object and how close (“danger”, which we subtract from interest then use it to add interest to the opposite direction), to help the enemy navigate around dynamic objects.

Well, I was having trouble getting my enemy to stop getting stuck on walls and instead navigate around them, and also noticed that even though the enemy is moving in the correct directions, the system I set up to indicate where it wants to go seems to be backwards. You see, I was trying to debug this system by placing sphere meshes in a circle where the raycasts are casting to, and having them turn green where there’s high interest and red where there’s low interest.

So I decided to create a minimal project to demonstrate these issues, and here’s where it gets weird… neither of those issues were present in the minimal project and I can’t figure out why. The code is almost identical apart from the code in the full game project having extra functions relating to things like taking damage and writing their coordinates to save files – things that shouldn’t have any effect on this navigation system.

The code is divided into two files and it’s quite long, so I’m linking it in a pastebin below. I’ve run both these scripts through a diff checker and I’ve got NOTHING for why one would have a backwards interest indicator colors glitch and the other wouldn’t. Thanks a ton to anyone who takes the time to try and help me with this because this navigation code is is really a lot to read through.

I had the exact same issue in my Contextual Steering attempt as well. It would just oscillate in its place and couldn’t decide which direction to go because if it goes one way, the other way is shorter so I used a backup direction.

If the npc using Contextual Steering is stuck in its place for a couple of seconds, it follows the backup direction. I calculate the backup direction by looping over raycasts and the first one that doesn’t collide with anything is the backup direction I choose. Then the npc follows that direction until raycasts don’t collide with anything and after that, I revert back to normal Contextual Steering path finding.

Here’s the code incase you are interested.

I first get a backup direction by looping over raycasts and see which one is not colliding with anything.

func get_backup_direction() → void:
    var front_ray: RayCast3D = context_rays[0]
    var quarter: int = number_of_rays / 4
    var left_ray: RayCast3D = context_rays[ quarter - 1]
    if front_ray.is_colliding():
        stuck_object = front_ray.get_collider()

    # If something is at the left side of the object, find a direction by
    # checking rays clockwise and vice versa.
    if left_ray.is_colliding():
	    for i in number_of_rays:
		    if not context_rays[-i].is_colliding():
			    backup_direction = context_rays[-i].global_basis.z
			    break
	else:
		for i in number_of_rays:
			if not context_rays[i].is_colliding():
				backup_direction = context_rays[i].global_basis.z
				break
	backup = true

If backup variable is true, I run the backup_navigation function in _physics_process() to figure out when the npc is away from the object that cause it to oscillate. If the npc is away from the object, turn backup boolean to false and continue with normal Contextual Steering

func backup_navigation(speed: float, backup_threshold: float) → void:
	var hit_count: int = 0
	for i in number_of_rays:
		if context_rays[i].is_colliding() and context_rays[i].get_collider() == stuck_object:
			hit_count += 1

	if hit_count < (number_of_rays / 4) and speed > backup_threshold:
		backup = false