Compare commits
3 commits
1dabdd0d23
...
a4e612c1d3
| Author | SHA1 | Date | |
|---|---|---|---|
| a4e612c1d3 | |||
| 0d26f30172 | |||
| 67d17074b2 |
30 changed files with 745 additions and 1105 deletions
BIN
art/exported/environment/textures/grass_olive_tile.png
Normal file
BIN
art/exported/environment/textures/grass_olive_tile.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 554 B |
|
|
@ -0,0 +1,41 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://btxhq3rdlum2"
|
||||
path.s3tc="res://.godot/imported/grass_olive_tile.png-72072a382d0948818df97773afa5493f.s3tc.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://art/exported/environment/textures/grass_olive_tile.png"
|
||||
dest_files=["res://.godot/imported/grass_olive_tile.png-72072a382d0948818df97773afa5493f.s3tc.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=true
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=0
|
||||
0
art/source/environment/textures/.gdignore
Normal file
0
art/source/environment/textures/.gdignore
Normal file
BIN
art/source/environment/textures/grass_olive_tile.xcf
Normal file
BIN
art/source/environment/textures/grass_olive_tile.xcf
Normal file
Binary file not shown.
|
|
@ -118,7 +118,7 @@ var _new_cast_press_armed: bool = true
|
|||
var _bobber_water_position: Vector3
|
||||
var _fight_start_position: Vector3
|
||||
var _cooldown_status: String = ""
|
||||
var _fishable_query_shape: SphereShape3D = SphereShape3D.new()
|
||||
var _fishable_query_shape: CylinderShape3D = CylinderShape3D.new()
|
||||
var _fish_selector: FishSelectorType = FishSelectorType.new()
|
||||
var _selected_water_region: FishableWaterRegionType
|
||||
var _selection_context: FishingContextType
|
||||
|
|
@ -966,7 +966,7 @@ func _calculate_cast_target(distance: float) -> Vector3:
|
|||
target
|
||||
)
|
||||
if water_region != null:
|
||||
target.y = water_region.surface_height
|
||||
target.y = water_region.get_surface_height()
|
||||
_presentation.set_water_surface_height(target.y)
|
||||
else:
|
||||
_presentation.reset_water_surface_height()
|
||||
|
|
@ -982,11 +982,12 @@ func get_fishable_water_region(
|
|||
target: Vector3,
|
||||
) -> FishableWaterRegionType:
|
||||
_fishable_query_shape.radius = fishable_query_radius
|
||||
_fishable_query_shape.height = preview_ray_length
|
||||
var query := PhysicsShapeQueryParameters3D.new()
|
||||
query.shape = _fishable_query_shape
|
||||
query.transform = Transform3D(
|
||||
Basis.IDENTITY,
|
||||
Vector3(target.x, _presentation.get_water_surface_height(), target.z)
|
||||
Vector3(target.x, target.y, target.z)
|
||||
)
|
||||
query.collision_mask = fishable_surface_mask
|
||||
query.collide_with_areas = true
|
||||
|
|
|
|||
88
world/README-WORLD-AUTHORING.md
Normal file
88
world/README-WORLD-AUTHORING.md
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
# World authoring
|
||||
|
||||
The active test world uses the human-authored starter island through
|
||||
`world/regions/starter_island_region.tscn`.
|
||||
|
||||
## Active composition
|
||||
|
||||
`world/test_world.tscn` owns the gameplay-wide environment, sun, world bounds,
|
||||
and below-world failsafe. `StarterIslandRegion` owns the placed island content:
|
||||
|
||||
```text
|
||||
StarterIslandRegion
|
||||
├── Terrain
|
||||
│ ├── Visual
|
||||
│ └── Collision
|
||||
├── WaterBodies
|
||||
│ ├── Pond
|
||||
│ │ ├── VisualWater
|
||||
│ │ ├── FishingRegion
|
||||
│ │ └── RecoveryRegion
|
||||
│ └── Ocean
|
||||
│ ├── VisualWater
|
||||
│ ├── FishingRegions
|
||||
│ └── RecoveryRegions
|
||||
├── PlayerSpawn
|
||||
├── SafeRespawns
|
||||
└── Interactables
|
||||
├── FishingShopWorld
|
||||
└── PelicanCoolerPerch
|
||||
```
|
||||
|
||||
Move the meaningful feature root rather than one of its implementation
|
||||
children. Child transforms are local offsets owned by that feature.
|
||||
|
||||
## Water bodies
|
||||
|
||||
Select `WaterBodies/Pond` to move or resize the pond. Its transform is the
|
||||
authoritative surface position. The `surface_size`, fishing padding, recovery
|
||||
padding, and recovery depth properties update the visible water and gameplay
|
||||
coverage together. Fishing and recovery derive the surface height from the
|
||||
owned surface transform.
|
||||
|
||||
Select `WaterBodies/Ocean` to move the surrounding water as one feature. Its
|
||||
visual, fishing lobes, and recovery lobes use local transforms beneath the
|
||||
ocean root. The existing multi-lobe footprint remains intentionally explicit;
|
||||
changing that footprint still requires editing its owned lobe children.
|
||||
|
||||
## Placed features
|
||||
|
||||
- `PlayerSpawn` is the authoritative initial player transform. Its rotation
|
||||
controls initial facing.
|
||||
- Each marker under `SafeRespawns` is an authoritative recovery destination.
|
||||
Recovery preserves the player's current facing; marker rotation is
|
||||
intentionally not applied.
|
||||
- `Interactables/FishingShopWorld` owns the shop visual, collision,
|
||||
interaction area, prompt, and entrance marker.
|
||||
- `Interactables/PelicanCoolerPerch` owns the complete Pelican landmark visual.
|
||||
Pelican selling remains a Cooler action and has no world interaction area.
|
||||
- `Terrain` owns both the imported visual and generated terrain collision.
|
||||
- `BelowWorldFailsafe/Coverage` exposes the below-world recovery coverage as a
|
||||
saved collision shape in `world/test_world.tscn`.
|
||||
|
||||
The active `Environment`, `Sun`, and external starter-island grass material
|
||||
remain directly editable through the Inspector. Their tuning is not recreated
|
||||
by runtime scripts.
|
||||
|
||||
## Reusable world props
|
||||
|
||||
Use a single placed `WorldProp` root for trees, rocks, buildings, benches,
|
||||
signs, vegetation, and similar landmarks:
|
||||
|
||||
```text
|
||||
WorldProp
|
||||
├── Visual
|
||||
└── Collision
|
||||
└── CollisionShape3D
|
||||
```
|
||||
|
||||
Add optional interaction areas, labels, and markers beneath the same root.
|
||||
Instance imported GLB visuals beneath `Visual`; keep gameplay collision
|
||||
Godot-owned beneath `Collision`. Place and duplicate the complete prop scene,
|
||||
not its visual child.
|
||||
|
||||
Author reusable assets at scale `(1, 1, 1)`. Uniform root scaling is acceptable
|
||||
for provisional props when visual and collision scale together. Avoid
|
||||
non-uniform root scaling because it can deform collision and imported geometry
|
||||
unpredictably. Make mutable per-instance shapes, meshes, and materials local to
|
||||
the scene so editing one prop does not change unrelated instances.
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
# NETFISHING test world
|
||||
|
||||
`world/test_world.tscn` remains the active world composition. It currently
|
||||
instances `world/regions/starter_island_region.tscn`, a Godot-owned gameplay
|
||||
wrapper around the human-authored starter-island GLB.
|
||||
|
||||
## Starter-island ownership
|
||||
|
||||
```text
|
||||
TestWorld
|
||||
├── Environment
|
||||
├── Regions
|
||||
│ └── StarterIslandRegion
|
||||
│ ├── Visuals
|
||||
│ │ ├── StarterIslandModel
|
||||
│ │ ├── OceanWater
|
||||
│ │ └── PondWater
|
||||
│ ├── StaticCollision
|
||||
│ ├── FishingWater
|
||||
│ ├── WaterRecovery
|
||||
│ ├── SafeRespawns
|
||||
│ ├── PlayerSpawn
|
||||
│ └── Interactables
|
||||
├── Safety
|
||||
└── WorldBounds
|
||||
```
|
||||
|
||||
The imported GLB is visual source content and remains at identity scale. The
|
||||
wrapper creates concave static collision from its explicit mesh reference and
|
||||
owns all water, fishing, recovery, spawn, and service placement.
|
||||
|
||||
Move the complete `StarterIslandRegion` root to keep visuals and gameplay
|
||||
volumes synchronized. When editing inside the wrapper, keep each water mesh
|
||||
aligned with its matching `FishingWater` and `WaterRecovery` shapes. Safe
|
||||
respawns and `PlayerSpawn` must remain on broad upper terrain.
|
||||
|
||||
Rename-sensitive paths:
|
||||
|
||||
- `TestWorld/Regions`
|
||||
- `TestWorld/Regions/StarterIslandRegion`
|
||||
- the NodePaths exported by `StarterIslandRegion`
|
||||
- each region's `FishingWater`, `WaterRecovery`, and `SafeRespawns` roots
|
||||
|
||||
## Reverting to the modular graybox
|
||||
|
||||
The previous region scenes remain unchanged under `world/regions/`. To restore
|
||||
the prior holdover world, restore `world/test_world.tscn` and
|
||||
`world/test_world.gd` from commit `633bbd9`, then remove the player-spawn
|
||||
composition line added to `main/main.gd`. That composition instances:
|
||||
|
||||
- `village_region.tscn`
|
||||
- `starter_pond_region.tscn`
|
||||
- `river_region.tscn`
|
||||
- `lake_region.tscn`
|
||||
- `marsh_region.tscn`
|
||||
- `coastal_dock_region.tscn`
|
||||
|
||||
No region asset needs to be reconstructed or recovered from deleted content.
|
||||
|
||||
## Water and recovery
|
||||
|
||||
The pond and surrounding ocean remain separate fishable regions using the
|
||||
existing test pool. Ocean fishing and recovery use four collision shapes so
|
||||
the raised island interior is not classified as ocean. Regional recovery is
|
||||
supplemented by `TestWorld/Safety/BelowWorldFailsafe`.
|
||||
|
||||
The pond surface is at `y=2.10`. The ocean is at `y=-0.45`, between the
|
||||
authored upper beach and submerged shelf rings. Fishable regions explicitly
|
||||
provide their surface heights to the shared fishing presentation.
|
||||
|
||||
The Fishing Shop remains a complete instanced interactable. The Pelican perch
|
||||
remains convenience signage only; Pelican selling is available through the
|
||||
Cooler from anywhere.
|
||||
24
world/below_world_failsafe.gd
Normal file
24
world/below_world_failsafe.gd
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
@tool
|
||||
class_name BelowWorldFailsafe
|
||||
extends PlayerWaterTrigger
|
||||
|
||||
@export_group("Failsafe Authoring")
|
||||
## Saved coverage volume that catches players below the playable world.
|
||||
@export_node_path("CollisionShape3D")
|
||||
var coverage_shape_path: NodePath = ^"Coverage"
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
super()
|
||||
if Engine.is_editor_hint():
|
||||
update_configuration_warnings()
|
||||
|
||||
|
||||
func _get_configuration_warnings() -> PackedStringArray:
|
||||
var warnings := PackedStringArray()
|
||||
var coverage := get_node_or_null(coverage_shape_path) as CollisionShape3D
|
||||
if coverage == null:
|
||||
warnings.append("Add the saved Coverage collision shape.")
|
||||
elif coverage.shape == null:
|
||||
warnings.append("Assign a shape to the failsafe Coverage node.")
|
||||
return warnings
|
||||
1
world/below_world_failsafe.gd.uid
Normal file
1
world/below_world_failsafe.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://b71576njgcgyw
|
||||
|
|
@ -1,9 +1,38 @@
|
|||
@tool
|
||||
class_name FishableWaterRegion
|
||||
extends Area3D
|
||||
|
||||
const FishPoolType = preload("res://fish/fish_pool.gd")
|
||||
|
||||
enum SurfaceHeightMode {
|
||||
EXPLICIT,
|
||||
PARENT_GLOBAL_Y,
|
||||
}
|
||||
|
||||
@export var location_tags: Array[StringName] = []
|
||||
@export var fish_pool: FishPoolType
|
||||
@export var selection_priority: int = 0
|
||||
@export_group("Surface")
|
||||
@export var surface_height_mode: SurfaceHeightMode = SurfaceHeightMode.EXPLICIT:
|
||||
set(value):
|
||||
surface_height_mode = value
|
||||
if Engine.is_editor_hint():
|
||||
notify_property_list_changed()
|
||||
## Legacy explicit height used when Surface Height Mode is Explicit.
|
||||
@export var surface_height: float = 0.3
|
||||
|
||||
|
||||
func get_surface_height() -> float:
|
||||
if surface_height_mode == SurfaceHeightMode.PARENT_GLOBAL_Y:
|
||||
var surface_owner := get_parent() as Node3D
|
||||
if surface_owner != null:
|
||||
return surface_owner.global_position.y
|
||||
return surface_height
|
||||
|
||||
|
||||
func _validate_property(property: Dictionary) -> void:
|
||||
if (
|
||||
property.name == "surface_height"
|
||||
and surface_height_mode == SurfaceHeightMode.PARENT_GLOBAL_Y
|
||||
):
|
||||
property.usage = int(property.usage) & ~PROPERTY_USAGE_EDITOR
|
||||
|
|
|
|||
|
|
@ -1,64 +1,78 @@
|
|||
[gd_scene load_steps=10 format=3]
|
||||
[gd_scene load_steps=11 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://world/fishing_shop_interaction.gd" id="1_shop"]
|
||||
[ext_resource type="Script" path="res://world/world_prop.gd" id="2_prop"]
|
||||
|
||||
[sub_resource type="BoxMesh" id="CounterMesh"]
|
||||
resource_local_to_scene = true
|
||||
size = Vector3(4.2, 1.25, 1.8)
|
||||
|
||||
[sub_resource type="BoxMesh" id="RoofMesh"]
|
||||
resource_local_to_scene = true
|
||||
size = Vector3(5.2, 0.35, 3.2)
|
||||
|
||||
[sub_resource type="BoxMesh" id="PostMesh"]
|
||||
resource_local_to_scene = true
|
||||
size = Vector3(0.28, 3.2, 0.28)
|
||||
|
||||
[sub_resource type="BoxMesh" id="BackMesh"]
|
||||
resource_local_to_scene = true
|
||||
size = Vector3(5, 2.8, 0.25)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="PrimaryMaterial"]
|
||||
resource_local_to_scene = true
|
||||
albedo_color = Color(0.12, 0.68, 0.62, 1)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="AccentMaterial"]
|
||||
resource_local_to_scene = true
|
||||
albedo_color = Color(1, 0.68, 0.18, 1)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="BackMaterial"]
|
||||
resource_local_to_scene = true
|
||||
albedo_color = Color(0.13, 0.34, 0.38, 1)
|
||||
|
||||
[sub_resource type="SphereShape3D" id="InteractionShape"]
|
||||
resource_local_to_scene = true
|
||||
radius = 3.0
|
||||
|
||||
[sub_resource type="BoxShape3D" id="CounterShape"]
|
||||
resource_local_to_scene = true
|
||||
size = Vector3(4.2, 1.25, 1.8)
|
||||
|
||||
[node name="FishingShopWorld" type="Node3D"]
|
||||
script = ExtResource("2_prop")
|
||||
collision_root_path = NodePath("Collision")
|
||||
interaction_area_path = NodePath("InteractionArea")
|
||||
entrance_marker_path = NodePath("EntranceMarker")
|
||||
|
||||
[node name="Visuals" type="Node3D" parent="."]
|
||||
[node name="Visual" type="Node3D" parent="."]
|
||||
|
||||
[node name="Counter" type="MeshInstance3D" parent="Visuals"]
|
||||
[node name="Counter" type="MeshInstance3D" parent="Visual"]
|
||||
position = Vector3(0, 0.625, 0)
|
||||
mesh = SubResource("CounterMesh")
|
||||
material_override = SubResource("PrimaryMaterial")
|
||||
|
||||
[node name="Back" type="MeshInstance3D" parent="Visuals"]
|
||||
[node name="Back" type="MeshInstance3D" parent="Visual"]
|
||||
position = Vector3(0, 1.4, 1.25)
|
||||
mesh = SubResource("BackMesh")
|
||||
material_override = SubResource("BackMaterial")
|
||||
|
||||
[node name="Roof" type="MeshInstance3D" parent="Visuals"]
|
||||
[node name="Roof" type="MeshInstance3D" parent="Visual"]
|
||||
position = Vector3(0, 3.15, 0.35)
|
||||
mesh = SubResource("RoofMesh")
|
||||
material_override = SubResource("AccentMaterial")
|
||||
|
||||
[node name="WestPost" type="MeshInstance3D" parent="Visuals"]
|
||||
[node name="WestPost" type="MeshInstance3D" parent="Visual"]
|
||||
position = Vector3(-2.15, 1.6, -0.8)
|
||||
mesh = SubResource("PostMesh")
|
||||
material_override = SubResource("PrimaryMaterial")
|
||||
|
||||
[node name="EastPost" type="MeshInstance3D" parent="Visuals"]
|
||||
[node name="EastPost" type="MeshInstance3D" parent="Visual"]
|
||||
position = Vector3(2.15, 1.6, -0.8)
|
||||
mesh = SubResource("PostMesh")
|
||||
material_override = SubResource("PrimaryMaterial")
|
||||
|
||||
[node name="ShopName" type="Label3D" parent="Visuals"]
|
||||
[node name="ShopName" type="Label3D" parent="Visual"]
|
||||
position = Vector3(0, 3.7, 0)
|
||||
text = "fishing shop"
|
||||
font_size = 42
|
||||
|
|
@ -66,18 +80,21 @@ outline_size = 9
|
|||
billboard = 1
|
||||
no_depth_test = true
|
||||
|
||||
[node name="StaticCollision" type="StaticBody3D" parent="."]
|
||||
[node name="Collision" type="StaticBody3D" parent="."]
|
||||
|
||||
[node name="CounterShape" type="CollisionShape3D" parent="StaticCollision"]
|
||||
[node name="CounterShape" type="CollisionShape3D" parent="Collision"]
|
||||
position = Vector3(0, 0.625, 0)
|
||||
shape = SubResource("CounterShape")
|
||||
|
||||
[node name="FishingShopInteraction" type="Area3D" parent="."]
|
||||
[node name="InteractionArea" type="Area3D" parent="."]
|
||||
unique_name_in_owner = true
|
||||
position = Vector3(0, 1, -0.3)
|
||||
collision_layer = 0
|
||||
collision_mask = 2
|
||||
script = ExtResource("1_shop")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="FishingShopInteraction"]
|
||||
[node name="InteractionShape" type="CollisionShape3D" parent="InteractionArea"]
|
||||
shape = SubResource("InteractionShape")
|
||||
|
||||
[node name="EntranceMarker" type="Marker3D" parent="."]
|
||||
position = Vector3(0, 0, -2)
|
||||
|
|
|
|||
|
|
@ -1,39 +1,46 @@
|
|||
[gd_scene load_steps=5 format=3]
|
||||
[gd_scene load_steps=6 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://world/world_prop.gd" id="1_prop"]
|
||||
|
||||
[sub_resource type="BoxMesh" id="PerchMesh"]
|
||||
resource_local_to_scene = true
|
||||
size = Vector3(5, 0.7, 2.2)
|
||||
|
||||
[sub_resource type="CylinderMesh" id="PostMesh"]
|
||||
resource_local_to_scene = true
|
||||
top_radius = 0.18
|
||||
bottom_radius = 0.24
|
||||
height = 2.5
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="WoodMaterial"]
|
||||
resource_local_to_scene = true
|
||||
albedo_color = Color(0.46, 0.28, 0.13, 1)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="SignMaterial"]
|
||||
resource_local_to_scene = true
|
||||
albedo_color = Color(0.95, 0.82, 0.42, 1)
|
||||
|
||||
[node name="PelicanCoolerPerch" type="Node3D"]
|
||||
script = ExtResource("1_prop")
|
||||
|
||||
[node name="Visuals" type="Node3D" parent="."]
|
||||
[node name="Visual" type="Node3D" parent="."]
|
||||
|
||||
[node name="Perch" type="MeshInstance3D" parent="Visuals"]
|
||||
[node name="Perch" type="MeshInstance3D" parent="Visual"]
|
||||
position = Vector3(0, 1.65, 0)
|
||||
mesh = SubResource("PerchMesh")
|
||||
material_override = SubResource("WoodMaterial")
|
||||
|
||||
[node name="WestPost" type="MeshInstance3D" parent="Visuals"]
|
||||
[node name="WestPost" type="MeshInstance3D" parent="Visual"]
|
||||
position = Vector3(-1.8, 0.7, 0)
|
||||
mesh = SubResource("PostMesh")
|
||||
material_override = SubResource("WoodMaterial")
|
||||
|
||||
[node name="EastPost" type="MeshInstance3D" parent="Visuals"]
|
||||
[node name="EastPost" type="MeshInstance3D" parent="Visual"]
|
||||
position = Vector3(1.8, 0.7, 0)
|
||||
mesh = SubResource("PostMesh")
|
||||
material_override = SubResource("WoodMaterial")
|
||||
|
||||
[node name="Sign" type="Label3D" parent="Visuals"]
|
||||
[node name="Sign" type="Label3D" parent="Visual"]
|
||||
position = Vector3(0, 2.55, 0)
|
||||
text = "sell to pelicans\nfrom the cooler"
|
||||
font_size = 30
|
||||
|
|
@ -41,7 +48,7 @@ outline_size = 8
|
|||
billboard = 1
|
||||
no_depth_test = true
|
||||
|
||||
[node name="ConvenienceLabel" type="Label3D" parent="Visuals"]
|
||||
[node name="ConvenienceLabel" type="Label3D" parent="Visual"]
|
||||
position = Vector3(0, 1.65, -1.15)
|
||||
text = "available anywhere • 0.25x"
|
||||
font_size = 20
|
||||
|
|
|
|||
10
world/materials/starter_island_grass.tres
Normal file
10
world/materials/starter_island_grass.tres
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[gd_resource type="StandardMaterial3D" load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Texture2D" path="res://art/exported/environment/textures/grass_olive_tile.png" id="1_texture"]
|
||||
|
||||
[resource]
|
||||
resource_name = "Starter Island Grass"
|
||||
texture_filter = 4
|
||||
albedo_texture = ExtResource("1_texture")
|
||||
roughness = 1.0
|
||||
uv1_scale = Vector3(21.406, 21.406, 21.406)
|
||||
|
|
@ -1,9 +1,24 @@
|
|||
@tool
|
||||
class_name PlayerWaterTrigger
|
||||
extends Area3D
|
||||
|
||||
signal recovery_requested(player: Player, surface_height: float)
|
||||
|
||||
enum SurfaceHeightMode {
|
||||
EXPLICIT,
|
||||
PARENT_GLOBAL_Y,
|
||||
}
|
||||
|
||||
@export_group("Surface")
|
||||
@export var surface_height_mode: SurfaceHeightMode = SurfaceHeightMode.EXPLICIT:
|
||||
set(value):
|
||||
surface_height_mode = value
|
||||
if Engine.is_editor_hint():
|
||||
notify_property_list_changed()
|
||||
## Legacy explicit height used when Surface Height Mode is Explicit.
|
||||
@export var surface_height: float = 0.2
|
||||
@export_group("Recovery Trigger")
|
||||
## Recovery begins when the player's body center reaches this depth.
|
||||
@export_range(0.0, 2.0, 0.05) var entry_depth_threshold: float = 0.35
|
||||
|
||||
var _tracked_players: Array[Player] = []
|
||||
|
|
@ -11,11 +26,15 @@ var _triggered_players: Dictionary[StringName, bool] = {}
|
|||
|
||||
|
||||
func _ready() -> void:
|
||||
if Engine.is_editor_hint():
|
||||
set_physics_process(false)
|
||||
return
|
||||
body_entered.connect(_on_body_entered)
|
||||
body_exited.connect(_on_body_exited)
|
||||
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
var active_surface_height: float = get_surface_height()
|
||||
for player: Player in _tracked_players.duplicate():
|
||||
if not is_instance_valid(player):
|
||||
_tracked_players.erase(player)
|
||||
|
|
@ -25,10 +44,26 @@ func _physics_process(_delta: float) -> void:
|
|||
continue
|
||||
if (
|
||||
player.get_body_center_position().y
|
||||
<= surface_height - entry_depth_threshold
|
||||
<= active_surface_height - entry_depth_threshold
|
||||
):
|
||||
_triggered_players[player_key] = true
|
||||
recovery_requested.emit(player, surface_height)
|
||||
recovery_requested.emit(player, active_surface_height)
|
||||
|
||||
|
||||
func get_surface_height() -> float:
|
||||
if surface_height_mode == SurfaceHeightMode.PARENT_GLOBAL_Y:
|
||||
var surface_owner := get_parent() as Node3D
|
||||
if surface_owner != null:
|
||||
return surface_owner.global_position.y
|
||||
return surface_height
|
||||
|
||||
|
||||
func _validate_property(property: Dictionary) -> void:
|
||||
if (
|
||||
property.name == "surface_height"
|
||||
and surface_height_mode == SurfaceHeightMode.PARENT_GLOBAL_Y
|
||||
):
|
||||
property.usage = int(property.usage) & ~PROPERTY_USAGE_EDITOR
|
||||
|
||||
|
||||
func _on_body_entered(body: Node3D) -> void:
|
||||
|
|
|
|||
|
|
@ -1,140 +0,0 @@
|
|||
[gd_scene load_steps=21 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://world/regions/graybox_region.gd" id="1_region"]
|
||||
[ext_resource type="Script" path="res://world/fishable_water_region.gd" id="2_water"]
|
||||
[ext_resource type="Resource" path="res://fish/pools/test_water_pool.tres" id="3_pool"]
|
||||
[ext_resource type="Script" path="res://world/player_water_trigger.gd" id="4_trigger"]
|
||||
[ext_resource type="Script" path="res://world/safe_respawn_point.gd" id="5_safe"]
|
||||
|
||||
[sub_resource type="BoxShape3D" id="ShoreShape"]
|
||||
size = Vector3(90, 6, 18)
|
||||
[sub_resource type="BoxMesh" id="ShoreMesh"]
|
||||
size = Vector3(90, 6, 18)
|
||||
[sub_resource type="BoxShape3D" id="DockShape"]
|
||||
size = Vector3(7, 0.4, 25)
|
||||
[sub_resource type="BoxMesh" id="DockMesh"]
|
||||
size = Vector3(7, 0.4, 25)
|
||||
[sub_resource type="BoxShape3D" id="DockRampShape"]
|
||||
size = Vector3(7, 0.35, 4)
|
||||
[sub_resource type="BoxMesh" id="DockRampMesh"]
|
||||
size = Vector3(7, 0.35, 4)
|
||||
[sub_resource type="CylinderMesh" id="TowerMesh"]
|
||||
top_radius = 2.4
|
||||
bottom_radius = 3.4
|
||||
height = 13
|
||||
[sub_resource type="CylinderMesh" id="BeaconMesh"]
|
||||
top_radius = 1.4
|
||||
bottom_radius = 1.4
|
||||
height = 2.5
|
||||
[sub_resource type="BoxMesh" id="CraneArmMesh"]
|
||||
size = Vector3(1, 1, 10)
|
||||
[sub_resource type="PlaneMesh" id="WaterMesh"]
|
||||
size = Vector2(90, 54)
|
||||
[sub_resource type="BoxShape3D" id="WaterShape"]
|
||||
size = Vector3(90, 0.2, 54)
|
||||
[sub_resource type="BoxShape3D" id="RecoveryShape"]
|
||||
size = Vector3(90, 5, 54)
|
||||
[sub_resource type="StandardMaterial3D" id="ShoreMaterial"]
|
||||
albedo_color = Color(0.7, 0.66, 0.5, 1)
|
||||
[sub_resource type="StandardMaterial3D" id="DockMaterial"]
|
||||
albedo_color = Color(0.58, 0.4, 0.2, 1)
|
||||
[sub_resource type="StandardMaterial3D" id="TowerMaterial"]
|
||||
albedo_color = Color(0.92, 0.9, 0.76, 1)
|
||||
[sub_resource type="StandardMaterial3D" id="BeaconMaterial"]
|
||||
albedo_color = Color(0.95, 0.28, 0.22, 1)
|
||||
[sub_resource type="StandardMaterial3D" id="WaterMaterial"]
|
||||
transparency = 1
|
||||
albedo_color = Color(0.04, 0.3, 0.62, 0.84)
|
||||
|
||||
[node name="CoastalDockRegion" type="Node3D"]
|
||||
script = ExtResource("1_region")
|
||||
region_id = &"coast"
|
||||
[node name="Visuals" type="Node3D" parent="."]
|
||||
[node name="Shore" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(0, -3, 22)
|
||||
mesh = SubResource("ShoreMesh")
|
||||
material_override = SubResource("ShoreMaterial")
|
||||
[node name="Ocean" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(0, 0.2, -14)
|
||||
mesh = SubResource("WaterMesh")
|
||||
material_override = SubResource("WaterMaterial")
|
||||
[node name="MainDock" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(0, 0.45, -3.5)
|
||||
mesh = SubResource("DockMesh")
|
||||
material_override = SubResource("DockMaterial")
|
||||
[node name="DockApproachRamp" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(0, 0.155, 11)
|
||||
rotation_degrees = Vector3(9, 0, 0)
|
||||
mesh = SubResource("DockRampMesh")
|
||||
material_override = SubResource("DockMaterial")
|
||||
[node name="Lighthouse" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(-32, 6.5, 20)
|
||||
mesh = SubResource("TowerMesh")
|
||||
material_override = SubResource("TowerMaterial")
|
||||
[node name="Beacon" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(-32, 14, 20)
|
||||
mesh = SubResource("BeaconMesh")
|
||||
material_override = SubResource("BeaconMaterial")
|
||||
[node name="CraneArm" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(17, 5, 19)
|
||||
rotation_degrees = Vector3(0, 0, 60)
|
||||
mesh = SubResource("CraneArmMesh")
|
||||
material_override = SubResource("BeaconMaterial")
|
||||
[node name="CoastLabel" type="Label3D" parent="Visuals"]
|
||||
position = Vector3(25, 3.2, 23)
|
||||
text = "coast"
|
||||
font_size = 38
|
||||
outline_size = 8
|
||||
billboard = 1
|
||||
no_depth_test = true
|
||||
|
||||
[node name="StaticCollision" type="Node3D" parent="."]
|
||||
[node name="Shore" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/Shore"]
|
||||
position = Vector3(0, -3, 22)
|
||||
shape = SubResource("ShoreShape")
|
||||
[node name="MainDock" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/MainDock"]
|
||||
position = Vector3(0, 0.45, -3.5)
|
||||
shape = SubResource("DockShape")
|
||||
[node name="DockApproachRamp" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/DockApproachRamp"]
|
||||
position = Vector3(0, 0.155, 11)
|
||||
rotation_degrees = Vector3(9, 0, 0)
|
||||
shape = SubResource("DockRampShape")
|
||||
|
||||
[node name="FishingWater" type="Node3D" parent="."]
|
||||
[node name="CoastalWater" type="Area3D" parent="FishingWater"]
|
||||
position = Vector3(0, 0.2, -14)
|
||||
collision_layer = 4
|
||||
collision_mask = 0
|
||||
monitoring = false
|
||||
script = ExtResource("2_water")
|
||||
location_tags = Array[StringName]([&"coast"])
|
||||
fish_pool = ExtResource("3_pool")
|
||||
[node name="Shape" type="CollisionShape3D" parent="FishingWater/CoastalWater"]
|
||||
shape = SubResource("WaterShape")
|
||||
|
||||
[node name="WaterRecovery" type="Node3D" parent="."]
|
||||
[node name="CoastalRecovery" type="Area3D" parent="WaterRecovery"]
|
||||
position = Vector3(0, -2.3, -14)
|
||||
collision_layer = 8
|
||||
collision_mask = 2
|
||||
script = ExtResource("4_trigger")
|
||||
surface_height = 0.2
|
||||
[node name="Shape" type="CollisionShape3D" parent="WaterRecovery/CoastalRecovery"]
|
||||
shape = SubResource("RecoveryShape")
|
||||
|
||||
[node name="SafeRespawns" type="Node3D" parent="."]
|
||||
[node name="DockApproach" type="Marker3D" parent="SafeRespawns"]
|
||||
position = Vector3(8, 0.58, 23)
|
||||
rotation_degrees = Vector3(0, 180, 0)
|
||||
script = ExtResource("5_safe")
|
||||
[node name="DockMidpoint" type="Marker3D" parent="SafeRespawns"]
|
||||
position = Vector3(0, 1.23, 0)
|
||||
rotation_degrees = Vector3(0, 180, 0)
|
||||
script = ExtResource("5_safe")
|
||||
[node name="LighthouseShore" type="Marker3D" parent="SafeRespawns"]
|
||||
position = Vector3(-24, 0.58, 24)
|
||||
rotation_degrees = Vector3(0, -135, 0)
|
||||
script = ExtResource("5_safe")
|
||||
|
|
@ -1,141 +0,0 @@
|
|||
[gd_scene load_steps=17 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://world/regions/graybox_region.gd" id="1_region"]
|
||||
[ext_resource type="Script" path="res://world/fishable_water_region.gd" id="2_water"]
|
||||
[ext_resource type="Resource" path="res://fish/pools/test_water_pool.tres" id="3_pool"]
|
||||
[ext_resource type="Script" path="res://world/player_water_trigger.gd" id="4_trigger"]
|
||||
[ext_resource type="Script" path="res://world/safe_respawn_point.gd" id="5_safe"]
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BankNSShape"]
|
||||
size = Vector3(58, 6, 10)
|
||||
[sub_resource type="BoxShape3D" id="BankEWShape"]
|
||||
size = Vector3(8, 6, 36)
|
||||
[sub_resource type="BoxMesh" id="BankNSMesh"]
|
||||
size = Vector3(58, 6, 10)
|
||||
[sub_resource type="BoxMesh" id="BankEWMesh"]
|
||||
size = Vector3(8, 6, 36)
|
||||
[sub_resource type="BoxShape3D" id="DockShape"]
|
||||
size = Vector3(10, 0.4, 7)
|
||||
[sub_resource type="BoxMesh" id="DockMesh"]
|
||||
size = Vector3(10, 0.4, 7)
|
||||
[sub_resource type="BoxShape3D" id="DockRampShape"]
|
||||
size = Vector3(4, 0.35, 7)
|
||||
[sub_resource type="BoxMesh" id="DockRampMesh"]
|
||||
size = Vector3(4, 0.35, 7)
|
||||
[sub_resource type="PlaneMesh" id="WaterMesh"]
|
||||
size = Vector2(42, 36)
|
||||
[sub_resource type="BoxShape3D" id="WaterShape"]
|
||||
size = Vector3(42, 0.2, 36)
|
||||
[sub_resource type="BoxShape3D" id="RecoveryShape"]
|
||||
size = Vector3(42, 5, 36)
|
||||
[sub_resource type="StandardMaterial3D" id="GrassMaterial"]
|
||||
albedo_color = Color(0.34, 0.65, 0.3, 1)
|
||||
[sub_resource type="StandardMaterial3D" id="DockMaterial"]
|
||||
albedo_color = Color(0.55, 0.34, 0.16, 1)
|
||||
[sub_resource type="StandardMaterial3D" id="WaterMaterial"]
|
||||
transparency = 1
|
||||
albedo_color = Color(0.08, 0.43, 0.75, 0.82)
|
||||
|
||||
[node name="LakeRegion" type="Node3D"]
|
||||
script = ExtResource("1_region")
|
||||
region_id = &"lake"
|
||||
[node name="Visuals" type="Node3D" parent="."]
|
||||
[node name="NorthBank" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(0, -3, 23)
|
||||
mesh = SubResource("BankNSMesh")
|
||||
material_override = SubResource("GrassMaterial")
|
||||
[node name="SouthBank" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(0, -3, -23)
|
||||
mesh = SubResource("BankNSMesh")
|
||||
material_override = SubResource("GrassMaterial")
|
||||
[node name="WestBank" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(-25, -3, 0)
|
||||
mesh = SubResource("BankEWMesh")
|
||||
material_override = SubResource("GrassMaterial")
|
||||
[node name="EastBank" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(25, -3, 0)
|
||||
mesh = SubResource("BankEWMesh")
|
||||
material_override = SubResource("GrassMaterial")
|
||||
[node name="Water" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(0, 0.2, 0)
|
||||
mesh = SubResource("WaterMesh")
|
||||
material_override = SubResource("WaterMaterial")
|
||||
[node name="WestDock" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(-12, 0.45, 0)
|
||||
mesh = SubResource("DockMesh")
|
||||
material_override = SubResource("DockMaterial")
|
||||
[node name="WestDockRamp" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(-19, 0.155, 0)
|
||||
rotation_degrees = Vector3(0, 0, 9)
|
||||
mesh = SubResource("DockRampMesh")
|
||||
material_override = SubResource("DockMaterial")
|
||||
[node name="LakeLabel" type="Label3D" parent="Visuals"]
|
||||
position = Vector3(-25, 3, 20)
|
||||
text = "lake"
|
||||
font_size = 38
|
||||
outline_size = 8
|
||||
billboard = 1
|
||||
no_depth_test = true
|
||||
|
||||
[node name="StaticCollision" type="Node3D" parent="."]
|
||||
[node name="NorthBank" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/NorthBank"]
|
||||
position = Vector3(0, -3, 23)
|
||||
shape = SubResource("BankNSShape")
|
||||
[node name="SouthBank" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/SouthBank"]
|
||||
position = Vector3(0, -3, -23)
|
||||
shape = SubResource("BankNSShape")
|
||||
[node name="WestBank" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/WestBank"]
|
||||
position = Vector3(-25, -3, 0)
|
||||
shape = SubResource("BankEWShape")
|
||||
[node name="EastBank" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/EastBank"]
|
||||
position = Vector3(25, -3, 0)
|
||||
shape = SubResource("BankEWShape")
|
||||
[node name="WestDock" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/WestDock"]
|
||||
position = Vector3(-12, 0.45, 0)
|
||||
shape = SubResource("DockShape")
|
||||
[node name="WestDockRamp" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/WestDockRamp"]
|
||||
position = Vector3(-19, 0.155, 0)
|
||||
rotation_degrees = Vector3(0, 0, 9)
|
||||
shape = SubResource("DockRampShape")
|
||||
|
||||
[node name="FishingWater" type="Node3D" parent="."]
|
||||
[node name="LakeWater" type="Area3D" parent="FishingWater"]
|
||||
position = Vector3(0, 0.2, 0)
|
||||
collision_layer = 4
|
||||
collision_mask = 0
|
||||
monitoring = false
|
||||
script = ExtResource("2_water")
|
||||
location_tags = Array[StringName]([&"lake"])
|
||||
fish_pool = ExtResource("3_pool")
|
||||
[node name="Shape" type="CollisionShape3D" parent="FishingWater/LakeWater"]
|
||||
shape = SubResource("WaterShape")
|
||||
|
||||
[node name="WaterRecovery" type="Node3D" parent="."]
|
||||
[node name="LakeRecovery" type="Area3D" parent="WaterRecovery"]
|
||||
position = Vector3(0, -2.3, 0)
|
||||
collision_layer = 8
|
||||
collision_mask = 2
|
||||
script = ExtResource("4_trigger")
|
||||
surface_height = 0.2
|
||||
[node name="Shape" type="CollisionShape3D" parent="WaterRecovery/LakeRecovery"]
|
||||
shape = SubResource("RecoveryShape")
|
||||
|
||||
[node name="SafeRespawns" type="Node3D" parent="."]
|
||||
[node name="WestDockApproach" type="Marker3D" parent="SafeRespawns"]
|
||||
position = Vector3(-25, 0.58, 8)
|
||||
rotation_degrees = Vector3(0, -90, 0)
|
||||
script = ExtResource("5_safe")
|
||||
[node name="NorthShore" type="Marker3D" parent="SafeRespawns"]
|
||||
position = Vector3(0, 0.58, 24)
|
||||
rotation_degrees = Vector3(0, 180, 0)
|
||||
script = ExtResource("5_safe")
|
||||
[node name="SouthEastShore" type="Marker3D" parent="SafeRespawns"]
|
||||
position = Vector3(25, 0.58, -23)
|
||||
rotation_degrees = Vector3(0, 45, 0)
|
||||
script = ExtResource("5_safe")
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
[gd_scene load_steps=20 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://world/regions/graybox_region.gd" id="1_region"]
|
||||
[ext_resource type="Script" path="res://world/fishable_water_region.gd" id="2_water"]
|
||||
[ext_resource type="Resource" path="res://fish/pools/test_water_pool.tres" id="3_pool"]
|
||||
[ext_resource type="Script" path="res://world/player_water_trigger.gd" id="4_trigger"]
|
||||
[ext_resource type="Script" path="res://world/safe_respawn_point.gd" id="5_safe"]
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BankNSShape"]
|
||||
size = Vector3(50, 6, 8)
|
||||
[sub_resource type="BoxShape3D" id="BankEWShape"]
|
||||
size = Vector3(8, 6, 30)
|
||||
[sub_resource type="BoxMesh" id="BankNSMesh"]
|
||||
size = Vector3(50, 6, 8)
|
||||
[sub_resource type="BoxMesh" id="BankEWMesh"]
|
||||
size = Vector3(8, 6, 30)
|
||||
[sub_resource type="BoxShape3D" id="BoardwalkShape"]
|
||||
size = Vector3(6, 0.4, 22)
|
||||
[sub_resource type="BoxMesh" id="BoardwalkMesh"]
|
||||
size = Vector3(6, 0.4, 22)
|
||||
[sub_resource type="BoxShape3D" id="BoardwalkRampShape"]
|
||||
size = Vector3(6, 0.35, 4)
|
||||
[sub_resource type="BoxMesh" id="BoardwalkRampMesh"]
|
||||
size = Vector3(6, 0.35, 4)
|
||||
[sub_resource type="CylinderMesh" id="ReedMesh"]
|
||||
top_radius = 0.06
|
||||
bottom_radius = 0.1
|
||||
height = 2.2
|
||||
[sub_resource type="PlaneMesh" id="WaterMesh"]
|
||||
size = Vector2(38, 30)
|
||||
[sub_resource type="BoxShape3D" id="WaterShape"]
|
||||
size = Vector3(38, 0.2, 30)
|
||||
[sub_resource type="BoxShape3D" id="RecoveryShape"]
|
||||
size = Vector3(38, 5, 30)
|
||||
[sub_resource type="StandardMaterial3D" id="BankMaterial"]
|
||||
albedo_color = Color(0.38, 0.53, 0.27, 1)
|
||||
[sub_resource type="StandardMaterial3D" id="BoardwalkMaterial"]
|
||||
albedo_color = Color(0.48, 0.32, 0.18, 1)
|
||||
[sub_resource type="StandardMaterial3D" id="ReedMaterial"]
|
||||
albedo_color = Color(0.59, 0.67, 0.2, 1)
|
||||
[sub_resource type="StandardMaterial3D" id="WaterMaterial"]
|
||||
transparency = 1
|
||||
albedo_color = Color(0.1, 0.48, 0.48, 0.8)
|
||||
|
||||
[node name="MarshRegion" type="Node3D"]
|
||||
script = ExtResource("1_region")
|
||||
region_id = &"marsh"
|
||||
[node name="Visuals" type="Node3D" parent="."]
|
||||
[node name="NorthBank" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(0, -3, 19)
|
||||
mesh = SubResource("BankNSMesh")
|
||||
material_override = SubResource("BankMaterial")
|
||||
[node name="SouthBank" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(0, -3, -19)
|
||||
mesh = SubResource("BankNSMesh")
|
||||
material_override = SubResource("BankMaterial")
|
||||
[node name="WestBank" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(-23, -3, 0)
|
||||
mesh = SubResource("BankEWMesh")
|
||||
material_override = SubResource("BankMaterial")
|
||||
[node name="EastBank" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(23, -3, 0)
|
||||
mesh = SubResource("BankEWMesh")
|
||||
material_override = SubResource("BankMaterial")
|
||||
[node name="Water" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(0, 0.2, 0)
|
||||
mesh = SubResource("WaterMesh")
|
||||
material_override = SubResource("WaterMaterial")
|
||||
[node name="Boardwalk" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(0, 0.45, 0)
|
||||
mesh = SubResource("BoardwalkMesh")
|
||||
material_override = SubResource("BoardwalkMaterial")
|
||||
[node name="BoardwalkNorthRamp" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(0, 0.155, 13)
|
||||
rotation_degrees = Vector3(9, 0, 0)
|
||||
mesh = SubResource("BoardwalkRampMesh")
|
||||
material_override = SubResource("BoardwalkMaterial")
|
||||
[node name="BoardwalkSouthRamp" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(0, 0.155, -13)
|
||||
rotation_degrees = Vector3(-9, 0, 0)
|
||||
mesh = SubResource("BoardwalkRampMesh")
|
||||
material_override = SubResource("BoardwalkMaterial")
|
||||
[node name="ReedWest" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(-13, 1.1, -8)
|
||||
mesh = SubResource("ReedMesh")
|
||||
material_override = SubResource("ReedMaterial")
|
||||
[node name="ReedEast" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(12, 1.1, 7)
|
||||
mesh = SubResource("ReedMesh")
|
||||
material_override = SubResource("ReedMaterial")
|
||||
[node name="MarshLabel" type="Label3D" parent="Visuals"]
|
||||
position = Vector3(21, 3, 17)
|
||||
text = "marsh"
|
||||
font_size = 36
|
||||
outline_size = 8
|
||||
billboard = 1
|
||||
no_depth_test = true
|
||||
|
||||
[node name="StaticCollision" type="Node3D" parent="."]
|
||||
[node name="NorthBank" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/NorthBank"]
|
||||
position = Vector3(0, -3, 19)
|
||||
shape = SubResource("BankNSShape")
|
||||
[node name="SouthBank" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/SouthBank"]
|
||||
position = Vector3(0, -3, -19)
|
||||
shape = SubResource("BankNSShape")
|
||||
[node name="WestBank" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/WestBank"]
|
||||
position = Vector3(-23, -3, 0)
|
||||
shape = SubResource("BankEWShape")
|
||||
[node name="EastBank" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/EastBank"]
|
||||
position = Vector3(23, -3, 0)
|
||||
shape = SubResource("BankEWShape")
|
||||
[node name="Boardwalk" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/Boardwalk"]
|
||||
position = Vector3(0, 0.45, 0)
|
||||
shape = SubResource("BoardwalkShape")
|
||||
[node name="BoardwalkNorthRamp" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/BoardwalkNorthRamp"]
|
||||
position = Vector3(0, 0.155, 13)
|
||||
rotation_degrees = Vector3(9, 0, 0)
|
||||
shape = SubResource("BoardwalkRampShape")
|
||||
[node name="BoardwalkSouthRamp" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/BoardwalkSouthRamp"]
|
||||
position = Vector3(0, 0.155, -13)
|
||||
rotation_degrees = Vector3(-9, 0, 0)
|
||||
shape = SubResource("BoardwalkRampShape")
|
||||
|
||||
[node name="FishingWater" type="Node3D" parent="."]
|
||||
[node name="MarshWater" type="Area3D" parent="FishingWater"]
|
||||
position = Vector3(0, 0.2, 0)
|
||||
collision_layer = 4
|
||||
collision_mask = 0
|
||||
monitoring = false
|
||||
script = ExtResource("2_water")
|
||||
location_tags = Array[StringName]([&"marsh"])
|
||||
fish_pool = ExtResource("3_pool")
|
||||
[node name="Shape" type="CollisionShape3D" parent="FishingWater/MarshWater"]
|
||||
shape = SubResource("WaterShape")
|
||||
|
||||
[node name="WaterRecovery" type="Node3D" parent="."]
|
||||
[node name="MarshRecovery" type="Area3D" parent="WaterRecovery"]
|
||||
position = Vector3(0, -2.3, 0)
|
||||
collision_layer = 8
|
||||
collision_mask = 2
|
||||
script = ExtResource("4_trigger")
|
||||
surface_height = 0.2
|
||||
[node name="Shape" type="CollisionShape3D" parent="WaterRecovery/MarshRecovery"]
|
||||
shape = SubResource("RecoveryShape")
|
||||
|
||||
[node name="SafeRespawns" type="Node3D" parent="."]
|
||||
[node name="BoardwalkNorth" type="Marker3D" parent="SafeRespawns"]
|
||||
position = Vector3(8, 0.58, 19)
|
||||
rotation_degrees = Vector3(0, 180, 0)
|
||||
script = ExtResource("5_safe")
|
||||
[node name="BoardwalkSouth" type="Marker3D" parent="SafeRespawns"]
|
||||
position = Vector3(-8, 0.58, -19)
|
||||
script = ExtResource("5_safe")
|
||||
[node name="EastBank" type="Marker3D" parent="SafeRespawns"]
|
||||
position = Vector3(23, 0.58, 7)
|
||||
rotation_degrees = Vector3(0, 90, 0)
|
||||
script = ExtResource("5_safe")
|
||||
|
|
@ -1,143 +0,0 @@
|
|||
[gd_scene load_steps=19 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://world/regions/graybox_region.gd" id="1_region"]
|
||||
[ext_resource type="Script" path="res://world/fishable_water_region.gd" id="2_water"]
|
||||
[ext_resource type="Resource" path="res://fish/pools/test_water_pool.tres" id="3_pool"]
|
||||
[ext_resource type="Script" path="res://world/player_water_trigger.gd" id="4_trigger"]
|
||||
[ext_resource type="Script" path="res://world/safe_respawn_point.gd" id="5_safe"]
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BankShape"]
|
||||
size = Vector3(13, 6, 61)
|
||||
[sub_resource type="BoxMesh" id="BankMesh"]
|
||||
size = Vector3(13, 6, 61)
|
||||
[sub_resource type="BoxShape3D" id="BridgeShape"]
|
||||
size = Vector3(6, 0.4, 7)
|
||||
[sub_resource type="BoxMesh" id="BridgeMesh"]
|
||||
size = Vector3(6, 0.4, 7)
|
||||
[sub_resource type="BoxShape3D" id="BridgeRampShape"]
|
||||
size = Vector3(4, 0.35, 7)
|
||||
[sub_resource type="BoxMesh" id="BridgeRampMesh"]
|
||||
size = Vector3(4, 0.35, 7)
|
||||
[sub_resource type="BoxMesh" id="RailMesh"]
|
||||
size = Vector3(14, 0.25, 0.25)
|
||||
[sub_resource type="PlaneMesh" id="WaterMesh"]
|
||||
size = Vector2(14, 58)
|
||||
[sub_resource type="BoxShape3D" id="WaterShape"]
|
||||
size = Vector3(14, 0.2, 58)
|
||||
[sub_resource type="BoxShape3D" id="RecoveryShape"]
|
||||
size = Vector3(14, 5, 58)
|
||||
[sub_resource type="StandardMaterial3D" id="BankMaterial"]
|
||||
albedo_color = Color(0.31, 0.61, 0.37, 1)
|
||||
[sub_resource type="StandardMaterial3D" id="BridgeMaterial"]
|
||||
albedo_color = Color(0.58, 0.58, 0.54, 1)
|
||||
[sub_resource type="StandardMaterial3D" id="RailMaterial"]
|
||||
albedo_color = Color(0.3, 0.32, 0.34, 1)
|
||||
[sub_resource type="StandardMaterial3D" id="WaterMaterial"]
|
||||
transparency = 1
|
||||
albedo_color = Color(0.12, 0.48, 0.72, 0.8)
|
||||
|
||||
[node name="RiverRegion" type="Node3D"]
|
||||
script = ExtResource("1_region")
|
||||
region_id = &"river"
|
||||
[node name="Visuals" type="Node3D" parent="."]
|
||||
[node name="WestBank" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(-13.5, -3, -1.5)
|
||||
mesh = SubResource("BankMesh")
|
||||
material_override = SubResource("BankMaterial")
|
||||
[node name="EastBank" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(13.5, -3, -1.5)
|
||||
mesh = SubResource("BankMesh")
|
||||
material_override = SubResource("BankMaterial")
|
||||
[node name="Water" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(0, 0.2, 0)
|
||||
mesh = SubResource("WaterMesh")
|
||||
material_override = SubResource("WaterMaterial")
|
||||
[node name="Bridge" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(0, 0.45, 7)
|
||||
mesh = SubResource("BridgeMesh")
|
||||
material_override = SubResource("BridgeMaterial")
|
||||
[node name="WestBridgeRamp" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(-5, 0.155, 7)
|
||||
rotation_degrees = Vector3(0, 0, 9)
|
||||
mesh = SubResource("BridgeRampMesh")
|
||||
material_override = SubResource("BridgeMaterial")
|
||||
[node name="EastBridgeRamp" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(5, 0.155, 7)
|
||||
rotation_degrees = Vector3(0, 0, -9)
|
||||
mesh = SubResource("BridgeRampMesh")
|
||||
material_override = SubResource("BridgeMaterial")
|
||||
[node name="NorthRail" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(0, 1.15, 10.2)
|
||||
mesh = SubResource("RailMesh")
|
||||
material_override = SubResource("RailMaterial")
|
||||
[node name="SouthRail" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(0, 1.15, 3.8)
|
||||
mesh = SubResource("RailMesh")
|
||||
material_override = SubResource("RailMaterial")
|
||||
[node name="RiverLabel" type="Label3D" parent="Visuals"]
|
||||
position = Vector3(-16, 3, 20)
|
||||
text = "river"
|
||||
font_size = 34
|
||||
outline_size = 7
|
||||
billboard = 1
|
||||
no_depth_test = true
|
||||
|
||||
[node name="StaticCollision" type="Node3D" parent="."]
|
||||
[node name="WestBank" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/WestBank"]
|
||||
position = Vector3(-13.5, -3, -1.5)
|
||||
shape = SubResource("BankShape")
|
||||
[node name="EastBank" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/EastBank"]
|
||||
position = Vector3(13.5, -3, -1.5)
|
||||
shape = SubResource("BankShape")
|
||||
[node name="Bridge" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/Bridge"]
|
||||
position = Vector3(0, 0.45, 7)
|
||||
shape = SubResource("BridgeShape")
|
||||
[node name="WestBridgeRamp" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/WestBridgeRamp"]
|
||||
position = Vector3(-5, 0.155, 7)
|
||||
rotation_degrees = Vector3(0, 0, 9)
|
||||
shape = SubResource("BridgeRampShape")
|
||||
[node name="EastBridgeRamp" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/EastBridgeRamp"]
|
||||
position = Vector3(5, 0.155, 7)
|
||||
rotation_degrees = Vector3(0, 0, -9)
|
||||
shape = SubResource("BridgeRampShape")
|
||||
|
||||
[node name="FishingWater" type="Node3D" parent="."]
|
||||
[node name="RiverWater" type="Area3D" parent="FishingWater"]
|
||||
position = Vector3(0, 0.2, 0)
|
||||
collision_layer = 4
|
||||
collision_mask = 0
|
||||
monitoring = false
|
||||
script = ExtResource("2_water")
|
||||
location_tags = Array[StringName]([&"river"])
|
||||
fish_pool = ExtResource("3_pool")
|
||||
[node name="Shape" type="CollisionShape3D" parent="FishingWater/RiverWater"]
|
||||
shape = SubResource("WaterShape")
|
||||
|
||||
[node name="WaterRecovery" type="Node3D" parent="."]
|
||||
[node name="RiverRecovery" type="Area3D" parent="WaterRecovery"]
|
||||
position = Vector3(0, -2.3, 0)
|
||||
collision_layer = 8
|
||||
collision_mask = 2
|
||||
script = ExtResource("4_trigger")
|
||||
surface_height = 0.2
|
||||
[node name="Shape" type="CollisionShape3D" parent="WaterRecovery/RiverRecovery"]
|
||||
shape = SubResource("RecoveryShape")
|
||||
|
||||
[node name="SafeRespawns" type="Node3D" parent="."]
|
||||
[node name="BridgeWest" type="Marker3D" parent="SafeRespawns"]
|
||||
position = Vector3(-15, 0.58, 14)
|
||||
rotation_degrees = Vector3(0, -90, 0)
|
||||
script = ExtResource("5_safe")
|
||||
[node name="NorthEastBank" type="Marker3D" parent="SafeRespawns"]
|
||||
position = Vector3(14, 0.58, 24)
|
||||
rotation_degrees = Vector3(0, 90, 0)
|
||||
script = ExtResource("5_safe")
|
||||
[node name="SouthWestBank" type="Marker3D" parent="SafeRespawns"]
|
||||
position = Vector3(-14, 0.58, -25)
|
||||
rotation_degrees = Vector3(0, -90, 0)
|
||||
script = ExtResource("5_safe")
|
||||
|
|
@ -1,27 +1,41 @@
|
|||
@tool
|
||||
class_name StarterIslandRegion
|
||||
extends GrayboxRegion
|
||||
extends WorldRegion
|
||||
|
||||
const FishingShopInteractionType = preload(
|
||||
"res://world/fishing_shop_interaction.gd"
|
||||
)
|
||||
|
||||
@export var visual_mesh_path: NodePath = (
|
||||
^"Visuals/StarterIslandModel/starter_island"
|
||||
@export_group("Owned Nodes")
|
||||
@export_node_path("MeshInstance3D")
|
||||
var visual_mesh_path: NodePath = (
|
||||
^"Terrain/Visual/starter_island"
|
||||
)
|
||||
@export var terrain_collision_shape_path: NodePath = (
|
||||
^"StaticCollision/Terrain/Shape"
|
||||
@export_node_path("CollisionShape3D")
|
||||
var terrain_collision_shape_path: NodePath = (
|
||||
^"Terrain/Collision/Shape"
|
||||
)
|
||||
@export var player_spawn_path: NodePath = ^"PlayerSpawn"
|
||||
@export var fishing_shop_path: NodePath = (
|
||||
^"Interactables/FishingShopWorld/FishingShopInteraction"
|
||||
@export_node_path("Marker3D")
|
||||
var player_spawn_path: NodePath = ^"PlayerSpawn"
|
||||
@export_node_path("Area3D")
|
||||
var fishing_shop_path: NodePath = (
|
||||
^"Interactables/FishingShopWorld/InteractionArea"
|
||||
)
|
||||
@export var pelican_landmark_path: NodePath = (
|
||||
@export_node_path("Node3D")
|
||||
var pelican_landmark_path: NodePath = (
|
||||
^"Interactables/PelicanCoolerPerch"
|
||||
)
|
||||
|
||||
@export_group("Grass Surface")
|
||||
@export var grass_material: Material
|
||||
@export_range(0, 16, 1) var grass_surface_index: int = 0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_apply_grass_material()
|
||||
_build_terrain_collision()
|
||||
if Engine.is_editor_hint():
|
||||
update_configuration_warnings()
|
||||
|
||||
|
||||
func get_player_spawn_transform() -> Transform3D:
|
||||
|
|
@ -44,6 +58,28 @@ func has_terrain_collision() -> bool:
|
|||
return collision_shape != null and collision_shape.shape != null
|
||||
|
||||
|
||||
func _apply_grass_material() -> void:
|
||||
var visual_mesh: MeshInstance3D = (
|
||||
get_node_or_null(visual_mesh_path) as MeshInstance3D
|
||||
)
|
||||
if visual_mesh == null or visual_mesh.mesh == null:
|
||||
push_error("Starter island visual mesh is unavailable.")
|
||||
return
|
||||
if grass_material == null:
|
||||
push_error("Starter island grass material is unavailable.")
|
||||
return
|
||||
if grass_surface_index >= visual_mesh.mesh.get_surface_count():
|
||||
push_error("Starter island grass surface index is invalid.")
|
||||
return
|
||||
if visual_mesh.mesh.surface_get_name(grass_surface_index) != "grass":
|
||||
push_error("Starter island grass surface name does not match.")
|
||||
return
|
||||
visual_mesh.set_surface_override_material(
|
||||
grass_surface_index,
|
||||
grass_material
|
||||
)
|
||||
|
||||
|
||||
func _build_terrain_collision() -> void:
|
||||
var visual_mesh: MeshInstance3D = (
|
||||
get_node_or_null(visual_mesh_path) as MeshInstance3D
|
||||
|
|
@ -64,3 +100,25 @@ func _build_terrain_collision() -> void:
|
|||
push_error("Starter island terrain collision could not be created.")
|
||||
return
|
||||
collision_shape.shape = terrain_shape
|
||||
|
||||
|
||||
func _get_configuration_warnings() -> PackedStringArray:
|
||||
var warnings := PackedStringArray()
|
||||
var visual_mesh := get_node_or_null(visual_mesh_path) as MeshInstance3D
|
||||
if visual_mesh == null or visual_mesh.mesh == null:
|
||||
warnings.append("Terrain/Visual must provide the island mesh.")
|
||||
elif grass_surface_index >= visual_mesh.mesh.get_surface_count():
|
||||
warnings.append("Grass surface index is outside the terrain mesh.")
|
||||
elif visual_mesh.mesh.surface_get_name(grass_surface_index) != "grass":
|
||||
warnings.append("Grass surface index must identify the grass surface.")
|
||||
if grass_material == null:
|
||||
warnings.append("Assign the starter-island grass material.")
|
||||
if get_node_or_null(terrain_collision_shape_path) == null:
|
||||
warnings.append("Terrain/Collision must provide a collision shape.")
|
||||
if get_node_or_null(player_spawn_path) == null:
|
||||
warnings.append("PlayerSpawn marker is missing.")
|
||||
if get_node_or_null(fishing_shop_path) == null:
|
||||
warnings.append("Fishing Shop placement is missing.")
|
||||
if get_node_or_null(pelican_landmark_path) == null:
|
||||
warnings.append("Pelican placement is missing.")
|
||||
return warnings
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1,114 +0,0 @@
|
|||
[gd_scene load_steps=14 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://world/regions/graybox_region.gd" id="1_region"]
|
||||
[ext_resource type="Script" path="res://world/fishable_water_region.gd" id="2_water"]
|
||||
[ext_resource type="Resource" path="res://fish/pools/test_water_pool.tres" id="3_pool"]
|
||||
[ext_resource type="Script" path="res://world/player_water_trigger.gd" id="4_trigger"]
|
||||
[ext_resource type="Script" path="res://world/safe_respawn_point.gd" id="5_safe"]
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BankNSShape"]
|
||||
size = Vector3(36, 6, 8)
|
||||
[sub_resource type="BoxShape3D" id="BankEWShape"]
|
||||
size = Vector3(6, 6, 20)
|
||||
[sub_resource type="BoxMesh" id="BankNSMesh"]
|
||||
size = Vector3(36, 6, 8)
|
||||
[sub_resource type="BoxMesh" id="BankEWMesh"]
|
||||
size = Vector3(6, 6, 20)
|
||||
[sub_resource type="PlaneMesh" id="WaterMesh"]
|
||||
size = Vector2(24, 20)
|
||||
[sub_resource type="BoxShape3D" id="WaterShape"]
|
||||
size = Vector3(24, 0.2, 20)
|
||||
[sub_resource type="BoxShape3D" id="RecoveryShape"]
|
||||
size = Vector3(24, 5, 20)
|
||||
[sub_resource type="StandardMaterial3D" id="GrassMaterial"]
|
||||
albedo_color = Color(0.43, 0.75, 0.34, 1)
|
||||
[sub_resource type="StandardMaterial3D" id="WaterMaterial"]
|
||||
transparency = 1
|
||||
albedo_color = Color(0.16, 0.58, 0.78, 0.78)
|
||||
roughness = 0.25
|
||||
|
||||
[node name="StarterPondRegion" type="Node3D"]
|
||||
script = ExtResource("1_region")
|
||||
region_id = &"starter_pond"
|
||||
|
||||
[node name="Visuals" type="Node3D" parent="."]
|
||||
[node name="NorthBank" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(0, -3, 14)
|
||||
mesh = SubResource("BankNSMesh")
|
||||
material_override = SubResource("GrassMaterial")
|
||||
[node name="SouthBank" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(0, -3, -14)
|
||||
mesh = SubResource("BankNSMesh")
|
||||
material_override = SubResource("GrassMaterial")
|
||||
[node name="WestBank" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(-15, -3, 0)
|
||||
mesh = SubResource("BankEWMesh")
|
||||
material_override = SubResource("GrassMaterial")
|
||||
[node name="EastBank" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(15, -3, 0)
|
||||
mesh = SubResource("BankEWMesh")
|
||||
material_override = SubResource("GrassMaterial")
|
||||
[node name="Water" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(0, 0.2, 0)
|
||||
mesh = SubResource("WaterMesh")
|
||||
material_override = SubResource("WaterMaterial")
|
||||
[node name="PondLabel" type="Label3D" parent="Visuals"]
|
||||
position = Vector3(-14, 2.4, 11)
|
||||
text = "pond"
|
||||
font_size = 34
|
||||
outline_size = 7
|
||||
billboard = 1
|
||||
no_depth_test = true
|
||||
|
||||
[node name="StaticCollision" type="Node3D" parent="."]
|
||||
[node name="NorthBank" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/NorthBank"]
|
||||
position = Vector3(0, -3, 14)
|
||||
shape = SubResource("BankNSShape")
|
||||
[node name="SouthBank" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/SouthBank"]
|
||||
position = Vector3(0, -3, -14)
|
||||
shape = SubResource("BankNSShape")
|
||||
[node name="WestBank" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/WestBank"]
|
||||
position = Vector3(-15, -3, 0)
|
||||
shape = SubResource("BankEWShape")
|
||||
[node name="EastBank" type="StaticBody3D" parent="StaticCollision"]
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/EastBank"]
|
||||
position = Vector3(15, -3, 0)
|
||||
shape = SubResource("BankEWShape")
|
||||
|
||||
[node name="FishingWater" type="Node3D" parent="."]
|
||||
[node name="StarterPondWater" type="Area3D" parent="FishingWater"]
|
||||
position = Vector3(0, 0.2, 0)
|
||||
collision_layer = 4
|
||||
collision_mask = 0
|
||||
monitoring = false
|
||||
script = ExtResource("2_water")
|
||||
location_tags = Array[StringName]([&"starter_pond"])
|
||||
fish_pool = ExtResource("3_pool")
|
||||
[node name="Shape" type="CollisionShape3D" parent="FishingWater/StarterPondWater"]
|
||||
shape = SubResource("WaterShape")
|
||||
|
||||
[node name="WaterRecovery" type="Node3D" parent="."]
|
||||
[node name="StarterPondRecovery" type="Area3D" parent="WaterRecovery"]
|
||||
position = Vector3(0, -2.3, 0)
|
||||
collision_layer = 8
|
||||
collision_mask = 2
|
||||
script = ExtResource("4_trigger")
|
||||
surface_height = 0.2
|
||||
[node name="Shape" type="CollisionShape3D" parent="WaterRecovery/StarterPondRecovery"]
|
||||
shape = SubResource("RecoveryShape")
|
||||
|
||||
[node name="SafeRespawns" type="Node3D" parent="."]
|
||||
[node name="EastShore" type="Marker3D" parent="SafeRespawns"]
|
||||
position = Vector3(15, 0.58, 4)
|
||||
rotation_degrees = Vector3(0, 90, 0)
|
||||
script = ExtResource("5_safe")
|
||||
[node name="NorthShore" type="Marker3D" parent="SafeRespawns"]
|
||||
position = Vector3(0, 0.58, 14)
|
||||
rotation_degrees = Vector3(0, 180, 0)
|
||||
script = ExtResource("5_safe")
|
||||
[node name="SouthShore" type="Marker3D" parent="SafeRespawns"]
|
||||
position = Vector3(0, 0.58, -14)
|
||||
script = ExtResource("5_safe")
|
||||
|
|
@ -1,179 +0,0 @@
|
|||
[gd_scene load_steps=16 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://world/regions/graybox_region.gd" id="1_region"]
|
||||
[ext_resource type="Script" path="res://world/safe_respawn_point.gd" id="2_safe"]
|
||||
[ext_resource type="PackedScene" path="res://world/interactables/fishing_shop_world.tscn" id="3_shop"]
|
||||
[ext_resource type="PackedScene" path="res://world/interactables/pelican_buyer_world.tscn" id="4_pelican"]
|
||||
|
||||
[sub_resource type="BoxShape3D" id="GroundShape"]
|
||||
size = Vector3(48, 6, 36)
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BuildingShape"]
|
||||
size = Vector3(8, 5, 7)
|
||||
|
||||
[sub_resource type="BoxMesh" id="GroundMesh"]
|
||||
size = Vector3(48, 6, 36)
|
||||
|
||||
[sub_resource type="BoxMesh" id="PlazaMesh"]
|
||||
size = Vector3(22, 0.02, 18)
|
||||
|
||||
[sub_resource type="BoxMesh" id="BuildingMesh"]
|
||||
size = Vector3(8, 5, 7)
|
||||
|
||||
[sub_resource type="CylinderMesh" id="RoofMesh"]
|
||||
top_radius = 0
|
||||
bottom_radius = 5.5
|
||||
height = 3
|
||||
radial_segments = 4
|
||||
|
||||
[sub_resource type="CylinderMesh" id="TowerMesh"]
|
||||
top_radius = 2.4
|
||||
bottom_radius = 2.4
|
||||
height = 8
|
||||
|
||||
[sub_resource type="CylinderMesh" id="TowerTankMesh"]
|
||||
top_radius = 3.2
|
||||
bottom_radius = 3.2
|
||||
height = 3.2
|
||||
|
||||
[sub_resource type="BoxMesh" id="PavilionRoofMesh"]
|
||||
size = Vector3(9, 0.35, 7)
|
||||
|
||||
[sub_resource type="BoxMesh" id="PavilionPostMesh"]
|
||||
size = Vector3(0.3, 3.2, 0.3)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="GrassMaterial"]
|
||||
albedo_color = Color(0.37, 0.68, 0.3, 1)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="PlazaMaterial"]
|
||||
albedo_color = Color(0.76, 0.69, 0.54, 1)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="BuildingMaterial"]
|
||||
albedo_color = Color(0.92, 0.55, 0.34, 1)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="RoofMaterial"]
|
||||
albedo_color = Color(0.2, 0.46, 0.53, 1)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="LandmarkMaterial"]
|
||||
albedo_color = Color(0.95, 0.82, 0.28, 1)
|
||||
|
||||
[node name="VillageRegion" type="Node3D"]
|
||||
script = ExtResource("1_region")
|
||||
region_id = &"village"
|
||||
|
||||
[node name="Visuals" type="Node3D" parent="."]
|
||||
|
||||
[node name="Ground" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(0, -3, 0)
|
||||
mesh = SubResource("GroundMesh")
|
||||
material_override = SubResource("GrassMaterial")
|
||||
|
||||
[node name="Plaza" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(0, 0.011, 0)
|
||||
mesh = SubResource("PlazaMesh")
|
||||
material_override = SubResource("PlazaMaterial")
|
||||
|
||||
[node name="WestBuilding" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(-17, 2.5, 9)
|
||||
mesh = SubResource("BuildingMesh")
|
||||
material_override = SubResource("BuildingMaterial")
|
||||
|
||||
[node name="WestRoof" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(-17, 6.1, 9)
|
||||
rotation_degrees = Vector3(0, 45, 0)
|
||||
mesh = SubResource("RoofMesh")
|
||||
material_override = SubResource("RoofMaterial")
|
||||
|
||||
[node name="NorthBuilding" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(-7, 2.5, 13)
|
||||
mesh = SubResource("BuildingMesh")
|
||||
material_override = SubResource("BuildingMaterial")
|
||||
|
||||
[node name="NorthRoof" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(-7, 6.1, 13)
|
||||
rotation_degrees = Vector3(0, 45, 0)
|
||||
mesh = SubResource("RoofMesh")
|
||||
material_override = SubResource("RoofMaterial")
|
||||
|
||||
[node name="WaterTower" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(18, 4, 11)
|
||||
mesh = SubResource("TowerMesh")
|
||||
material_override = SubResource("RoofMaterial")
|
||||
|
||||
[node name="WaterTank" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(18, 8.5, 11)
|
||||
mesh = SubResource("TowerTankMesh")
|
||||
material_override = SubResource("LandmarkMaterial")
|
||||
|
||||
[node name="PavilionRoof" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(-12, 3.3, -10)
|
||||
mesh = SubResource("PavilionRoofMesh")
|
||||
material_override = SubResource("LandmarkMaterial")
|
||||
|
||||
[node name="PavilionPostNW" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(-15.5, 1.6, -12.5)
|
||||
mesh = SubResource("PavilionPostMesh")
|
||||
material_override = SubResource("RoofMaterial")
|
||||
|
||||
[node name="PavilionPostSE" type="MeshInstance3D" parent="Visuals"]
|
||||
position = Vector3(-8.5, 1.6, -7.5)
|
||||
mesh = SubResource("PavilionPostMesh")
|
||||
material_override = SubResource("RoofMaterial")
|
||||
|
||||
[node name="VillageLabel" type="Label3D" parent="Visuals"]
|
||||
position = Vector3(0, 3.2, 7)
|
||||
text = "village"
|
||||
font_size = 42
|
||||
outline_size = 8
|
||||
billboard = 1
|
||||
no_depth_test = true
|
||||
|
||||
[node name="StaticCollision" type="Node3D" parent="."]
|
||||
|
||||
[node name="Ground" type="StaticBody3D" parent="StaticCollision"]
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticCollision/Ground"]
|
||||
position = Vector3(0, -3, 0)
|
||||
shape = SubResource("GroundShape")
|
||||
|
||||
[node name="WestBuilding" type="StaticBody3D" parent="StaticCollision"]
|
||||
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/WestBuilding"]
|
||||
position = Vector3(-17, 2.5, 9)
|
||||
shape = SubResource("BuildingShape")
|
||||
|
||||
[node name="NorthBuilding" type="StaticBody3D" parent="StaticCollision"]
|
||||
|
||||
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/NorthBuilding"]
|
||||
position = Vector3(-7, 2.5, 13)
|
||||
shape = SubResource("BuildingShape")
|
||||
|
||||
[node name="FishingWater" type="Node3D" parent="."]
|
||||
|
||||
[node name="WaterRecovery" type="Node3D" parent="."]
|
||||
|
||||
[node name="SafeRespawns" type="Node3D" parent="."]
|
||||
|
||||
[node name="VillageCenter" type="Marker3D" parent="SafeRespawns"]
|
||||
position = Vector3(0, 0.58, 2)
|
||||
script = ExtResource("2_safe")
|
||||
|
||||
[node name="VillageWest" type="Marker3D" parent="SafeRespawns"]
|
||||
position = Vector3(-19, 0.58, -2)
|
||||
rotation_degrees = Vector3(0, -90, 0)
|
||||
script = ExtResource("2_safe")
|
||||
|
||||
[node name="VillageSouth" type="Marker3D" parent="SafeRespawns"]
|
||||
position = Vector3(5, 0.58, -14)
|
||||
rotation_degrees = Vector3(0, 180, 0)
|
||||
script = ExtResource("2_safe")
|
||||
|
||||
[node name="Interactables" type="Node3D" parent="."]
|
||||
|
||||
[node name="FishingShopWorld" parent="Interactables" instance=ExtResource("3_shop")]
|
||||
position = Vector3(12, 0, 3)
|
||||
rotation_degrees = Vector3(0, -25, 0)
|
||||
|
||||
[node name="PelicanCoolerPerch" parent="Interactables" instance=ExtResource("4_pelican")]
|
||||
position = Vector3(-19, 0, -9)
|
||||
rotation_degrees = Vector3(0, 20, 0)
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
class_name GrayboxRegion
|
||||
@tool
|
||||
class_name WorldRegion
|
||||
extends Node3D
|
||||
|
||||
@export var region_id: StringName
|
||||
|
|
@ -12,10 +13,7 @@ func get_fishable_water_regions() -> Array[FishableWaterRegion]:
|
|||
var root: Node = get_node_or_null(fishable_water_root)
|
||||
if root == null:
|
||||
return regions
|
||||
for child: Node in root.get_children():
|
||||
var water: FishableWaterRegion = child as FishableWaterRegion
|
||||
if water != null:
|
||||
regions.append(water)
|
||||
_collect_fishable_water_regions(root, regions)
|
||||
return regions
|
||||
|
||||
|
||||
|
|
@ -24,10 +22,7 @@ func get_water_recovery_triggers() -> Array[PlayerWaterTrigger]:
|
|||
var root: Node = get_node_or_null(water_recovery_root)
|
||||
if root == null:
|
||||
return triggers
|
||||
for child: Node in root.get_children():
|
||||
var trigger: PlayerWaterTrigger = child as PlayerWaterTrigger
|
||||
if trigger != null:
|
||||
triggers.append(trigger)
|
||||
_collect_water_recovery_triggers(root, triggers)
|
||||
return triggers
|
||||
|
||||
|
||||
|
|
@ -41,3 +36,25 @@ func get_safe_respawn_points() -> Array[SafeRespawnPoint]:
|
|||
if point != null:
|
||||
points.append(point)
|
||||
return points
|
||||
|
||||
|
||||
func _collect_fishable_water_regions(
|
||||
root: Node,
|
||||
regions: Array[FishableWaterRegion],
|
||||
) -> void:
|
||||
for child: Node in root.get_children():
|
||||
var water := child as FishableWaterRegion
|
||||
if water != null:
|
||||
regions.append(water)
|
||||
_collect_fishable_water_regions(child, regions)
|
||||
|
||||
|
||||
func _collect_water_recovery_triggers(
|
||||
root: Node,
|
||||
triggers: Array[PlayerWaterTrigger],
|
||||
) -> void:
|
||||
for child: Node in root.get_children():
|
||||
var trigger := child as PlayerWaterTrigger
|
||||
if trigger != null:
|
||||
triggers.append(trigger)
|
||||
_collect_water_recovery_triggers(child, triggers)
|
||||
|
|
@ -19,7 +19,7 @@ const FishingShopInteractionType = preload(
|
|||
|
||||
func get_player_water_triggers() -> Array[PlayerWaterTrigger]:
|
||||
var triggers: Array[PlayerWaterTrigger] = []
|
||||
for region: GrayboxRegion in _get_regions():
|
||||
for region: WorldRegion in _get_regions():
|
||||
triggers.append_array(region.get_water_recovery_triggers())
|
||||
triggers.append(_below_world_failsafe)
|
||||
return triggers
|
||||
|
|
@ -27,7 +27,7 @@ func get_player_water_triggers() -> Array[PlayerWaterTrigger]:
|
|||
|
||||
func get_safe_respawn_points() -> Array[SafeRespawnPoint]:
|
||||
var points: Array[SafeRespawnPoint] = []
|
||||
for region: GrayboxRegion in _get_regions():
|
||||
for region: WorldRegion in _get_regions():
|
||||
points.append_array(region.get_safe_respawn_points())
|
||||
return points
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ func get_player_spawn_transform() -> Transform3D:
|
|||
|
||||
func get_fishable_water_regions() -> Array[FishableWaterRegion]:
|
||||
var waters: Array[FishableWaterRegion] = []
|
||||
for region: GrayboxRegion in _get_regions():
|
||||
for region: WorldRegion in _get_regions():
|
||||
waters.append_array(region.get_fishable_water_regions())
|
||||
return waters
|
||||
|
||||
|
|
@ -51,10 +51,10 @@ func get_pelican_convenience_landmark() -> Node3D:
|
|||
return _starter_island.get_pelican_landmark()
|
||||
|
||||
|
||||
func _get_regions() -> Array[GrayboxRegion]:
|
||||
var regions: Array[GrayboxRegion] = []
|
||||
func _get_regions() -> Array[WorldRegion]:
|
||||
var regions: Array[WorldRegion] = []
|
||||
for child: Node in _regions_root.get_children():
|
||||
var region: GrayboxRegion = child as GrayboxRegion
|
||||
var region: WorldRegion = child as WorldRegion
|
||||
if region != null:
|
||||
regions.append(region)
|
||||
return regions
|
||||
|
|
|
|||
|
|
@ -2,14 +2,25 @@
|
|||
|
||||
[ext_resource type="Script" path="res://world/test_world.gd" id="1_world"]
|
||||
[ext_resource type="PackedScene" path="res://world/regions/starter_island_region.tscn" id="2_island"]
|
||||
[ext_resource type="Script" path="res://world/player_water_trigger.gd" id="3_water_trigger"]
|
||||
[ext_resource type="Script" path="res://world/below_world_failsafe.gd" id="3_water_trigger"]
|
||||
|
||||
[sub_resource type="Environment" id="Environment"]
|
||||
background_mode = 1
|
||||
background_color = Color(0.48, 0.74, 0.92, 1)
|
||||
background_color = Color(0.58, 0.72, 0.82, 1)
|
||||
background_energy_multiplier = 0.85
|
||||
ambient_light_source = 3
|
||||
ambient_light_color = Color(0.72, 0.78, 0.84, 1)
|
||||
ambient_light_energy = 0.72
|
||||
ambient_light_color = Color(0.78, 0.84, 0.92, 1)
|
||||
ambient_light_energy = 0.95
|
||||
fog_enabled = true
|
||||
fog_light_color = Color(0.62, 0.73, 0.8, 1)
|
||||
fog_light_energy = 0.75
|
||||
fog_density = 0.0025
|
||||
fog_aerial_perspective = 0.2
|
||||
fog_sky_affect = 0.15
|
||||
adjustment_enabled = true
|
||||
adjustment_brightness = 0.9
|
||||
adjustment_contrast = 0.89
|
||||
adjustment_saturation = 0.91
|
||||
|
||||
[sub_resource type="BoxShape3D" id="NorthSouthBoundsShape"]
|
||||
size = Vector3(120, 14, 2)
|
||||
|
|
@ -30,8 +41,11 @@ environment = SubResource("Environment")
|
|||
|
||||
[node name="Sun" type="DirectionalLight3D" parent="Environment"]
|
||||
rotation_degrees = Vector3(-54, -32, 0)
|
||||
light_energy = 1.1
|
||||
light_color = Color(1, 0.94, 0.88, 1)
|
||||
light_energy = 0.68
|
||||
shadow_enabled = true
|
||||
shadow_opacity = 0.58
|
||||
shadow_blur = 2.0
|
||||
|
||||
[node name="Regions" type="Node3D" parent="."]
|
||||
|
||||
|
|
@ -46,7 +60,7 @@ collision_mask = 2
|
|||
script = ExtResource("3_water_trigger")
|
||||
surface_height = 0.3
|
||||
|
||||
[node name="FailsafeShape" type="CollisionShape3D" parent="Safety/BelowWorldFailsafe"]
|
||||
[node name="Coverage" type="CollisionShape3D" parent="Safety/BelowWorldFailsafe"]
|
||||
shape = SubResource("FailsafeShape")
|
||||
|
||||
[node name="WorldBounds" type="Node3D" parent="."]
|
||||
|
|
|
|||
158
world/water_body_authoring.gd
Normal file
158
world/water_body_authoring.gd
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
@tool
|
||||
class_name WaterBodyAuthoring
|
||||
extends Node3D
|
||||
|
||||
@export_group("Surface")
|
||||
## Visible water footprint in meters.
|
||||
@export_custom(
|
||||
PROPERTY_HINT_RANGE,
|
||||
"0.1,200.0,0.1,or_greater,suffix:m",
|
||||
)
|
||||
var surface_size: Vector2 = Vector2(10.0, 10.0):
|
||||
set(value):
|
||||
surface_size = Vector2(maxf(value.x, 0.1), maxf(value.y, 0.1))
|
||||
_sync_owned_nodes()
|
||||
## Material applied to the visible water surface.
|
||||
@export var water_material: Material:
|
||||
set(value):
|
||||
water_material = value
|
||||
_sync_owned_nodes()
|
||||
|
||||
@export_group("Fishing Coverage")
|
||||
## Extra fishable coverage beyond each edge of the visible surface.
|
||||
@export_custom(
|
||||
PROPERTY_HINT_RANGE,
|
||||
"0.0,20.0,0.1,or_greater,suffix:m",
|
||||
)
|
||||
var fishing_padding: Vector2 = Vector2.ZERO:
|
||||
set(value):
|
||||
fishing_padding = Vector2(maxf(value.x, 0.0), maxf(value.y, 0.0))
|
||||
_sync_owned_nodes()
|
||||
@export_range(0.1, 20.0, 0.1, "or_greater", "suffix:m")
|
||||
var fishing_depth: float = 4.0:
|
||||
set(value):
|
||||
fishing_depth = maxf(value, 0.1)
|
||||
_sync_owned_nodes()
|
||||
|
||||
@export_group("Recovery Coverage")
|
||||
## Extra recovery coverage beyond each edge of the visible surface.
|
||||
@export_custom(
|
||||
PROPERTY_HINT_RANGE,
|
||||
"0.0,20.0,0.1,or_greater,suffix:m",
|
||||
)
|
||||
var recovery_padding: Vector2 = Vector2.ZERO:
|
||||
set(value):
|
||||
recovery_padding = Vector2(maxf(value.x, 0.0), maxf(value.y, 0.0))
|
||||
_sync_owned_nodes()
|
||||
@export_range(0.1, 20.0, 0.1, "or_greater", "suffix:m")
|
||||
var recovery_depth: float = 4.8:
|
||||
set(value):
|
||||
recovery_depth = maxf(value, 0.1)
|
||||
_sync_owned_nodes()
|
||||
|
||||
@export_group("Owned Nodes")
|
||||
@export_node_path("MeshInstance3D")
|
||||
var visual_water_path: NodePath = ^"VisualWater"
|
||||
@export_node_path("CollisionShape3D")
|
||||
var fishing_shape_path: NodePath = ^"FishingRegion/Shape"
|
||||
@export_node_path("Area3D")
|
||||
var recovery_region_path: NodePath = ^"RecoveryRegion"
|
||||
@export_node_path("CollisionShape3D")
|
||||
var recovery_shape_path: NodePath = ^"RecoveryRegion/Shape"
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_sync_owned_nodes()
|
||||
if Engine.is_editor_hint():
|
||||
update_configuration_warnings()
|
||||
|
||||
|
||||
func _sync_owned_nodes() -> void:
|
||||
if not is_inside_tree():
|
||||
return
|
||||
var visual_water := get_node_or_null(visual_water_path) as MeshInstance3D
|
||||
if visual_water != null:
|
||||
var plane_mesh := visual_water.mesh as PlaneMesh
|
||||
if plane_mesh != null:
|
||||
plane_mesh.size = surface_size
|
||||
visual_water.material_override = water_material
|
||||
|
||||
var fishing_shape_node := (
|
||||
get_node_or_null(fishing_shape_path) as CollisionShape3D
|
||||
)
|
||||
if fishing_shape_node != null:
|
||||
var fishing_shape := fishing_shape_node.shape as BoxShape3D
|
||||
if fishing_shape != null:
|
||||
fishing_shape.size = Vector3(
|
||||
surface_size.x + fishing_padding.x * 2.0,
|
||||
fishing_depth,
|
||||
surface_size.y + fishing_padding.y * 2.0
|
||||
)
|
||||
|
||||
var recovery_region := (
|
||||
get_node_or_null(recovery_region_path) as Area3D
|
||||
)
|
||||
if recovery_region != null:
|
||||
recovery_region.position.y = -recovery_depth * 0.5
|
||||
var recovery_shape_node := (
|
||||
get_node_or_null(recovery_shape_path) as CollisionShape3D
|
||||
)
|
||||
if recovery_shape_node != null:
|
||||
var recovery_shape := recovery_shape_node.shape as BoxShape3D
|
||||
if recovery_shape != null:
|
||||
recovery_shape.size = Vector3(
|
||||
surface_size.x + recovery_padding.x * 2.0,
|
||||
recovery_depth,
|
||||
surface_size.y + recovery_padding.y * 2.0
|
||||
)
|
||||
|
||||
if Engine.is_editor_hint():
|
||||
update_configuration_warnings()
|
||||
|
||||
|
||||
func _get_configuration_warnings() -> PackedStringArray:
|
||||
var warnings := PackedStringArray()
|
||||
if not scale.is_equal_approx(Vector3.ONE):
|
||||
warnings.append(
|
||||
"Keep root scale at 1; resize water with Surface Size."
|
||||
)
|
||||
var visual_water := get_node_or_null(visual_water_path) as MeshInstance3D
|
||||
if visual_water == null or not visual_water.mesh is PlaneMesh:
|
||||
warnings.append("VisualWater must provide a PlaneMesh.")
|
||||
var fishing_shape := get_node_or_null(fishing_shape_path) as CollisionShape3D
|
||||
if fishing_shape == null or not fishing_shape.shape is BoxShape3D:
|
||||
warnings.append("FishingRegion must provide a BoxShape3D.")
|
||||
var recovery_region := (
|
||||
get_node_or_null(recovery_region_path) as PlayerWaterTrigger
|
||||
)
|
||||
if recovery_region == null:
|
||||
warnings.append("RecoveryRegion must use PlayerWaterTrigger.")
|
||||
elif (
|
||||
recovery_region.surface_height_mode
|
||||
!= PlayerWaterTrigger.SurfaceHeightMode.PARENT_GLOBAL_Y
|
||||
):
|
||||
warnings.append(
|
||||
"RecoveryRegion must derive surface height from its parent."
|
||||
)
|
||||
var recovery_shape := (
|
||||
get_node_or_null(recovery_shape_path) as CollisionShape3D
|
||||
)
|
||||
if recovery_shape == null or not recovery_shape.shape is BoxShape3D:
|
||||
warnings.append("RecoveryRegion must provide a BoxShape3D.")
|
||||
var fishing_region := (
|
||||
fishing_shape.get_parent() as FishableWaterRegion
|
||||
if fishing_shape != null
|
||||
else null
|
||||
)
|
||||
if fishing_region == null:
|
||||
warnings.append("FishingRegion must use FishableWaterRegion.")
|
||||
elif (
|
||||
fishing_region.surface_height_mode
|
||||
!= FishableWaterRegion.SurfaceHeightMode.PARENT_GLOBAL_Y
|
||||
):
|
||||
warnings.append(
|
||||
"FishingRegion must derive surface height from its parent."
|
||||
)
|
||||
if water_material == null:
|
||||
warnings.append("Assign a water material.")
|
||||
return warnings
|
||||
1
world/water_body_authoring.gd.uid
Normal file
1
world/water_body_authoring.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dtcgnxl1kmdu1
|
||||
62
world/world_prop.gd
Normal file
62
world/world_prop.gd
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
@tool
|
||||
class_name WorldProp
|
||||
extends Node3D
|
||||
|
||||
@export_group("Owned Nodes")
|
||||
@export_node_path("Node3D")
|
||||
var visual_root_path: NodePath = ^"Visual"
|
||||
@export_node_path("Node3D")
|
||||
var collision_root_path: NodePath
|
||||
@export_node_path("Area3D")
|
||||
var interaction_area_path: NodePath
|
||||
@export_node_path("Marker3D")
|
||||
var entrance_marker_path: NodePath
|
||||
|
||||
@export_group("Scaling")
|
||||
## Enable only when this prop explicitly supports non-uniform root scaling.
|
||||
@export var allow_non_uniform_scale: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
if not Engine.is_editor_hint():
|
||||
return
|
||||
set_notify_transform(true)
|
||||
update_configuration_warnings()
|
||||
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
if Engine.is_editor_hint() and what == NOTIFICATION_TRANSFORM_CHANGED:
|
||||
update_configuration_warnings()
|
||||
|
||||
|
||||
func _get_configuration_warnings() -> PackedStringArray:
|
||||
var warnings := PackedStringArray()
|
||||
if get_node_or_null(visual_root_path) == null:
|
||||
warnings.append("Assign a valid Visual root.")
|
||||
if (
|
||||
not collision_root_path.is_empty()
|
||||
and get_node_or_null(collision_root_path) == null
|
||||
):
|
||||
warnings.append("Assign a valid Collision root.")
|
||||
if (
|
||||
not interaction_area_path.is_empty()
|
||||
and get_node_or_null(interaction_area_path) == null
|
||||
):
|
||||
warnings.append("Assign a valid InteractionArea.")
|
||||
if (
|
||||
not entrance_marker_path.is_empty()
|
||||
and get_node_or_null(entrance_marker_path) == null
|
||||
):
|
||||
warnings.append("Assign a valid EntranceMarker.")
|
||||
if not allow_non_uniform_scale and not _has_uniform_scale():
|
||||
warnings.append(
|
||||
"Use uniform root scale so visuals and collision stay aligned."
|
||||
)
|
||||
return warnings
|
||||
|
||||
|
||||
func _has_uniform_scale() -> bool:
|
||||
return (
|
||||
is_equal_approx(scale.x, scale.y)
|
||||
and is_equal_approx(scale.y, scale.z)
|
||||
)
|
||||
1
world/world_prop.gd.uid
Normal file
1
world/world_prop.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://c1p4583452rpa
|
||||
Loading…
Add table
Add a link
Reference in a new issue