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.