RED91
RED91

Reputation: 35

Issue with RayCast3d with detecting player in godot 4.2.1

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

Answers (1)

Theraot
Theraot

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

Related Questions