I am trying to make a system where various things increase an NPCs threat meter, so that the NPC can then choose who to target once they become hostile, and I am having some trouble with the NPCs detection function. Here is the function that is causing the issue.
func stimulus_sight_check(type, target):
print("STIMSIGHTCHECK")
if type == StimulusGlobal.ST_HEAR:
print("CAN HEAR")
if areaNode.overlaps_area(target.area):
return true
elif type == StimulusGlobal.ST_SIGHT:
print(sightCone.get_overlapping_bodies())
sightRay.target_position = sightRay.to_local(target.global_position)
sightRay.force_raycast_update()
if sightRay.is_colliding() and sightRay.get_collider() == target.caller and sightCone.overlaps_body(target.caller):
print("CAN SEE")
return true
else:
print(sightRay.get_collider())
#print(target)
print("CANT SEE")
return false
Right now I am testing this system with the player, and a “threat cube”, and I can make it so the NPC can “detect” any combination of the player, and the cube. The issue that occurs is that sightCone.get_overlapping_bodies() is only detecting the threat cube if the player is also detectable. If the threat cube is the only thing the NPC can “detect” it won’t ever appear in the overlapping bodies array. I’m not sure what’s causing this as its a very unusual situation, I would appreciate any assisstance.
The function is called in the physics process from this function, which is part of a larger detection system.
overlapAreas = alertArea.get_overlapping_areas()
for i in overlapAreas.size():
if overlapAreas[i].is_in_group("Stimulus"):
var stimulus = overlapAreas[i].get_parent()
if stimulus_group_check(stimulus.group) == true and stimulus_sight_check(stimulus.type, stimulus) == true and stimulus_one_time_check(stimulus) == true:
alert += stimulus.intensity
The stimulus_group_check is returning as true, but the sight_check is the issue, as posted earlier. Here is what my player, and threat box scenes look like:
The print functions I used in the first code block I posted. When the NPC is looking for the threat box, it is returning “CANT SEE”, and since the thing that would stop that is either the sightRay not colliding, or the sightCone not overlapping, I print both the sightRays collider, and the sightCones overlapping bodies, and the sightRay says it’s interacting with the box, where the sightCone does not have the threat box inside of it.
Then with the weird edge case I noticed where if I have the NPC try to detect the player and the threatbox, the threatbox now shows up inside of the sightCones overlapping bodies, and it can be seen.
Why do you check for overlaps in stimulus_sight_check() when you already did that before you called it. Start by printing all overlaps in the second code snippet. Do you get what you expect there?
In the second code snippet, the NPC is looking for every stimulus item that is within its maximum detection range, this is to stop it from running the detection functions on every item in the game. When I print overlapping bodies, it is a number of area3Ds that are made by the stimulus object, which looks like this:
extends Node3D
@onready var caller = null
@onready var type = null
@onready var range = 0.0
@onready var group = null
@onready var oneTime = null
@onready var intensity = null
@onready var time = null
@onready var seenTargets = Array()
@onready var area = $Area3D
@onready var areaCollision = $Area3D/CollisionShape3D
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
#StimulusGlobal.stimulusArray.append(self)
pass
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
areaCollision.shape.radius = range
if time > 0:
time -= 1
if time == 0:
#StimulusGlobal.stimulusArray.erase(self)
queue_free()
They are created by running the following global function:
func create_stimulus(caller,type,range,group,oneTime,intensity,time):
var stimulusInstance = stimulusScene.instantiate()
caller.add_child(stimulusInstance)
stimulusInstance.caller = caller
stimulusInstance.type = type
stimulusInstance.range = range
stimulusInstance.group = group
stimulusInstance.oneTime = oneTime
stimulusInstance.intensity = intensity
stimulusInstance.time = time
The threatbox is being detected with the following code:
#Check Stimulus
overlapAreas = alertArea.get_overlapping_areas()
for i in overlapAreas.size():
if overlapAreas[i].is_in_group("Stimulus"):
var stimulus = overlapAreas[i].get_parent()
print(stimulus.caller)
if stimulus_group_check(stimulus.group) == true and stimulus_sight_check(stimulus.type, stimulus) == true and stimulus_one_time_check(stimulus) == true:
alert += stimulus.intensity
The print(stimulus.caller) is returning the player and the threatbox
I have found out more information. It appears that the detection will work fine on CharacterBody3Ds, but seems to have this issue on StaticBody3Ds, if this helps at all.