diff --git a/levels/ghost_ship/ghost_ship_level.tscn b/levels/ghost_ship/ghost_ship_level.tscn index 0e0e6b3..4f7c1e6 100644 --- a/levels/ghost_ship/ghost_ship_level.tscn +++ b/levels/ghost_ship/ghost_ship_level.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=232 format=4 uid="uid://crydi5cjgfwe5"] +[gd_scene load_steps=231 format=4 uid="uid://crydi5cjgfwe5"] [ext_resource type="PackedScene" uid="uid://oowut88kr2ox" path="res://levels/ghost_ship/player_ship/player_ship.tscn" id="1_2pyr1"] [ext_resource type="PackedScene" uid="uid://c2omlx4ptrc01" path="res://src/world/gunk_body/gunk_body.tscn" id="2_2egij"] @@ -81,7 +81,6 @@ [ext_resource type="PackedScene" uid="uid://h2gswdcxyotk" path="res://src/props/med_cart/med_cart.tscn" id="70_wqqoq"] [ext_resource type="Texture2D" uid="uid://cd142v5tbh10j" path="res://assets/props/railing/railing_N.png" id="71_dxmep"] [ext_resource type="Texture2D" uid="uid://tpweuhaqj3uy" path="res://assets/props/railing/railing_R.png" id="72_4akax"] -[ext_resource type="PackedScene" uid="uid://ehf5sg3ahvbf" path="res://src/world/grunk_beast/grunk_beast.tscn" id="82_rigxx"] [sub_resource type="NavigationMesh" id="NavigationMesh_vt4uw"] vertices = PackedVector3Array(-3.5, -2.00426, -89.75, -2, -2.00426, -89.75, -1.75, -2.25426, -90.25, -3.5, -2.50426, -93.25, -3.5, -2.50426, -90.9167, 3.75, -2.50426, -92.5, 3.75, -2.50426, -94.75, 2.25, -2.50426, -94.5, 3, -2.50426, -89.5, 3.75, -2.50426, -90, -0.5, -2.50426, -90, -1.5, -2.50426, -96.5, -3.5, -2.50426, -96.5, -0.5, -2.50426, -87.5, 3, -2.50426, -87.5, 0.75, -2.50426, -96.5, -2.75, 0.495737, -96.5, -3.5, 0.495737, -96.5, -3.5, 0.495737, -95.5, -2.25, 0.495737, -95.75, 3.75, 0.495737, -86.75, 3.75, 0.495737, -89.25, 2.5, 0.495737, -88.5, 3, 0.495737, -86.25, -1, 0.495737, -95.5, 0, 0.495737, -95.75, 2.5, 0.495737, -85.5, 3, 0.495737, -84, 3.75, 0.495737, -80.25, 3.75, 0.495737, -81, 3, 0.495737, -81.5, 1.75, 0.495737, -81.5, 0, 0.495737, -80.5, 3.75, 0.495737, -96.5, 2.75, 0.495737, -96.5, 2.25, 0.495737, -95.75, 2.5, 0.495737, -94.75, 3.75, 0.495737, -94.25, 1.75, 0.495737, -95.5, 2.5, 0.495737, -82.25, -1.75, 0.495737, -81.5, -3.5, 0.495737, -80.5, -3.5, -1.25426, -87.5, -2, -0.754263, -85.75, -2.25, 0.495737, -82, -3.5, 0.245737, -83, -3.5, -0.504263, -85.25, 2.5, 0.495737, -91.75, 3.75, 0.495737, -91.75, -3.5, -2.50426, -80.5, -2, -2.50426, -80.25, -1.5, -2.50426, -81, -1, -2.50426, -83.75, -3.5, -2.50426, -83.75, -0.5, -2.50426, -84.25, 0.75, -2.50426, -81, 3, -2.50426, -81, 3, -2.50426, -84.25, 0.75, 0.495737, -77.5, 0.5, 0.495737, -78.5, -0.5, 0.495737, -78.5, -0.5, 0.495737, -75.75, 0.75, 0.495737, -74.75, -0.5, 0.495737, -59.25, -0.5, 0.495737, -56.5, 0.75, 0.495737, -56.75, 0.75, 0.495737, -59.75, -1, 0.495737, -65.25, -0.5, 0.495737, -64.75, 0.75, 0.495737, -65.75, -0.5, 0.495737, -67.25, -1.25, 0.495737, -66.5, -0.5, 0.495737, -73, 0.75, 0.495737, -71.75, -4.25, 0.495737, -66.5, -7, 0.495737, -66.5, -6.75, 0.495737, -65.25, -4, 0.495737, -65.25, -0.5, 0.495737, -70.25, 0.75, 0.495737, -68.75, 0.75, 0.495737, -62.75, -0.5, 0.495737, -62, -9.75, 0.495737, -66.5, -12.5, 0.495737, -66.5, -12.5, 0.495737, -65.25, -9.75, 0.495737, -65.25, -0.5, 0.495737, -53.5, 0.75, 0.495737, -53.75, -21.75, 0.495737, -71, -20.25, 0.495737, -71, -20.25, 0.495737, -73.25, -25, 0.495737, -72.75, -24.5, 0.495737, -71.25, -20.25, 0.495737, -75.5, -24, 0.495737, -75.5, -27.5, 0.495737, -75.5, -27.5, 0.495737, -72.75, -15.5, 0.495737, -73.25, -15.5, 0.495737, -71, -14, 0.495737, -71, -11.25, 0.495737, -71.25, -10.75, 0.495737, -72.75, -12, 0.495737, -75.5, -15.5, 0.495737, -75.5, -8.25, 0.495737, -72.75, -8.25, 0.495737, -75.5, -21.5, 0.495737, -61.5, -20.25, 0.495737, -61.25, -19.75, 0.495737, -62.25, -21.5, 0.495737, -64, -16, 0.495737, -62.25, -15.5, 0.495737, -61.25, -14.25, 0.495737, -61.5, -14.5, 0.495737, -64.25, -21.5, 0.495737, -69, -20.25, 0.495737, -69, -18.75, 0.495737, -65.25, -17.25, 0.495737, -65.25, -19.5, 0.495737, -68.5, -21.5, 0.495737, -66.5, -19.75, 0.495737, -66.25, -14.5, 0.495737, -67.75, -15.75, 0.495737, -69, -16.5, 0.495737, -68.5, -16.25, 0.495737, -66.25, -26.25, 0.495737, -65.25, -23.5, 0.495737, -65.5, -23.5, 0.495737, -66.5, -26.75, 0.495737, -66.5, -36.5, 0.495737, -56.5, -36.5, 0.495737, -53.5, -35.25, 0.495737, -53.5, -35.25, 0.495737, -56.75, -36.25, 0.495737, -57.25, -29, 0.495737, -65.25, -29.75, 0.495737, -66.5, -36.5, 0.495737, -59.25, -36.25, 0.495737, -59.5, -32, 0.495737, -65.25, -32.75, 0.495737, -66.5, -35.25, 0.495737, -60, -35.25, 0.495737, -62.5, -36.5, 0.495737, -62.25, -34.75, 0.495737, -65.25, -35.75, 0.495737, -66.5, -35.75, 0.495737, -65.5, -36.5, 0.495737, -65, -35.25, 0.495737, -64.75, -22.25, 0.495737, -60.5, -20.25, 0.495737, -58.75, -25, 0.495737, -59.25, -27.5, 0.495737, -59.25, -27.5, 0.495737, -56.25, -24, 0.495737, -56.25, -24.5, 0.495737, -60.5, -20.25, 0.495737, -56.25, -13.75, 0.495737, -60.5, -15.5, 0.495737, -58.75, -8.25, 0.495737, -56.25, -8.25, 0.495737, -59.25, -10.75, 0.495737, -59.25, -12, 0.495737, -56.25, -11.25, 0.495737, -60.5, -15.5, 0.495737, -56.25, 0.75, 0.495737, -52, -0.5, 0.495737, -34.75, -0.5, 0.495737, -32.5, 0.75, 0.495737, -32.5, 0.75, 0.495737, -34.75, 0.75, 0.495737, -47.75, -0.5, 0.495737, -49.5, -0.5, 0.495737, -45.5, 0.75, 0.495737, -45.5, -1, 0.495737, -35.25, 0.75, 0.495737, -37, -0.5, 0.495737, -37.25, -1.25, 0.495737, -36.5, 0.75, 0.495737, -39.25, -0.5, 0.495737, -39.5, 1.25, 0.495737, -50.25, 3.5, 0.495737, -50.25, 3.5, 0.495737, -51.5, 1.25, 0.495737, -51.5, 0.75, 0.495737, -43.5, -0.5, 0.495737, -41.5, 0.75, 0.495737, -49.75, 0.75, 0.495737, -41.25, -4, 0.495737, -36.5, -6.5, 0.495737, -36.5, -6.5, 0.495737, -35.25, -3.75, 0.495737, -35.25, -26.25, 0.495737, -44.5, -24.25, 0.495737, -44.25, -24.25, 0.495737, -44.75, -27.5, 0.745737, -46.25, -28.5, 0.745737, -44.5, -24.5, 0.495737, -46.25, -27.5, 0.495737, -51.5, -28.75, 0.495737, -50.5, -26.75, 0.495737, -50.25, -24.5, 0.495737, -50.25, -23.5, 0.495737, -51.5, -31.5, 0.495737, -51.5, -31.5, 0.745737, -50.5, -23.25, 0.495737, -45.25, -24, 0.495737, -46.75, -32.75, 0.745737, -48.5, -33.75, 0.495737, -46.5, -32, 0.495737, -45.5, -30.5, 0.745737, -48, -24, 0.495737, -49.75, -23.25, 0.495737, -48.5, -35, 0.495737, -45, -35.25, 0.495737, -44.25, -32, 0.495737, -44.25, -35.75, 0.495737, -45, -36.25, 0.745737, -49.25, -35, 0.745737, -51.5, -38.5, 0.495737, -51.5, -38.5, 0.495737, -47.75, -37.5, 0.745737, -47.25, -37.5, 0.495737, -46.25, -38.25, 0.495737, -44.25, -13.5, 0.495737, -37.75, -14.5, 0.495737, -37.75, -14.5, 0.495737, -36.75, -13.25, 0.495737, -36.25, -12.75, 0.495737, -36.5, -21.5, 0.495737, -51.5, -21.5, 0.495737, -50.25, -18.25, 0.495737, -50.25, -18, 0.495737, -51.5, -10.25, 0.495737, -41, -10.5, 0.495737, -37.25, -9.25, 0.495737, -37.5, -9.25, 0.495737, -41, -13.25, 0.495737, -35.25, -10.75, 0.495737, -35.25, -11.25, 0.495737, -36.5, -9.75, 0.495737, -49, -8.25, 0.495737, -49, -8.25, 0.495737, -50.5, -10.75, 0.495737, -50.25, -8.5, 0.495737, -35.5, -8.5, 0.495737, -37, -8.25, 0.495737, -41.25, -8.25, 0.495737, -44, -9.25, 0.495737, -41.75, -9.25, 0.495737, -44.5, -10.25, 0.495737, -43.75, -9.25, 0.495737, -42.5, -15, 0.495737, -50.5, -14.25, 0.495737, -51.5, -15, 0.495737, -41, -14, 0.495737, -40.25, -12.75, 0.495737, -42, -14.5, 0.495737, -43.25, -9.25, 0.495737, -46.25, -11, 0.495737, -46.25, -11.5, 0.495737, -43.75, -13.75, 0.495737, -50.5, -14.5, 0.495737, -50, -11, 0.495737, -50.5, -11.75, 0.495737, -50.25, -12.75, 0.495737, -48, -12.75, 0.495737, -49.25, -14.5, 0.495737, -46.75, -0.25, 0.495737, -29.5, 0.75, 0.495737, -30, 0.75, 0.495737, -30.5, -1.5, 0.495737, -30.5, -1, 0.495737, -29.25, -10.5, 0.495737, -30.5, -12.75, 0.495737, -30.5, -13, 0.495737, -29.25, -10, 0.495737, -29.25, -26.25, 0.495737, -41.25, -26.5, 0.495737, -42.5, -27.5, 0.495737, -42.5, -27.5, 0.495737, -39.25, -26.25, 0.495737, -38.75, -6, 0.495737, -30.5, -8.25, 0.495737, -30.5, -7, 0.495737, -29.25, 0, 0.495737, -25.25, -0.25, 0.495737, -27.25, -0.5, 0.495737, -26, -0.5, 0.495737, -23.25, -27.5, 0.495737, -32.75, -27.5, 0.495737, -29.25, -26.75, 0.495737, -30.25, -26.25, 0.495737, -31, -26.25, 0.495737, -33.75, -27.5, 0.495737, -36, -26.25, 0.495737, -36.25, -0.5, 0.495737, -20.5, -0.5, 0.495737, -17.5, 0.75, 0.495737, -17.5, 0.75, 0.495737, -21.25, -4, 0.495737, -29.25, -3.75, 0.495737, -30.5, -0.5, 0.495737, -28.75, 0.75, 0.495737, -24.75, -25.75, 0.495737, -30.5, -25.5, 0.495737, -30.25, -23, 0.495737, -30.5, -17, 0.495737, -30.5, -18, 0.495737, -29.5, -16, 0.495737, -29.25, -15, 0.495737, -30.5, -24.75, 0.495737, -29.25, -22, 0.495737, -29.25, -19.75, 0.495737, -29.5, -20.25, 0.495737, -30.5, -19, 0.495737, -29.25, -3, 0.495737, -12.5, -3.5, 0.495737, -12.25, -3, 0.495737, -11.5, -1.25, 0.495737, -9, -3.5, 0.495737, -15.5, -3.5, 0.495737, -14.75, -3, 0.495737, -14.5, 0, 0.495737, -15.5, 3, 0.495737, -14.5, 3.75, 0.495737, -15, 3.75, 0.495737, -15.5, -0.75, 0.495737, -8.25, 0.75, 0.495737, -8.25, 2.25, 0.495737, -9.5, 2.25, 0.495737, -10.25, 3.5, 0.495737, -11.75, 3, 0.495737, -12.5, -3, 0.495737, -9.25) @@ -5039,9 +5038,6 @@ metadata/_custom_type_script = "uid://cvx514gdjd5ev" [node name="CargoBay" type="Node3D" parent="BeastNav"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 12, -12, -60) -[node name="GrunkBeast" parent="." instance=ExtResource("82_rigxx")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, -51) - [node name="LurkPoints" type="Node3D" parent="."] [node name="LurkPoint" type="Marker3D" parent="LurkPoints" groups=["LurkPoint"]] @@ -5074,6 +5070,44 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6, 0, -66) [node name="LurkPoint10" type="Marker3D" parent="LurkPoints" groups=["LurkPoint"]] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -21, 0, -63) +[node name="BeastSpawns" type="Node3D" parent="."] + +[node name="BeastSpawnPoint" type="Marker3D" parent="BeastSpawns" groups=["BeastSpawnPoint"]] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6, 1.5, -36) + +[node name="BeastSpawnPoint2" type="Marker3D" parent="BeastSpawns" groups=["BeastSpawnPoint"]] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, -36) + +[node name="BeastSpawnPoint3" type="Marker3D" parent="BeastSpawns" groups=["BeastSpawnPoint"]] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, -51) + +[node name="BeastSpawnPoint4" type="Marker3D" parent="BeastSpawns" groups=["BeastSpawnPoint"]] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 1.5, -51) + +[node name="BeastSpawnPoint5" type="Marker3D" parent="BeastSpawns" groups=["BeastSpawnPoint"]] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, -66) + +[node name="BeastSpawnPoint6" type="Marker3D" parent="BeastSpawns" groups=["BeastSpawnPoint"]] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12, 1.5, -66) + +[node name="BeastSpawnPoint7" type="Marker3D" parent="BeastSpawns" groups=["BeastSpawnPoint"]] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6, 1.5, -66) + +[node name="BeastSpawnPoint8" type="Marker3D" parent="BeastSpawns" groups=["BeastSpawnPoint"]] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, -78) + +[node name="BeastSpawnPoint9" type="Marker3D" parent="BeastSpawns" groups=["BeastSpawnPoint"]] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, -57) + +[node name="BeastSpawnPoint10" type="Marker3D" parent="BeastSpawns" groups=["BeastSpawnPoint"]] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, -42) + +[node name="BeastSpawnPoint11" type="Marker3D" parent="BeastSpawns" groups=["BeastSpawnPoint"]] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12, 1.5, -45) + +[node name="BeastSpawnPoint12" type="Marker3D" parent="BeastSpawns" groups=["BeastSpawnPoint"]] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -9, 1.5, -57) + [connection signal="activated" from="BeastNav/Airlock/Bounds/FarWall/SwitchA1" to="BeastNav/Airlock/Bounds/FarWall/SwitchA1" method="disable"] [connection signal="activated" from="BeastNav/Airlock/Bounds/FarWall/SwitchA1" to="BeastNav/BulkheadA" method="open"] [connection signal="activated" from="BeastNav/Airlock/Bounds/FarWall/SwitchA1" to="BeastNav/Corridor1/Hallway1/SwitchA2" method="disable"] diff --git a/project.godot b/project.godot index 2422925..ea3542e 100644 --- a/project.godot +++ b/project.godot @@ -85,6 +85,8 @@ MetalMaterial="This surface is made of metal." PlasticMaterial="This surface is made of plastic." MeetSpookSource="meet-spook event sources" LurkPoint="Point which a lurking beast may wander to." +BeastSpawnPoint="Spawn point for a grunkbeast" +GrunkBeast="GrunkBeast instances." [importer_defaults] diff --git a/src/util/scene_tools.gd b/src/util/scene_tools.gd index de14360..75a57c9 100644 --- a/src/util/scene_tools.gd +++ b/src/util/scene_tools.gd @@ -1,6 +1,8 @@ class_name SceneTools extends Object ## Tools for specialized operations in a scene +const RAY_MASK := 0b00100101 + ## Get the Node3D in the given group which is spatially closest to the target node. ## @@ -15,3 +17,39 @@ static func closest_in_group(target: Node3D, group_name: String) -> Node3D: min_dist_sq = dist_sq closest = n return closest + + +## Does the player have an unobstructed line-of-sight to the given point? +static func player_can_see(target: Vector3) -> bool: + if not is_instance_valid(Player.instance): + return false + + var camera := Player.instance.get_viewport().get_camera_3d() + + if not camera.is_position_in_frustum(target): + return false + + var query := PhysicsRayQueryParameters3D.create(camera.global_position, target, RAY_MASK) + # TODO may need to add an "exceptions" parameter for the source's body + var raycast := Player.instance.get_world_3d().direct_space_state.intersect_ray(query) + # If raycast is empty, view is unoccluded and player has line-of-sight! + return not raycast + + +## Get a random Node3D from the given group which is not currently visible to the player +## +## Returns null is there is no such node, either because the group is empty +## or the player can see every node in the group. +static func pick_unseen_from_group(group_name: String) -> Node3D: + if not is_instance_valid(Player.instance): + return null + + var nodes: Array[Node] = Player.instance.get_tree().get_nodes_in_group(group_name) + while nodes: + var candidate: Node = nodes.pick_random() + nodes.erase(candidate) + var target := candidate as Node3D + if target and not SceneTools.player_can_see(target.global_position): + return target + + return null diff --git a/src/world/grunk_beast/behaviors/actions/set_player_priority_target.gd b/src/world/grunk_beast/behaviors/actions/set_player_priority_target.gd new file mode 100644 index 0000000..ab7cf59 --- /dev/null +++ b/src/world/grunk_beast/behaviors/actions/set_player_priority_target.gd @@ -0,0 +1,16 @@ +@tool +class_name SetPlayerPriorityTarget extends ActionLeaf +## Set the player as a pursuit target if the grunk alert level is above a priority threshold. + +## Blackboard key to set. +@export var blackboard_key := "pursuit_target" + +## Set the player as target only if the grunk alert level is greater than or equal to this. +@export var alert_threshold := 3 + + +func tick(_actor: Node, blackboard: Blackboard) -> int: + if Game.manager.alert_level >= alert_threshold and is_instance_valid(Player.instance): + blackboard.set_value(blackboard_key, Player.instance) + return SUCCESS + return FAILURE diff --git a/src/world/grunk_beast/behaviors/actions/set_player_priority_target.gd.uid b/src/world/grunk_beast/behaviors/actions/set_player_priority_target.gd.uid new file mode 100644 index 0000000..06db8ba --- /dev/null +++ b/src/world/grunk_beast/behaviors/actions/set_player_priority_target.gd.uid @@ -0,0 +1 @@ +uid://c5cikaa68tsto diff --git a/src/world/grunk_beast/grunk_beast.gd b/src/world/grunk_beast/grunk_beast.gd index 0e6e4ee..aac8273 100644 --- a/src/world/grunk_beast/grunk_beast.gd +++ b/src/world/grunk_beast/grunk_beast.gd @@ -8,6 +8,10 @@ const STALKING_SOUND_LIMIT := 20.0 #region Exported Properties @export var base_speed := 60.0 @export var pursuit_speed := 180.0 + +@export var debug_destroy: bool: + set(value): + queue_free() #endregion #region Member Variables diff --git a/src/world/grunk_beast/grunk_beast.tscn b/src/world/grunk_beast/grunk_beast.tscn index 249d486..fd05d6e 100644 --- a/src/world/grunk_beast/grunk_beast.tscn +++ b/src/world/grunk_beast/grunk_beast.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=41 format=3 uid="uid://ehf5sg3ahvbf"] +[gd_scene load_steps=42 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="Shader" uid="uid://ckxc0ngd37rtk" path="res://src/shaders/gunk.gdshader" id="4_0gxpq"] @@ -19,6 +19,7 @@ [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://c5cikaa68tsto" path="res://src/world/grunk_beast/behaviors/actions/set_player_priority_target.gd" id="14_csisu"] [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"] @@ -102,7 +103,7 @@ radius = 3.0 [sub_resource type="SphereShape3D" id="SphereShape3D_lak6w"] radius = 10.0 -[node name="GrunkBeast" type="CharacterBody3D"] +[node name="GrunkBeast" type="CharacterBody3D" groups=["GrunkBeast"]] collision_layer = 36 script = ExtResource("2_qqnhb") @@ -124,6 +125,7 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.5, 0) [node name="NavAgent" type="NavigationAgent3D" parent="Navigation"] unique_name_in_owner = true path_postprocessing = 1 +avoidance_enabled = true debug_enabled = true [node name="NavProbe" type="NavigationAgent3D" parent="Navigation"] @@ -213,6 +215,10 @@ metadata/_custom_type_script = "uid://dcojdhvj8qcw0" script = ExtResource("12_dkcdj") metadata/_custom_type_script = "uid://8hn4kne15ac5" +[node name="SetPlayerPriorityTarget" type="Node" parent="GrunkBeastBehavior/StateSelector/PursuitSequence/TargetSelector"] +script = ExtResource("14_csisu") +metadata/_custom_type_script = "uid://c5cikaa68tsto" + [node name="TargetInPursuitRange" type="Node" parent="GrunkBeastBehavior/StateSelector/PursuitSequence/TargetSelector" node_paths=PackedStringArray("area")] script = ExtResource("9_xuag8") blackboard_key = "pursuit_target" diff --git a/src/world/meet_spook/meet_spook_mob.gd b/src/world/meet_spook/meet_spook_mob.gd index dd11084..0424bda 100644 --- a/src/world/meet_spook/meet_spook_mob.gd +++ b/src/world/meet_spook/meet_spook_mob.gd @@ -3,7 +3,6 @@ class_name MeetSpookMob extends Node3D enum State { WAITING, FREEZE, MOVING } -const RAY_MASK := 0b00100101 const BASE_SPEED := 4.0 @export var source: MeetSpook @@ -41,15 +40,8 @@ func _physics_process(delta: float) -> void: match state: State.WAITING: # Not yet seen by the player - if camera.is_position_in_frustum(global_position): - var query := PhysicsRayQueryParameters3D.create( - camera.global_position, global_position, RAY_MASK - ) - # TODO exceptions should include this mob's collision body - var raycast := get_world_3d().direct_space_state.intersect_ray(query) - if not raycast: - # Player has line-of-sight! - activate() + if SceneTools.player_can_see(global_position): + activate() State.FREEZE: # Just stand there for a sec pass diff --git a/src/world/spook_manager/spook_manager.gd b/src/world/spook_manager/spook_manager.gd index 64e9396..8c56890 100644 --- a/src/world/spook_manager/spook_manager.gd +++ b/src/world/spook_manager/spook_manager.gd @@ -1,6 +1,10 @@ class_name SpookManager extends Resource ## A strategy for handling horror elements through the level. +const SPAWN_GROUP := "BeastSpawnPoint" + +@export var grunkbeast_scene: PackedScene + var debug_set_alert_level: int: set = _on_alert_raised @@ -10,6 +14,35 @@ func _init() -> void: Game.manager.alert_cleared.connect(_on_alert_cleared) +func _spawn_beast_at_point(spawn_point: Node3D) -> void: + print_debug("Spawning active beast at ", spawn_point.global_position) + var beast: GrunkBeast = grunkbeast_scene.instantiate() + spawn_point.add_child(beast) + + +## Spawn a beast somewhere the player isn't looking. +func spawn_beast() -> void: + var spawn_point := SceneTools.pick_unseen_from_group(SPAWN_GROUP) + if not spawn_point: + print_debug("Couldn't find a hidden spawn point... Picking one at random.") + var nodes := Game.manager.get_tree().get_nodes_in_group(SPAWN_GROUP) + if not nodes: + print_debug("Oh that's why. There aren't any spawn points. Complain to a developer.") + return + spawn_point = nodes.pick_random() as Node3D + + _spawn_beast_at_point(spawn_point) + + +## Spawn beasts at _every_ spawn point the player can't see. +func spawn_many_beasts() -> void: + var nodes := Game.manager.get_tree().get_nodes_in_group(SPAWN_GROUP) + for node: Node in nodes: + var target := node as Node3D + if is_instance_valid(target) and not SceneTools.player_can_see(target.global_position): + _spawn_beast_at_point(target) + + func _on_alert_raised(new_level: int) -> void: match new_level: 0: @@ -27,15 +60,16 @@ func _on_alert_raised(new_level: int) -> void: 2: # LEVEL 2: AGGRESSIVE # Beast pursues player on sight. - pass # TODO + spawn_beast() 3: # LEVEL 3: PREDATORY # Beast pursues player relentlessly. - pass # TODO + # The logic for this behavior change is handled directly in the GrunkBeast AI. + pass 4: # LEVEL 4: SWARMING # Many beasts spawn, overwhelming the player. - pass # TODO + spawn_many_beasts() 5: # LEVEL 5: FUN # Just kill that fool! diff --git a/src/world/world.tscn b/src/world/world.tscn index 38f85d6..6cfc475 100644 --- a/src/world/world.tscn +++ b/src/world/world.tscn @@ -1,12 +1,14 @@ -[gd_scene load_steps=6 format=3 uid="uid://884jqafhtrv0"] +[gd_scene load_steps=7 format=3 uid="uid://884jqafhtrv0"] [ext_resource type="Script" uid="uid://cgqmhtemibxc5" path="res://src/world/world.gd" id="1_1k4gi"] [ext_resource type="PackedScene" uid="uid://byvjsvavbg5xe" path="res://src/ui/menus/pause_menu/pause_menu.tscn" id="2_6fy3g"] +[ext_resource type="PackedScene" uid="uid://ehf5sg3ahvbf" path="res://src/world/grunk_beast/grunk_beast.tscn" id="2_43c6p"] [ext_resource type="Script" uid="uid://bsn026pxqwkbc" path="res://src/world/spook_manager/spook_manager.gd" id="2_bsf3i"] [ext_resource type="PackedScene" uid="uid://bov4ok76woyc" path="res://levels/ghost_ship/ghost_ship.tscn" id="2_jte2u"] [sub_resource type="Resource" id="Resource_43c6p"] script = ExtResource("2_bsf3i") +grunkbeast_scene = ExtResource("2_43c6p") metadata/_custom_type_script = "uid://bsn026pxqwkbc" [node name="World" type="Node"] diff --git a/vault/TODO.md b/vault/TODO.md index c150dce..44323a6 100644 --- a/vault/TODO.md +++ b/vault/TODO.md @@ -28,7 +28,7 @@ - [x] Model - [x] Animation - [ ] Controller - - [ ] Nav/logic? + - [x] Nav/logic? - [ ] [[level.canvas|level]] - [x] level planning - [ ] [[player ship]]