Reputation: 35
I am working on an enemy that uses a simple raycast to detect if a player is in front of them, then to begin chasing the player. However I get this error when run: "Attempt to call function 'is_in_group' in base 'null instance' on a null instance."
Here's the code:
extends CharacterBody3D
var player = null
var health = 100
const SPEED = 4.0
const ATTACK_RANGE = 2.0
@export var player_path : NodePath
@onready var nav_agent = $NavigationAgent3D
@onready var view_ray = $MeshInstance3D/RayCast3D
var player_found = false
# Called when the node enters the scene tree for the first time.
func _ready():
player = get_node(player_path)
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
velocity = Vector3.ZERO
if(player_found == true):
nav_agent.set_target_position(player.global_transform.origin)
var next_nav_point = nav_agent.get_next_path_position()
velocity = (next_nav_point - global_transform.origin).normalized() * SPEED
look_at(Vector3(player.global_position.x, global_position.y, player.global_position.z), Vector3.UP)
if(player_found == false):
pass
if view_ray.get_collider().is_in_group("Player") and view_ray.get_collider() != null:
player_found = true
if view_ray.get_collider() == null:
player_found = false
move_and_slide()
func _target_in_range():
return global_position.distance_to(player.global_position) < ATTACK_RANGE
func _hit_finished():
if global_position.distance_to(player.global_position) < ATTACK_RANGE + 1.0:
var dir = global_position.direction_to(player.global_position)
player.hit(dir)
func hit():
health -= 33
if (health == 0 or health < 0):
queue_free()
Here's the node structure:
VC_scout
MeshInstance3D
RayCast3D
CollisionShape3D
NavigationAgent3D
Thank you in advance!
Upvotes: 1
Views: 268
Reputation: 40285
The error is telling you that you are calling is_in_group
on null
. Since you call is_in_group
in this part of the code:
if view_ray.get_collider().is_in_group("Player") and view_ray.get_collider() != null:
player_found = true
We have to conclude that view_ray.get_collider()
is null
. Which would mean that the ray didn't collide.
And yes, you are checking if view_ray.get_collider() != null
, but you are checking that AFTER you try to call is_in_group
.
Thus, you should be able to solve this swapping the checks:
if view_ray.get_collider() != null and view_ray.get_collider().is_in_group("Player"):
player_found = true
Since we have an and
, and and
is only true
when the conditions are true
... If one of the conditions is false
, we know the result will be false
without checking the other. So when view_ray.get_collider() != null
is false
(i.e. when view_ray.get_collider()
is null
) Godot can skip checking view_ray.get_collider().is_in_group("Player")
.
To be completely clear, Godot will evaluate the bool conditions from left to right, and will short-circuit (i.e. exit early) if possible. This is a common feature in many programming languages, see Short-circuit evaluation.
Upvotes: 1