generated from krampus/template-godot4
Grunkbeast behavior tree
This commit is contained in:
parent
bb545bcbcd
commit
e105601c1b
File diff suppressed because one or more lines are too long
@ -1,9 +1,9 @@
|
|||||||
[gd_scene load_steps=12 format=3 uid="uid://cbxlfnlmgdvsq"]
|
[gd_scene load_steps=12 format=3 uid="uid://cbxlfnlmgdvsq"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://d2664rpg4losx" path="res://src/world/procedural_grunk_beast/procedural_grunk_beast.tscn" id="1_6yv42"]
|
[ext_resource type="Script" uid="uid://b1tbovuphat7d" path="res://levels/grunkbeast_test/procedural_grunkbeast_test.gd" id="1_ixhpa"]
|
||||||
[ext_resource type="Script" uid="uid://bukihqt1lybnx" path="res://src/util/frame_skipper.gd" id="1_eco5q"]
|
[ext_resource type="Script" uid="uid://bukihqt1lybnx" path="res://src/util/frame_skipper.gd" id="2_82w0n"]
|
||||||
[ext_resource type="Script" uid="uid://b1tbovuphat7d" path="res://levels/grunkbeast_test/grunkbeast_test.gd" id="1_ovhaj"]
|
[ext_resource type="PackedScene" uid="uid://d2664rpg4losx" path="res://src/world/procedural_grunk_beast/procedural_grunk_beast.tscn" id="3_b4iwh"]
|
||||||
[ext_resource type="Script" uid="uid://cpt8dy0csa3eu" path="res://levels/grunkbeast_test/fixed_camera.gd" id="2_77sam"]
|
[ext_resource type="Script" uid="uid://cpt8dy0csa3eu" path="res://levels/grunkbeast_test/fixed_camera.gd" id="4_32imj"]
|
||||||
|
|
||||||
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_goufh"]
|
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_goufh"]
|
||||||
|
|
||||||
@ -28,8 +28,8 @@ height = 1.0
|
|||||||
height = 1.0
|
height = 1.0
|
||||||
radius = 2.0
|
radius = 2.0
|
||||||
|
|
||||||
[node name="GrunkbeastTest" type="Node3D"]
|
[node name="ProceduralGrunkbeastTest" type="Node3D"]
|
||||||
script = ExtResource("1_ovhaj")
|
script = ExtResource("1_ixhpa")
|
||||||
|
|
||||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
|
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
|
||||||
transform = Transform3D(0.866025, -0.156955, -0.474726, 0.5, 0.271854, 0.82225, 0, -0.949453, 0.31391, 0, 0, 0)
|
transform = Transform3D(0.866025, -0.156955, -0.474726, 0.5, 0.271854, 0.82225, 0, -0.949453, 0.31391, 0, 0, 0)
|
||||||
@ -56,15 +56,15 @@ mesh = SubResource("CylinderMesh_4n07c")
|
|||||||
shape = SubResource("CylinderShape3D_6yv42")
|
shape = SubResource("CylinderShape3D_6yv42")
|
||||||
|
|
||||||
[node name="FrameSkipper" type="Node" parent="."]
|
[node name="FrameSkipper" type="Node" parent="."]
|
||||||
script = ExtResource("1_eco5q")
|
script = ExtResource("2_82w0n")
|
||||||
frame_skip = 3
|
frame_skip = 3
|
||||||
|
|
||||||
[node name="GrunkBeast" parent="FrameSkipper" instance=ExtResource("1_6yv42")]
|
[node name="GrunkBeast" parent="FrameSkipper" instance=ExtResource("3_b4iwh")]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
move_speed = 8.0
|
move_speed = 8.0
|
||||||
step_time = 0.06
|
step_time = 0.06
|
||||||
|
|
||||||
[node name="Camera3D" type="Camera3D" parent="." node_paths=PackedStringArray("target")]
|
[node name="Camera3D" type="Camera3D" parent="." node_paths=PackedStringArray("target")]
|
||||||
transform = Transform3D(0.252101, -0.522855, 0.81429, 0, 0.841469, 0.540306, -0.967701, -0.136212, 0.212135, 6.63551, 7.43415, 1.1904)
|
transform = Transform3D(0.252101, -0.522855, 0.81429, 0, 0.841469, 0.540306, -0.967701, -0.136212, 0.212135, 6.63551, 7.43415, 1.1904)
|
||||||
script = ExtResource("2_77sam")
|
script = ExtResource("4_32imj")
|
||||||
target = NodePath("../FrameSkipper/GrunkBeast")
|
target = NodePath("../FrameSkipper/GrunkBeast")
|
@ -37,11 +37,12 @@ background_mode = 2
|
|||||||
sky = SubResource("Sky_pka60")
|
sky = SubResource("Sky_pka60")
|
||||||
|
|
||||||
[sub_resource type="NavigationMesh" id="NavigationMesh_gyhlh"]
|
[sub_resource type="NavigationMesh" id="NavigationMesh_gyhlh"]
|
||||||
vertices = PackedVector3Array(-26.25, 0.519, -29.25, -26.5, 0.519, -30.75, -27.5, 0.519, -30.75, -27.5, 0.519, -17.25, -26.75, 0.519, -18.25, -26.25, 0.519, -19, -0.25, 0.519, -17.5, 0.75, 0.519, -18, 0.75, 0.519, -19.75, -0.75, 0.519, -19, -1.25, 0.519, -18.5, -1, 0.519, -17.25, -3.25, 0.519, -24.25, -3.25, 0.519, -20.25, -1.25, 0.519, -20.25, 1.75, 0.519, -20.25, 1.75, 0.519, -24.25, -25.75, 0.519, -18.5, -25.25, 0.519, -18.25, -19.75, 0.519, -17.5, -24.75, 0.519, -17.25, -18, 0.519, -17.5, -0.5, 0.519, -16.75, -20.25, 0.519, -18.5, -0.5, 0.519, -6, 0.75, 0.519, -6, 0.75, 0.519, -12.75, 0, 0.519, -13.25, -17, 0.519, -18.5, -24.25, 0.519, -24.25, -24.25, 0.519, -20.25, 2.5, 0.519, -19.75, 24.25, 0.519, -24.25, 2.5, 0.519, -5.75, 24.25, 0.519, -5.5, -2.25, 0.519, -4.25, -2.25, 0.519, -15.5, -24.25, 0.519, -15.5, -1.5, 0.519, -3.75, -24.25, 0.519, 24.25, -1.5, 0.519, 24.25, 0.75, 0.519, -4.25, -0.5, 0.519, -4.25, 1.75, 0.519, -3.75, 1.75, 0.519, 24.25, 2.5, 0.519, -4.25, 24.25, 0.519, 24.25)
|
vertices = PackedVector3Array(-26.25, 0.499, -29.25, -26.5, 0.499, -30.75, -27.5, 0.499, -30.75, -27.5, 0.499, -17.25, -26.75, 0.499, -18.25, -26.25, 0.499, -19, -0.25, 0.499, -17.5, 0.75, 0.499, -18, 0.75, 0.499, -19.75, -0.75, 0.499, -19, -1.25, 0.499, -18.5, -1, 0.499, -17.25, -3.25, 0.499, -24.25, -3.25, 0.499, -20.25, -1.25, 0.499, -20.25, 1.75, 0.499, -20.25, 1.75, 0.499, -24.25, -25.75, 0.499, -18.5, -25.5, 0.499, -18.25, -19.75, 0.499, -17.5, -24.75, 0.499, -17.25, -18, 0.499, -17.5, -0.5, 0.499, -16.75, -20.25, 0.499, -18.5, -0.5, 0.499, -6, 0.75, 0.499, -6, 0.75, 0.499, -12.75, 0, 0.499, -13.25, -17, 0.499, -18.5, -24.25, 0.499, -24.25, -24.25, 0.499, -20.25, 2.5, 0.499, -19.75, 24.25, 0.499, -24.25, 2.5, 0.499, -5.75, 24.25, 0.499, -5.5, -2.25, 0.499, -4.25, -2.25, 0.499, -15.5, -24.25, 0.499, -15.5, -1.5, 0.499, -3.75, -24.25, 0.499, 24.25, -1.5, 0.499, 24.25, 0.75, 0.499, -4.25, -0.5, 0.499, -4.25, 1.75, 0.499, -3.75, 1.75, 0.499, 24.25, 2.5, 0.499, -4.25, 24.25, 0.499, 24.25)
|
||||||
polygons = [PackedInt32Array(4, 3, 5), PackedInt32Array(5, 3, 0), PackedInt32Array(0, 3, 1), PackedInt32Array(1, 3, 2), PackedInt32Array(11, 10, 6), PackedInt32Array(6, 10, 9), PackedInt32Array(6, 9, 7), PackedInt32Array(7, 9, 8), PackedInt32Array(14, 13, 12), PackedInt32Array(8, 14, 15), PackedInt32Array(15, 14, 16), PackedInt32Array(16, 14, 12), PackedInt32Array(18, 4, 17), PackedInt32Array(20, 18, 19), PackedInt32Array(8, 9, 14), PackedInt32Array(19, 21, 20), PackedInt32Array(20, 21, 11), PackedInt32Array(6, 22, 11), PackedInt32Array(17, 23, 18), PackedInt32Array(18, 23, 19), PackedInt32Array(25, 24, 26), PackedInt32Array(26, 24, 27), PackedInt32Array(10, 11, 28), PackedInt32Array(28, 11, 21), PackedInt32Array(6, 27, 22), PackedInt32Array(22, 27, 24), PackedInt32Array(17, 4, 5), PackedInt32Array(30, 29, 13), PackedInt32Array(13, 29, 12), PackedInt32Array(15, 16, 31), PackedInt32Array(31, 16, 32), PackedInt32Array(33, 31, 34), PackedInt32Array(34, 31, 32), PackedInt32Array(37, 36, 35), PackedInt32Array(35, 38, 37), PackedInt32Array(37, 38, 40), PackedInt32Array(37, 40, 39), PackedInt32Array(42, 24, 41), PackedInt32Array(41, 24, 25), PackedInt32Array(41, 43, 42), PackedInt32Array(42, 43, 38), PackedInt32Array(38, 43, 44), PackedInt32Array(38, 44, 40), PackedInt32Array(45, 33, 34), PackedInt32Array(45, 34, 43), PackedInt32Array(43, 34, 44), PackedInt32Array(44, 34, 46)]
|
polygons = [PackedInt32Array(4, 3, 5), PackedInt32Array(5, 3, 0), PackedInt32Array(0, 3, 1), PackedInt32Array(1, 3, 2), PackedInt32Array(11, 10, 6), PackedInt32Array(6, 10, 9), PackedInt32Array(6, 9, 7), PackedInt32Array(7, 9, 8), PackedInt32Array(14, 13, 12), PackedInt32Array(8, 14, 15), PackedInt32Array(15, 14, 16), PackedInt32Array(16, 14, 12), PackedInt32Array(18, 4, 17), PackedInt32Array(20, 18, 19), PackedInt32Array(8, 9, 14), PackedInt32Array(19, 21, 20), PackedInt32Array(20, 21, 11), PackedInt32Array(6, 22, 11), PackedInt32Array(17, 23, 18), PackedInt32Array(18, 23, 19), PackedInt32Array(25, 24, 26), PackedInt32Array(26, 24, 27), PackedInt32Array(10, 11, 28), PackedInt32Array(28, 11, 21), PackedInt32Array(6, 27, 22), PackedInt32Array(22, 27, 24), PackedInt32Array(17, 4, 5), PackedInt32Array(30, 29, 13), PackedInt32Array(13, 29, 12), PackedInt32Array(15, 16, 31), PackedInt32Array(31, 16, 32), PackedInt32Array(33, 31, 34), PackedInt32Array(34, 31, 32), PackedInt32Array(37, 36, 35), PackedInt32Array(35, 38, 37), PackedInt32Array(37, 38, 40), PackedInt32Array(37, 40, 39), PackedInt32Array(42, 24, 41), PackedInt32Array(41, 24, 25), PackedInt32Array(41, 43, 42), PackedInt32Array(42, 43, 38), PackedInt32Array(38, 43, 44), PackedInt32Array(38, 44, 40), PackedInt32Array(45, 33, 34), PackedInt32Array(45, 34, 43), PackedInt32Array(43, 34, 44), PackedInt32Array(44, 34, 46)]
|
||||||
geometry_parsed_geometry_type = 1
|
geometry_parsed_geometry_type = 1
|
||||||
geometry_collision_mask = 4278190081
|
geometry_collision_mask = 4278190081
|
||||||
agent_height = 2.0
|
agent_height = 2.0
|
||||||
|
agent_radius = 0.75
|
||||||
|
|
||||||
[sub_resource type="PlaneMesh" id="PlaneMesh_nwuu1"]
|
[sub_resource type="PlaneMesh" id="PlaneMesh_nwuu1"]
|
||||||
size = Vector2(50, 50)
|
size = Vector2(50, 50)
|
||||||
@ -335,6 +336,7 @@ navigation_mesh = SubResource("NavigationMesh_gyhlh")
|
|||||||
|
|
||||||
[node name="WorldFloor" type="StaticBody3D" parent="NavigationRegion3D" groups=["PlasticMaterial"]]
|
[node name="WorldFloor" type="StaticBody3D" parent="NavigationRegion3D" groups=["PlasticMaterial"]]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.001, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.001, 0)
|
||||||
|
collision_layer = 5
|
||||||
|
|
||||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="NavigationRegion3D/WorldFloor"]
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="NavigationRegion3D/WorldFloor"]
|
||||||
mesh = SubResource("PlaneMesh_nwuu1")
|
mesh = SubResource("PlaneMesh_nwuu1")
|
||||||
|
@ -63,8 +63,9 @@ folder_colors={
|
|||||||
"res://levels/": "blue",
|
"res://levels/": "blue",
|
||||||
"res://levels/ghost_ship/": "purple",
|
"res://levels/ghost_ship/": "purple",
|
||||||
"res://src/": "green",
|
"res://src/": "green",
|
||||||
"res://src/ui/": "yellow",
|
"res://src/ui/": "orange",
|
||||||
"res://src/world/": "teal"
|
"res://src/world/": "teal",
|
||||||
|
"res://src/world/grunk_beast/behaviors/": "yellow"
|
||||||
}
|
}
|
||||||
|
|
||||||
[game]
|
[game]
|
||||||
|
14
src/world/grunk_beast/behaviors/actions/blackboard_copy.gd
Normal file
14
src/world/grunk_beast/behaviors/actions/blackboard_copy.gd
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
@tool
|
||||||
|
class_name BlackboardCopy extends ActionLeaf
|
||||||
|
## Copy a value from one blackboard key to another.
|
||||||
|
|
||||||
|
## Source blackboard key.
|
||||||
|
@export var source_key: String
|
||||||
|
|
||||||
|
## Destination blackboard key.
|
||||||
|
@export var destination_key: String
|
||||||
|
|
||||||
|
|
||||||
|
func tick(_actor: Node, blackboard: Blackboard) -> int:
|
||||||
|
blackboard.set_value(destination_key, blackboard.get_value(source_key))
|
||||||
|
return SUCCESS
|
@ -0,0 +1 @@
|
|||||||
|
uid://wfd5nbethyw6
|
@ -0,0 +1,14 @@
|
|||||||
|
@tool
|
||||||
|
class_name BlackboardEraseSafe extends ActionLeaf
|
||||||
|
## Erases the specified key from the blackboard.
|
||||||
|
##
|
||||||
|
## Unlike Beehave's builtin BlackboardEraseAction, this version will succeed silently if
|
||||||
|
## the given key is not defined.
|
||||||
|
|
||||||
|
## Expression representing a blackboard key.
|
||||||
|
@export var key := ""
|
||||||
|
|
||||||
|
|
||||||
|
func tick(_actor: Node, blackboard: Blackboard) -> int:
|
||||||
|
blackboard.erase_value(key)
|
||||||
|
return SUCCESS
|
@ -0,0 +1 @@
|
|||||||
|
uid://demv7xh27ouvr
|
20
src/world/grunk_beast/behaviors/actions/grab_target.gd
Normal file
20
src/world/grunk_beast/behaviors/actions/grab_target.gd
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
@tool
|
||||||
|
class_name GrabTarget extends ActionLeaf
|
||||||
|
## Grab the given target!!
|
||||||
|
##
|
||||||
|
## Returns FAILURE if there is no valid key at the given target.
|
||||||
|
|
||||||
|
## Blackboard key of the grab target.
|
||||||
|
@export var blackboard_key := "target"
|
||||||
|
|
||||||
|
|
||||||
|
func tick(_actor: Node, blackboard: Blackboard) -> int:
|
||||||
|
@warning_ignore("unsafe_cast")
|
||||||
|
var target := blackboard.get_value(blackboard_key) as Node3D
|
||||||
|
if not is_instance_valid(target):
|
||||||
|
return FAILURE
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
print_debug("GET FUCKIGN GRABBED IDIOT!! ", target)
|
||||||
|
|
||||||
|
return SUCCESS
|
@ -0,0 +1 @@
|
|||||||
|
uid://b0xue7ao0gjqo
|
@ -0,0 +1,19 @@
|
|||||||
|
@tool
|
||||||
|
class_name PickRandomFromGroup extends ActionLeaf
|
||||||
|
## Picks a random node in the given group and stores it in the blackboard.
|
||||||
|
##
|
||||||
|
## Returns FAILURE if there are no nodes in the given group.
|
||||||
|
|
||||||
|
## Blackboard key under which the node will be stored.
|
||||||
|
@export var blackboard_key := "target"
|
||||||
|
|
||||||
|
## Name of the group to pick from.
|
||||||
|
@export var group: String
|
||||||
|
|
||||||
|
|
||||||
|
func tick(actor: Node, blackboard: Blackboard) -> int:
|
||||||
|
var nodes: Array[Node] = actor.get_tree().get_nodes_in_group(group)
|
||||||
|
if not nodes:
|
||||||
|
return FAILURE
|
||||||
|
blackboard.set_value(blackboard_key, nodes.pick_random())
|
||||||
|
return SUCCESS
|
@ -0,0 +1 @@
|
|||||||
|
uid://cg55nu4y0a5ud
|
20
src/world/grunk_beast/behaviors/actions/pursue_target.gd
Normal file
20
src/world/grunk_beast/behaviors/actions/pursue_target.gd
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
@tool
|
||||||
|
class_name PursueTarget extends ActionLeaf
|
||||||
|
## Wait until the navigation target is reached (or cannot navigate further)
|
||||||
|
##
|
||||||
|
## This action will update the target's position each tick, allowing for tracking moving targets.
|
||||||
|
## Returns FAILURE if there isn't a Node3D at the given blackboard key.
|
||||||
|
|
||||||
|
@export var blackboard_key := "target"
|
||||||
|
|
||||||
|
@onready var nav_agent: NavigationAgent3D = %NavAgent
|
||||||
|
|
||||||
|
|
||||||
|
func tick(_actor: Node, blackboard: Blackboard) -> int:
|
||||||
|
@warning_ignore("unsafe_cast")
|
||||||
|
var target := blackboard.get_value(blackboard_key) as Node3D
|
||||||
|
if not is_instance_valid(target):
|
||||||
|
return FAILURE
|
||||||
|
nav_agent.target_position = target.global_position
|
||||||
|
|
||||||
|
return SUCCESS if nav_agent.is_navigation_finished() else RUNNING
|
@ -0,0 +1 @@
|
|||||||
|
uid://bkdwuqv4tudka
|
26
src/world/grunk_beast/behaviors/actions/set_nav_target.gd
Normal file
26
src/world/grunk_beast/behaviors/actions/set_nav_target.gd
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
@tool
|
||||||
|
class_name SetNavTarget extends ActionLeaf
|
||||||
|
## Set the nav agent target position to the global position at the given blackboard key.
|
||||||
|
##
|
||||||
|
## The target value may be a Vector3 position in space,
|
||||||
|
## or a Node3D, in which case the global position of the node will be used as the target position.
|
||||||
|
##
|
||||||
|
## Returns failure if there is no valid target under the given blackboard key.
|
||||||
|
|
||||||
|
## Blackboard key of the Node3D to set as a target
|
||||||
|
@export var blackboard_key := "target"
|
||||||
|
|
||||||
|
@onready var nav_agent: NavigationAgent3D = %NavAgent
|
||||||
|
|
||||||
|
|
||||||
|
func tick(_actor: Node, blackboard: Blackboard) -> int:
|
||||||
|
var value: Variant = blackboard.get_value(blackboard_key)
|
||||||
|
if value is Vector3:
|
||||||
|
@warning_ignore("unsafe_cast")
|
||||||
|
nav_agent.target_position = value as Vector3
|
||||||
|
elif value is Node3D and is_instance_valid(value):
|
||||||
|
@warning_ignore("unsafe_cast")
|
||||||
|
nav_agent.target_position = (value as Node3D).global_position
|
||||||
|
else:
|
||||||
|
return FAILURE
|
||||||
|
return SUCCESS
|
@ -0,0 +1 @@
|
|||||||
|
uid://u1ntpwjwjqhj
|
@ -0,0 +1,21 @@
|
|||||||
|
@tool
|
||||||
|
class_name SetTargetFromArea extends ActionLeaf
|
||||||
|
## Store the first node in the given area on the blackboard.
|
||||||
|
##
|
||||||
|
## Returns FAILURE if there is no such node overlapping the given area.
|
||||||
|
## NOTE: You probably should only use this with areas masked to only have one possible body.
|
||||||
|
|
||||||
|
## Key to store the target under.
|
||||||
|
@export var blackboard_key := "target"
|
||||||
|
|
||||||
|
## Area to get target from.
|
||||||
|
@export var area: Area3D
|
||||||
|
|
||||||
|
|
||||||
|
func tick(_actor: Node, blackboard: Blackboard) -> int:
|
||||||
|
var bodies := area.get_overlapping_bodies()
|
||||||
|
if not bodies:
|
||||||
|
return FAILURE
|
||||||
|
|
||||||
|
blackboard.set_value(blackboard_key, bodies[0])
|
||||||
|
return SUCCESS
|
@ -0,0 +1 @@
|
|||||||
|
uid://b34l3v4sr8rmq
|
18
src/world/grunk_beast/behaviors/actions/start_timer.gd
Normal file
18
src/world/grunk_beast/behaviors/actions/start_timer.gd
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
@tool
|
||||||
|
class_name StartTimer extends ActionLeaf
|
||||||
|
## Start the given timer.
|
||||||
|
## If `seconds > 0`, start the timer with that duration, otherwise use the default.
|
||||||
|
|
||||||
|
## Timer to start.
|
||||||
|
@export var timer: Timer
|
||||||
|
|
||||||
|
## Number of seconds to set the timer for. If <0, use the default.
|
||||||
|
@export var seconds := -1.0
|
||||||
|
|
||||||
|
|
||||||
|
func tick(_actor: Node, _blackboard: Blackboard) -> int:
|
||||||
|
if seconds > 0:
|
||||||
|
timer.start(seconds)
|
||||||
|
else:
|
||||||
|
timer.start()
|
||||||
|
return SUCCESS
|
@ -0,0 +1 @@
|
|||||||
|
uid://ykfqlqp7e8og
|
@ -0,0 +1,9 @@
|
|||||||
|
@tool
|
||||||
|
class_name TravelToDestination extends ActionLeaf
|
||||||
|
## Wait until the navigation target is reached (or cannot navigate further)
|
||||||
|
|
||||||
|
@onready var nav_agent: NavigationAgent3D = %NavAgent
|
||||||
|
|
||||||
|
|
||||||
|
func tick(_actor: Node, _blackboard: Blackboard) -> int:
|
||||||
|
return SUCCESS if nav_agent.is_navigation_finished() else RUNNING
|
@ -0,0 +1 @@
|
|||||||
|
uid://om57w2acvgb7
|
@ -0,0 +1,11 @@
|
|||||||
|
@tool
|
||||||
|
class_name AreaHasBodies extends ConditionLeaf
|
||||||
|
## Does the given Area3D have any overlapping bodies?
|
||||||
|
|
||||||
|
## Area3D to check for overlapping bodies.
|
||||||
|
@export var area: Area3D
|
||||||
|
|
||||||
|
|
||||||
|
func tick(_actor: Node, _blackboard: Blackboard) -> int:
|
||||||
|
area.get_overlapping_bodies()
|
||||||
|
return SUCCESS if area.has_overlapping_bodies() else FAILURE
|
@ -0,0 +1 @@
|
|||||||
|
uid://ulw86qyy1knh
|
16
src/world/grunk_beast/behaviors/conditions/body_in_area.gd
Normal file
16
src/world/grunk_beast/behaviors/conditions/body_in_area.gd
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
@tool
|
||||||
|
class_name BodyInArea extends ConditionLeaf
|
||||||
|
## Is the body at the given blackboard key in the given area?
|
||||||
|
##
|
||||||
|
## Returns FAILURE if there is no Node3D at the given blackboard key.
|
||||||
|
|
||||||
|
## Blackboard key of the body to check.
|
||||||
|
@export var blackboard_key := "target"
|
||||||
|
## Area3D to check for the target body.
|
||||||
|
@export var area: Area3D
|
||||||
|
|
||||||
|
|
||||||
|
func tick(_actor: Node, blackboard: Blackboard) -> int:
|
||||||
|
@warning_ignore("unsafe_cast")
|
||||||
|
var body := blackboard.get_value(blackboard_key) as Node3D
|
||||||
|
return SUCCESS if is_instance_valid(body) and body in area.get_overlapping_bodies() else FAILURE
|
@ -0,0 +1 @@
|
|||||||
|
uid://7k5hor1omsxc
|
@ -0,0 +1,9 @@
|
|||||||
|
@tool
|
||||||
|
class_name TargetReached extends ConditionLeaf
|
||||||
|
## Has the nav agent reached its current target?
|
||||||
|
|
||||||
|
@onready var nav_agent: NavigationAgent3D = %NavAgent
|
||||||
|
|
||||||
|
|
||||||
|
func tick(_actor: Node, _blackboard: Blackboard) -> int:
|
||||||
|
return SUCCESS if nav_agent.is_target_reached() else FAILURE
|
@ -0,0 +1 @@
|
|||||||
|
uid://bnd8y8fkvg082
|
10
src/world/grunk_beast/behaviors/conditions/timer_running.gd
Normal file
10
src/world/grunk_beast/behaviors/conditions/timer_running.gd
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
@tool
|
||||||
|
class_name TimerRunning extends ConditionLeaf
|
||||||
|
## Is the given timer currently running?
|
||||||
|
|
||||||
|
## Timer to check.
|
||||||
|
@export var timer: Timer
|
||||||
|
|
||||||
|
|
||||||
|
func tick(_actor: Node, _blackboard: Blackboard) -> int:
|
||||||
|
return FAILURE if timer.is_stopped() else SUCCESS
|
@ -0,0 +1 @@
|
|||||||
|
uid://h0cp58nswpml
|
31
src/world/grunk_beast/behaviors/decorators/random_delay.gd
Normal file
31
src/world/grunk_beast/behaviors/decorators/random_delay.gd
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
@tool
|
||||||
|
class_name RandomDelay extends DelayDecorator
|
||||||
|
## DelayDecorator which randomizes the wait time to a normal random sample each time it's run.
|
||||||
|
|
||||||
|
## Mean wait time, in seconds.
|
||||||
|
@export var mean_time := 1.0:
|
||||||
|
set(value):
|
||||||
|
mean_time = value
|
||||||
|
randomize_wait_time()
|
||||||
|
|
||||||
|
## Standard deviation of wait time, in seconds.
|
||||||
|
@export var st_dev_time := 0.1:
|
||||||
|
set(value):
|
||||||
|
st_dev_time = value
|
||||||
|
randomize_wait_time()
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
randomize_wait_time()
|
||||||
|
|
||||||
|
|
||||||
|
func randomize_wait_time() -> void:
|
||||||
|
wait_time = maxf(0.0, randfn(mean_time, st_dev_time))
|
||||||
|
|
||||||
|
|
||||||
|
func tick(actor: Node, blackboard: Blackboard) -> int:
|
||||||
|
var total_time: float = blackboard.get_value(cache_key, 0.0, str(actor.get_instance_id()))
|
||||||
|
if total_time == 0.0:
|
||||||
|
randomize_wait_time()
|
||||||
|
|
||||||
|
return super.tick(actor, blackboard)
|
@ -0,0 +1 @@
|
|||||||
|
uid://beyk2xtbjrsg4
|
@ -2,25 +2,12 @@ class_name GrunkBeast extends CharacterBody3D
|
|||||||
## Grunk beast controller
|
## Grunk beast controller
|
||||||
|
|
||||||
#region Constants
|
#region Constants
|
||||||
signal state_changed(new_state: State)
|
const STALKING_SOUND_LIMIT := 20.0
|
||||||
|
|
||||||
enum State {
|
|
||||||
UNKNOWN,
|
|
||||||
LURKING,
|
|
||||||
STALKING,
|
|
||||||
PURSUIT,
|
|
||||||
}
|
|
||||||
|
|
||||||
const LURK_POINT_GROUP := "LurkPoint"
|
|
||||||
const STALKING_SOUND_LIMIT := 14.0
|
|
||||||
const IDLE_EPSILON := 0.001
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Exported Properties
|
#region Exported Properties
|
||||||
@export var lurk_spontaneity := 0.02
|
|
||||||
@export var base_speed := 60.0
|
@export var base_speed := 60.0
|
||||||
@export var pursuit_speed := 180.0
|
@export var pursuit_speed := 180.0
|
||||||
@export var initial_state := State.LURKING
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Member Variables
|
#region Member Variables
|
||||||
@ -29,29 +16,52 @@ var gravity: Vector3 = (
|
|||||||
* ProjectSettings.get_setting("physics/3d/default_gravity_vector")
|
* ProjectSettings.get_setting("physics/3d/default_gravity_vector")
|
||||||
)
|
)
|
||||||
|
|
||||||
var state: State:
|
|
||||||
set(value):
|
|
||||||
if state != value:
|
|
||||||
_on_state_change(value)
|
|
||||||
state = value
|
|
||||||
|
|
||||||
var pathfinding := true
|
var pathfinding := true
|
||||||
|
|
||||||
@onready var nav_agent: NavigationAgent3D = %NavAgent
|
@onready var nav_agent: NavigationAgent3D = %NavAgent
|
||||||
@onready var stalking_timeout: Timer = %StalkingTimeout
|
@onready var nav_probe: NavigationAgent3D = %NavProbe
|
||||||
@onready var idle_timer: Timer = %IdleTimer
|
@onready var stalking_timer: Timer = %StalkingTimer
|
||||||
|
|
||||||
|
@onready var blackboard: Blackboard = %Blackboard
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Character Controller
|
#region Character Controller
|
||||||
|
|
||||||
|
|
||||||
|
func is_pursuing() -> bool:
|
||||||
|
return blackboard.has_value("pursuit_target")
|
||||||
|
|
||||||
|
|
||||||
|
func is_stalking() -> bool:
|
||||||
|
return false # TODO
|
||||||
|
|
||||||
|
|
||||||
func get_speed() -> float:
|
func get_speed() -> float:
|
||||||
match state:
|
if is_pursuing():
|
||||||
State.PURSUIT:
|
|
||||||
return pursuit_speed
|
return pursuit_speed
|
||||||
return base_speed
|
return base_speed
|
||||||
|
|
||||||
|
|
||||||
|
func path_shorter_than(target: Vector3, limit: float) -> bool:
|
||||||
|
var limit_sq := limit * limit
|
||||||
|
var length_sq := 0.0
|
||||||
|
var last_pos := global_position
|
||||||
|
|
||||||
|
nav_probe.target_position = target
|
||||||
|
|
||||||
|
for waypoint: Vector3 in nav_probe.get_current_navigation_path().slice(
|
||||||
|
nav_probe.get_current_navigation_path_index()
|
||||||
|
):
|
||||||
|
# Using distance squared to save a sqrt instruction
|
||||||
|
length_sq += last_pos.distance_squared_to(waypoint)
|
||||||
|
if length_sq > limit_sq:
|
||||||
|
return false
|
||||||
|
last_pos = waypoint
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
|
|
||||||
func _physics_process(delta: float) -> void:
|
func _physics_process(delta: float) -> void:
|
||||||
var motion := Vector3.ZERO
|
var motion := Vector3.ZERO
|
||||||
|
|
||||||
@ -66,114 +76,13 @@ func _physics_process(delta: float) -> void:
|
|||||||
if not is_on_floor():
|
if not is_on_floor():
|
||||||
velocity += gravity * delta
|
velocity += gravity * delta
|
||||||
|
|
||||||
if velocity.length_squared() > IDLE_EPSILON:
|
|
||||||
idle_timer.start()
|
|
||||||
|
|
||||||
move_and_slide()
|
move_and_slide()
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region State Machine
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
state = initial_state
|
|
||||||
|
|
||||||
|
|
||||||
func _current_path_shorter_than(limit: float) -> bool:
|
|
||||||
var limit_sq := limit * limit
|
|
||||||
var length_sq := 0.0
|
|
||||||
var last_pos := global_position
|
|
||||||
|
|
||||||
for waypoint: Vector3 in nav_agent.get_current_navigation_path().slice(
|
|
||||||
nav_agent.get_current_navigation_path_index()
|
|
||||||
):
|
|
||||||
# Using distance squared to save a sqrt instruction
|
|
||||||
length_sq += last_pos.distance_squared_to(waypoint)
|
|
||||||
if length_sq > limit_sq:
|
|
||||||
return false
|
|
||||||
last_pos = waypoint
|
|
||||||
|
|
||||||
return true
|
|
||||||
|
|
||||||
|
|
||||||
func _set_new_lurk_point() -> void:
|
|
||||||
@warning_ignore("unsafe_cast")
|
|
||||||
var next_lurk_point := get_tree().get_nodes_in_group(LURK_POINT_GROUP).pick_random() as Node3D
|
|
||||||
if next_lurk_point:
|
|
||||||
nav_agent.target_position = next_lurk_point.global_position
|
|
||||||
else:
|
|
||||||
push_warning(self, " tried to lurk, but couldn't find a lurk point!")
|
|
||||||
|
|
||||||
|
|
||||||
## Lurking routine
|
|
||||||
func lurk() -> void:
|
|
||||||
if nav_agent.is_target_reached() or randf() < lurk_spontaneity:
|
|
||||||
_set_new_lurk_point()
|
|
||||||
|
|
||||||
|
|
||||||
## Stalking routine
|
|
||||||
func stalk() -> void:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
## Pursuit routine
|
|
||||||
func pursue() -> void:
|
|
||||||
if Player.instance:
|
|
||||||
nav_agent.target_position = Player.instance.global_position
|
|
||||||
|
|
||||||
|
|
||||||
func _on_state_change(new_state: State) -> void:
|
|
||||||
match new_state:
|
|
||||||
State.LURKING:
|
|
||||||
_set_new_lurk_point()
|
|
||||||
State.STALKING:
|
|
||||||
stalking_timeout.start()
|
|
||||||
|
|
||||||
state_changed.emit(new_state)
|
|
||||||
|
|
||||||
|
|
||||||
func update_behavior() -> void:
|
|
||||||
match state:
|
|
||||||
State.UNKNOWN:
|
|
||||||
state = State.LURKING
|
|
||||||
update_behavior()
|
|
||||||
State.LURKING:
|
|
||||||
lurk()
|
|
||||||
State.STALKING:
|
|
||||||
stalk()
|
|
||||||
State.PURSUIT:
|
|
||||||
pursue()
|
|
||||||
|
|
||||||
|
|
||||||
func on_sound_detected(source: Vector3) -> void:
|
func on_sound_detected(source: Vector3) -> void:
|
||||||
var prev_target := nav_agent.target_position
|
|
||||||
nav_agent.target_position = source
|
|
||||||
# Check that the source isn't too far away, e.g. a sound from another room
|
# Check that the source isn't too far away, e.g. a sound from another room
|
||||||
if _current_path_shorter_than(STALKING_SOUND_LIMIT):
|
if path_shorter_than(source, STALKING_SOUND_LIMIT):
|
||||||
# First detection switches to stalking, second switches to pursuit
|
blackboard.set_value("stalking_target", source)
|
||||||
if state == State.STALKING:
|
stalking_timer.start()
|
||||||
state = State.PURSUIT
|
|
||||||
else:
|
|
||||||
state = State.STALKING
|
|
||||||
else:
|
|
||||||
nav_agent.target_position = prev_target
|
|
||||||
|
|
||||||
|
|
||||||
func on_player_entered_grabbing_range(_body: Node3D) -> void:
|
|
||||||
print_debug("GET GRABBED, IDIOT!")
|
|
||||||
|
|
||||||
|
|
||||||
func on_player_left_pursuit_range(_body: Node3D) -> void:
|
|
||||||
state = State.STALKING
|
|
||||||
|
|
||||||
|
|
||||||
func on_stalking_timeout_timeout() -> void:
|
|
||||||
state = State.LURKING
|
|
||||||
|
|
||||||
|
|
||||||
func on_stalking_idle_timer_timeout() -> void:
|
|
||||||
pass # Replace with function body.
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -1,10 +1,30 @@
|
|||||||
[gd_scene load_steps=16 format=3 uid="uid://ehf5sg3ahvbf"]
|
[gd_scene load_steps=37 format=3 uid="uid://ehf5sg3ahvbf"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://gwwmqwixqqr5" path="res://src/world/grunk_beast/grunk_beast.gd" id="2_qqnhb"]
|
[ext_resource type="Script" uid="uid://gwwmqwixqqr5" path="res://src/world/grunk_beast/grunk_beast.gd" id="2_qqnhb"]
|
||||||
[ext_resource type="Shader" uid="uid://ckxc0ngd37rtk" path="res://src/shaders/gunk.gdshader" id="4_0gxpq"]
|
[ext_resource type="Shader" uid="uid://ckxc0ngd37rtk" path="res://src/shaders/gunk.gdshader" id="4_0gxpq"]
|
||||||
[ext_resource type="Script" uid="uid://cfsiyhhrcua6o" path="res://src/world/game_sound/game_sound_listener.gd" id="5_3gbao"]
|
[ext_resource type="Script" uid="uid://cfsiyhhrcua6o" path="res://src/world/game_sound/game_sound_listener.gd" id="5_3gbao"]
|
||||||
[ext_resource type="Texture2D" uid="uid://cm1jrvx7ftx4c" path="res://assets/black.png" id="5_xuag8"]
|
[ext_resource type="Texture2D" uid="uid://cm1jrvx7ftx4c" path="res://assets/black.png" id="5_xuag8"]
|
||||||
|
[ext_resource type="Script" uid="uid://bb0t2ovl7wifo" path="res://addons/beehave/nodes/beehave_tree.gd" id="6_d4ex2"]
|
||||||
[ext_resource type="FastNoiseLite" uid="uid://cnlvdtx68giv6" path="res://assets/materials/gunk_noise.tres" id="6_mbqcc"]
|
[ext_resource type="FastNoiseLite" uid="uid://cnlvdtx68giv6" path="res://assets/materials/gunk_noise.tres" id="6_mbqcc"]
|
||||||
|
[ext_resource type="Script" uid="uid://dme5f24l0edsf" path="res://addons/beehave/blackboard.gd" id="7_cn3ok"]
|
||||||
|
[ext_resource type="Script" uid="uid://cw22yurt5l74k" path="res://addons/beehave/nodes/composites/selector_reactive.gd" id="7_vvw1q"]
|
||||||
|
[ext_resource type="Script" uid="uid://cg016dbe7gs1x" path="res://addons/beehave/nodes/composites/sequence.gd" id="8_0gxpq"]
|
||||||
|
[ext_resource type="Script" uid="uid://7k5hor1omsxc" path="res://src/world/grunk_beast/behaviors/conditions/body_in_area.gd" id="9_xuag8"]
|
||||||
|
[ext_resource type="Script" uid="uid://u1ntpwjwjqhj" path="res://src/world/grunk_beast/behaviors/actions/set_nav_target.gd" id="10_kjykp"]
|
||||||
|
[ext_resource type="Script" uid="uid://2qri6rrfv8ui" path="res://addons/beehave/nodes/decorators/cooldown.gd" id="10_ntlom"]
|
||||||
|
[ext_resource type="Script" uid="uid://beyk2xtbjrsg4" path="res://src/world/grunk_beast/behaviors/decorators/random_delay.gd" id="11_mbqcc"]
|
||||||
|
[ext_resource type="Script" uid="uid://b0xue7ao0gjqo" path="res://src/world/grunk_beast/behaviors/actions/grab_target.gd" id="11_nq7ke"]
|
||||||
|
[ext_resource type="Script" uid="uid://8hn4kne15ac5" path="res://addons/beehave/nodes/composites/selector.gd" id="12_dkcdj"]
|
||||||
|
[ext_resource type="Script" uid="uid://cg55nu4y0a5ud" path="res://src/world/grunk_beast/behaviors/actions/pick_random_from_group.gd" id="12_ml8dd"]
|
||||||
|
[ext_resource type="Script" uid="uid://dcojdhvj8qcw0" path="res://addons/beehave/nodes/composites/sequence_reactive.gd" id="12_xde72"]
|
||||||
|
[ext_resource type="Script" uid="uid://b34l3v4sr8rmq" path="res://src/world/grunk_beast/behaviors/actions/set_target_from_area.gd" id="13_x8l6r"]
|
||||||
|
[ext_resource type="Script" uid="uid://om57w2acvgb7" path="res://src/world/grunk_beast/behaviors/actions/travel_to_destination.gd" id="14_4y64f"]
|
||||||
|
[ext_resource type="Script" uid="uid://bkdwuqv4tudka" path="res://src/world/grunk_beast/behaviors/actions/pursue_target.gd" id="14_x8l6r"]
|
||||||
|
[ext_resource type="Script" uid="uid://demv7xh27ouvr" path="res://src/world/grunk_beast/behaviors/actions/blackboard_erase_safe.gd" id="15_4b27i"]
|
||||||
|
[ext_resource type="Script" uid="uid://dwfdg523bk776" path="res://addons/beehave/nodes/decorators/failer.gd" id="15_oons1"]
|
||||||
|
[ext_resource type="Script" uid="uid://wfd5nbethyw6" path="res://src/world/grunk_beast/behaviors/actions/blackboard_copy.gd" id="15_umoec"]
|
||||||
|
[ext_resource type="Script" uid="uid://ykfqlqp7e8og" path="res://src/world/grunk_beast/behaviors/actions/start_timer.gd" id="16_asd50"]
|
||||||
|
[ext_resource type="Script" uid="uid://h0cp58nswpml" path="res://src/world/grunk_beast/behaviors/conditions/timer_running.gd" id="16_oons1"]
|
||||||
|
|
||||||
[sub_resource type="NoiseTexture3D" id="NoiseTexture3D_faau1"]
|
[sub_resource type="NoiseTexture3D" id="NoiseTexture3D_faau1"]
|
||||||
width = 256
|
width = 256
|
||||||
@ -62,10 +82,10 @@ radial_segments = 7
|
|||||||
rings = 1
|
rings = 1
|
||||||
|
|
||||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_faau1"]
|
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_faau1"]
|
||||||
radius = 0.45
|
radius = 0.4
|
||||||
|
|
||||||
[sub_resource type="SphereShape3D" id="SphereShape3D_wffas"]
|
[sub_resource type="SphereShape3D" id="SphereShape3D_wffas"]
|
||||||
radius = 7.0
|
radius = 16.0
|
||||||
|
|
||||||
[sub_resource type="SphereShape3D" id="SphereShape3D_3gbao"]
|
[sub_resource type="SphereShape3D" id="SphereShape3D_3gbao"]
|
||||||
radius = 1.4
|
radius = 1.4
|
||||||
@ -73,7 +93,11 @@ radius = 1.4
|
|||||||
[sub_resource type="SphereShape3D" id="SphereShape3D_d4ex2"]
|
[sub_resource type="SphereShape3D" id="SphereShape3D_d4ex2"]
|
||||||
radius = 20.0
|
radius = 20.0
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="SphereShape3D_oons1"]
|
||||||
|
radius = 3.0
|
||||||
|
|
||||||
[node name="GrunkBeast" type="CharacterBody3D"]
|
[node name="GrunkBeast" type="CharacterBody3D"]
|
||||||
|
collision_layer = 36
|
||||||
script = ExtResource("2_qqnhb")
|
script = ExtResource("2_qqnhb")
|
||||||
|
|
||||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
||||||
@ -90,19 +114,13 @@ shape = SubResource("CapsuleShape3D_faau1")
|
|||||||
|
|
||||||
[node name="NavAgent" type="NavigationAgent3D" parent="."]
|
[node name="NavAgent" type="NavigationAgent3D" parent="."]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
|
path_desired_distance = 0.75
|
||||||
|
avoidance_enabled = true
|
||||||
|
debug_enabled = true
|
||||||
|
|
||||||
[node name="IdleTimer" type="Timer" parent="."]
|
[node name="NavProbe" type="NavigationAgent3D" parent="."]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
wait_time = 1.2
|
path_desired_distance = 0.75
|
||||||
one_shot = true
|
|
||||||
|
|
||||||
[node name="StalkingTimeout" type="Timer" parent="."]
|
|
||||||
unique_name_in_owner = true
|
|
||||||
wait_time = 25.0
|
|
||||||
one_shot = true
|
|
||||||
|
|
||||||
[node name="BehaviorUpdateTimer" type="Timer" parent="."]
|
|
||||||
autostart = true
|
|
||||||
|
|
||||||
[node name="GameSoundListener" type="StaticBody3D" parent="."]
|
[node name="GameSoundListener" type="StaticBody3D" parent="."]
|
||||||
collision_layer = 16
|
collision_layer = 16
|
||||||
@ -120,15 +138,167 @@ collision_mask = 8
|
|||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="GrabbingRange"]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="GrabbingRange"]
|
||||||
shape = SubResource("SphereShape3D_3gbao")
|
shape = SubResource("SphereShape3D_3gbao")
|
||||||
|
|
||||||
[node name="PursuitLimit" type="Area3D" parent="."]
|
[node name="PursuitRange" type="Area3D" parent="."]
|
||||||
collision_layer = 0
|
collision_layer = 0
|
||||||
collision_mask = 8
|
collision_mask = 8
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="PursuitLimit"]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="PursuitRange"]
|
||||||
shape = SubResource("SphereShape3D_d4ex2")
|
shape = SubResource("SphereShape3D_d4ex2")
|
||||||
|
|
||||||
[connection signal="timeout" from="StalkingTimeout" to="." method="on_stalking_timeout_timeout"]
|
[node name="AggroRange" type="Area3D" parent="."]
|
||||||
[connection signal="timeout" from="BehaviorUpdateTimer" to="." method="update_behavior"]
|
collision_layer = 0
|
||||||
|
collision_mask = 8
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="AggroRange"]
|
||||||
|
shape = SubResource("SphereShape3D_oons1")
|
||||||
|
|
||||||
|
[node name="SniffRange" type="Area3D" parent="."]
|
||||||
|
collision_layer = 0
|
||||||
|
collision_mask = 8
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="SniffRange"]
|
||||||
|
shape = SubResource("SphereShape3D_wffas")
|
||||||
|
|
||||||
|
[node name="StalkingTimer" type="Timer" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
wait_time = 25.0
|
||||||
|
one_shot = true
|
||||||
|
|
||||||
|
[node name="GrunkBeastBehavior" type="Node" parent="." node_paths=PackedStringArray("blackboard", "actor")]
|
||||||
|
script = ExtResource("6_d4ex2")
|
||||||
|
blackboard = NodePath("../Blackboard")
|
||||||
|
actor = NodePath("..")
|
||||||
|
metadata/_custom_type_script = "uid://bb0t2ovl7wifo"
|
||||||
|
|
||||||
|
[node name="StateSelector" type="Node" parent="GrunkBeastBehavior"]
|
||||||
|
script = ExtResource("7_vvw1q")
|
||||||
|
metadata/_custom_type_script = "uid://cw22yurt5l74k"
|
||||||
|
|
||||||
|
[node name="GrabSequence" type="Node" parent="GrunkBeastBehavior/StateSelector"]
|
||||||
|
script = ExtResource("8_0gxpq")
|
||||||
|
metadata/_custom_type_script = "uid://cg016dbe7gs1x"
|
||||||
|
|
||||||
|
[node name="IsTargetInGrabbingRange" type="Node" parent="GrunkBeastBehavior/StateSelector/GrabSequence" node_paths=PackedStringArray("area")]
|
||||||
|
script = ExtResource("9_xuag8")
|
||||||
|
blackboard_key = "pursuit_target"
|
||||||
|
area = NodePath("../../../../GrabbingRange")
|
||||||
|
metadata/_custom_type_script = "uid://7k5hor1omsxc"
|
||||||
|
|
||||||
|
[node name="GrabCooldown" type="Node" parent="GrunkBeastBehavior/StateSelector/GrabSequence"]
|
||||||
|
script = ExtResource("10_ntlom")
|
||||||
|
wait_time = 2.0
|
||||||
|
metadata/_custom_type_script = "uid://2qri6rrfv8ui"
|
||||||
|
|
||||||
|
[node name="GrabTarget" type="Node" parent="GrunkBeastBehavior/StateSelector/GrabSequence/GrabCooldown"]
|
||||||
|
script = ExtResource("11_nq7ke")
|
||||||
|
blackboard_key = "pursuit_target"
|
||||||
|
metadata/_custom_type_script = "uid://b0xue7ao0gjqo"
|
||||||
|
|
||||||
|
[node name="PursuitSequence" type="Node" parent="GrunkBeastBehavior/StateSelector"]
|
||||||
|
script = ExtResource("12_xde72")
|
||||||
|
metadata/_custom_type_script = "uid://dcojdhvj8qcw0"
|
||||||
|
|
||||||
|
[node name="TargetSelector" type="Node" parent="GrunkBeastBehavior/StateSelector/PursuitSequence"]
|
||||||
|
script = ExtResource("12_dkcdj")
|
||||||
|
metadata/_custom_type_script = "uid://8hn4kne15ac5"
|
||||||
|
|
||||||
|
[node name="TargetInPursuitRange" type="Node" parent="GrunkBeastBehavior/StateSelector/PursuitSequence/TargetSelector" node_paths=PackedStringArray("area")]
|
||||||
|
script = ExtResource("9_xuag8")
|
||||||
|
blackboard_key = "pursuit_target"
|
||||||
|
area = NodePath("../../../../../PursuitRange")
|
||||||
|
metadata/_custom_type_script = "uid://7k5hor1omsxc"
|
||||||
|
|
||||||
|
[node name="GetTargetFromAggroRange" type="Node" parent="GrunkBeastBehavior/StateSelector/PursuitSequence/TargetSelector" node_paths=PackedStringArray("area")]
|
||||||
|
script = ExtResource("13_x8l6r")
|
||||||
|
blackboard_key = "pursuit_target"
|
||||||
|
area = NodePath("../../../../../AggroRange")
|
||||||
|
metadata/_custom_type_script = "uid://b34l3v4sr8rmq"
|
||||||
|
|
||||||
|
[node name="UpdateStalkingTarget" type="Node" parent="GrunkBeastBehavior/StateSelector/PursuitSequence"]
|
||||||
|
script = ExtResource("15_umoec")
|
||||||
|
source_key = "pursuit_target"
|
||||||
|
destination_key = "stalking_target"
|
||||||
|
metadata/_custom_type_script = "uid://wfd5nbethyw6"
|
||||||
|
|
||||||
|
[node name="RestartStalkingTimer" type="Node" parent="GrunkBeastBehavior/StateSelector/PursuitSequence" node_paths=PackedStringArray("timer")]
|
||||||
|
script = ExtResource("16_asd50")
|
||||||
|
timer = NodePath("../../../../StalkingTimer")
|
||||||
|
metadata/_custom_type_script = "uid://ykfqlqp7e8og"
|
||||||
|
|
||||||
|
[node name="PursueTarget" type="Node" parent="GrunkBeastBehavior/StateSelector/PursuitSequence"]
|
||||||
|
script = ExtResource("14_x8l6r")
|
||||||
|
blackboard_key = "pursuit_target"
|
||||||
|
metadata/_custom_type_script = "uid://bkdwuqv4tudka"
|
||||||
|
|
||||||
|
[node name="AlwaysFailDecorator" type="Node" parent="GrunkBeastBehavior/StateSelector"]
|
||||||
|
script = ExtResource("15_oons1")
|
||||||
|
metadata/_custom_type_script = "uid://dwfdg523bk776"
|
||||||
|
|
||||||
|
[node name="ErasePursuitTarget" type="Node" parent="GrunkBeastBehavior/StateSelector/AlwaysFailDecorator"]
|
||||||
|
script = ExtResource("15_4b27i")
|
||||||
|
key = "pursuit_target"
|
||||||
|
metadata/_custom_type_script = "uid://demv7xh27ouvr"
|
||||||
|
|
||||||
|
[node name="StalkingSequence" type="Node" parent="GrunkBeastBehavior/StateSelector"]
|
||||||
|
script = ExtResource("12_xde72")
|
||||||
|
metadata/_custom_type_script = "uid://dcojdhvj8qcw0"
|
||||||
|
|
||||||
|
[node name="StalkingTimerRunning" type="Node" parent="GrunkBeastBehavior/StateSelector/StalkingSequence" node_paths=PackedStringArray("timer")]
|
||||||
|
script = ExtResource("16_oons1")
|
||||||
|
timer = NodePath("../../../../StalkingTimer")
|
||||||
|
metadata/_custom_type_script = "uid://h0cp58nswpml"
|
||||||
|
|
||||||
|
[node name="SetNavTarget" type="Node" parent="GrunkBeastBehavior/StateSelector/StalkingSequence"]
|
||||||
|
script = ExtResource("10_kjykp")
|
||||||
|
blackboard_key = "stalking_target"
|
||||||
|
metadata/_custom_type_script = "uid://u1ntpwjwjqhj"
|
||||||
|
|
||||||
|
[node name="TravelToDestination" type="Node" parent="GrunkBeastBehavior/StateSelector/StalkingSequence"]
|
||||||
|
script = ExtResource("14_4y64f")
|
||||||
|
metadata/_custom_type_script = "uid://om57w2acvgb7"
|
||||||
|
|
||||||
|
[node name="SelectorReactiveComposite" type="Node" parent="GrunkBeastBehavior/StateSelector/StalkingSequence"]
|
||||||
|
script = ExtResource("7_vvw1q")
|
||||||
|
metadata/_custom_type_script = "uid://cw22yurt5l74k"
|
||||||
|
|
||||||
|
[node name="AlwaysFailDecorator2" type="Node" parent="GrunkBeastBehavior/StateSelector"]
|
||||||
|
script = ExtResource("15_oons1")
|
||||||
|
metadata/_custom_type_script = "uid://dwfdg523bk776"
|
||||||
|
|
||||||
|
[node name="EraseStalkingTarget" type="Node" parent="GrunkBeastBehavior/StateSelector/AlwaysFailDecorator2"]
|
||||||
|
script = ExtResource("15_4b27i")
|
||||||
|
key = "stalking_target"
|
||||||
|
metadata/_custom_type_script = "uid://demv7xh27ouvr"
|
||||||
|
|
||||||
|
[node name="LurkSequence" type="Node" parent="GrunkBeastBehavior/StateSelector"]
|
||||||
|
script = ExtResource("8_0gxpq")
|
||||||
|
metadata/_custom_type_script = "uid://cg016dbe7gs1x"
|
||||||
|
|
||||||
|
[node name="RandomDelay" type="Node" parent="GrunkBeastBehavior/StateSelector/LurkSequence"]
|
||||||
|
script = ExtResource("11_mbqcc")
|
||||||
|
mean_time = 5.0
|
||||||
|
st_dev_time = 1.0
|
||||||
|
wait_time = 4.6164
|
||||||
|
metadata/_custom_type_script = "uid://beyk2xtbjrsg4"
|
||||||
|
|
||||||
|
[node name="PickRandomLurkTarget" type="Node" parent="GrunkBeastBehavior/StateSelector/LurkSequence/RandomDelay"]
|
||||||
|
script = ExtResource("12_ml8dd")
|
||||||
|
blackboard_key = "lurk_target"
|
||||||
|
group = "LurkPoint"
|
||||||
|
metadata/_custom_type_script = "uid://cg55nu4y0a5ud"
|
||||||
|
|
||||||
|
[node name="SetNavTarget" type="Node" parent="GrunkBeastBehavior/StateSelector/LurkSequence"]
|
||||||
|
script = ExtResource("10_kjykp")
|
||||||
|
blackboard_key = "lurk_target"
|
||||||
|
metadata/_custom_type_script = "uid://u1ntpwjwjqhj"
|
||||||
|
|
||||||
|
[node name="TravelToDestination" type="Node" parent="GrunkBeastBehavior/StateSelector/LurkSequence"]
|
||||||
|
script = ExtResource("14_4y64f")
|
||||||
|
metadata/_custom_type_script = "uid://om57w2acvgb7"
|
||||||
|
|
||||||
|
[node name="Blackboard" type="Node" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
script = ExtResource("7_cn3ok")
|
||||||
|
metadata/_custom_type_script = "uid://dme5f24l0edsf"
|
||||||
|
|
||||||
[connection signal="sound_detected" from="GameSoundListener" to="." method="on_sound_detected"]
|
[connection signal="sound_detected" from="GameSoundListener" to="." method="on_sound_detected"]
|
||||||
[connection signal="body_entered" from="GrabbingRange" to="." method="on_player_entered_grabbing_range"]
|
|
||||||
[connection signal="body_exited" from="PursuitLimit" to="." method="on_player_left_pursuit_range"]
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user