How can i make this more eficient this code?

Godot Version

Godot 4.5.2-stable

Question

Hi, I am making a 3D fps game that uses sprites, something ilike classic Doom, but well i have this small part of code to check the player’s distance and the enemy police guy, as you can see below than check the distance, and enter a “weapons free” state, than going into a function that defines that state. What i would like to you guys to help me with is: Converting the distance numbers below into meters and also making this more complex.

This is the block, the more honest you guys can be the better:

# Checks the distance between the player and the policeguy
func check_distance():
	var distance = self.global_position.distance_to(get_node("res://DATA/Actors/Player.tscn").global_position)  
	if distance >=100: # If is highier than 100, return to walk
		return police_active()
	elif distance == 150: # If less than 100m shoots while prone, for bbetter precision
		police_firing_prone()
	elif distance <= 100: # If less than 100m shoots normally
		police_firing()

How did you determine it’s inefficient?

This part certainly doesn’t work and will give you an error. You cannot get nodes from resource paths.


For general code review

  • Don’t use get_node for every distance check, store a player reference elsewhere and reuse it.
  • Don’t compare floats by ==, your distance == 150 will almost certainly never trigger.
  • Square your values and use distance_squared_to for a minor performance increase.
1 Like

Enemies in my game all have an instance of this class. That way they only have to look for the player node once.

class_name CharacterTracker 
extends Node2D

## Must be added to tree

var tracking: CharacterBody2D

func _init(to_track: CharacterBody2D) -> void:
	tracking = to_track
	
func get_vector() -> Vector2:
	if not tracking: return Vector2.ZERO
	return tracking.position
	

func get_distance() -> float:
	if not tracking: return 0.0
	return global_position.distance_to(get_vector())
	

overriding _init with args on a Node will break it’s ability to instantiate, generally speaking never override _init unless you know what you are doing and extending with a RefCounted.

1 Like

Good thing I know what I’m doing then.

I don’t want that class to instantiate unless it is called with a reference to the character it is tracking. The only reason it extends Node2D is so I can use global_position in the get_distance method.

As far as I know there is no way to do this via _init when extending Node2D, both .instantiate() and CharacterTracker.new() don’t take arguments and will fail, unless you are making the script object and the node separately then applying it, but I wouldn’t recommend such a workflow to new users and could be replaced by a simplier .instantiate() then calling a method or assigning properties.

If you are doing this to specifically guarantee the data exists then you should use an assert on _ready or as soon as you believe the object is valid and should function. Furthermore if that were true you wouldn’t add if not tracking in your other functions, these check makes your scripts silently fail instead of producing errors you can solve.

.new() should work for nodes with parametrized _init(), but .instantiate() won’t because there’s no way to pass the arguments, except if there are default values for all arguments. I do agree though that this example is a rather odd usage of it.

1 Like

That seems great for a bullet hell. Seems unnecessary though if you have enemies that only track the player when it’s in range. I set that value when the player enters range. Especially since I don’t always spawn he player when I spawn the level if there’s a cutscene or something else.

This method also allows me to have enemies target one another if confused, or to have multiple players and let the enemies target different ones.