Add playable starter island

This commit is contained in:
Alexander Sellite 2026-07-27 00:13:07 -04:00
parent 633bbd9a88
commit 8032d266ec
14 changed files with 402 additions and 173 deletions

Binary file not shown.

View file

@ -0,0 +1,45 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://bk38p45urtjis"
path="res://.godot/imported/starter_island.glb-2e424e31e476d52eee139d119e5596cc.scn"
[deps]
source_file="res://art/exported/environment/terrain/starter_island.glb"
dest_files=["res://.godot/imported/starter_island.glb-2e424e31e476d52eee139d119e5596cc.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
mesh_library/use_node_names_as_mesh_names=false
array_mesh/deduplicate_surfaces=true
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={}
gltf/naming_version=2
gltf/embedded_image_handling=1
gltf/texture_map_mode=1

View file

Binary file not shown.

View file

@ -72,9 +72,11 @@ var _pickup_position: Vector3
var _active_tween: Tween var _active_tween: Tween
var _rod_tween: Tween var _rod_tween: Tween
var _bite_tween: Tween var _bite_tween: Tween
var _default_water_surface_offset_y: float
func _ready() -> void: func _ready() -> void:
_default_water_surface_offset_y = water_surface_offset_y
_line.mesh = _line_mesh _line.mesh = _line_mesh
cleanup() cleanup()
@ -94,6 +96,14 @@ func get_water_surface_height() -> float:
return global_position.y + water_surface_offset_y return global_position.y + water_surface_offset_y
func set_water_surface_height(surface_height: float) -> void:
water_surface_offset_y = surface_height - global_position.y
func reset_water_surface_height() -> void:
water_surface_offset_y = _default_water_surface_offset_y
func set_line_mode(mode: LineMode) -> void: func set_line_mode(mode: LineMode) -> void:
_line_mode = mode _line_mode = mode
_line.visible = mode != LineMode.HIDDEN _line.visible = mode != LineMode.HIDDEN

View file

@ -431,6 +431,7 @@ func _begin_aiming(player: PlayerType) -> void:
if state != FishingState.READY or _active_player != null: if state != FishingState.READY or _active_player != null:
return return
_presentation.reset_water_surface_height()
_active_player = player _active_player = player
_active_player.set_movement_enabled(false) _active_player.set_movement_enabled(false)
_cast_direction = _capture_cast_direction(_active_player) _cast_direction = _capture_cast_direction(_active_player)
@ -894,6 +895,7 @@ func _cleanup_attempt(
_catch_controller.reset() _catch_controller.reset()
if visual_outcome.is_empty(): if visual_outcome.is_empty():
_presentation.cleanup() _presentation.cleanup()
_presentation.reset_water_surface_height()
else: else:
if visual_outcome in [&"catch", &"invalid", &"withdrawal"]: if visual_outcome in [&"catch", &"invalid", &"withdrawal"]:
_presentation.set_line_mode( _presentation.set_line_mode(
@ -918,6 +920,7 @@ func _cleanup_attempt(
func _return_to_ready() -> void: func _return_to_ready() -> void:
_presentation.reset_water_surface_height()
state = FishingState.READY state = FishingState.READY
_state_time_remaining = 0.0 _state_time_remaining = 0.0
_cooldown_status = "" _cooldown_status = ""
@ -954,11 +957,21 @@ func _capture_cast_direction(player: PlayerType) -> Vector3:
func _calculate_cast_target(distance: float) -> Vector3: func _calculate_cast_target(distance: float) -> Vector3:
return Vector3( var target := Vector3(
_cast_origin_position.x + _cast_direction.x * distance, _cast_origin_position.x + _cast_direction.x * distance,
_presentation.get_water_surface_height(), _presentation.get_water_surface_height(),
_cast_origin_position.z + _cast_direction.z * distance _cast_origin_position.z + _cast_direction.z * distance
) )
var water_region: FishableWaterRegionType = get_fishable_water_region(
target
)
if water_region != null:
target.y = water_region.surface_height
_presentation.set_water_surface_height(target.y)
else:
_presentation.reset_water_surface_height()
target.y = _presentation.get_water_surface_height()
return target
func is_target_fishable(target: Vector3) -> bool: func is_target_fishable(target: Vector3) -> bool:

View file

@ -54,6 +54,8 @@ var _quit_in_progress: bool = false
func _ready() -> void: func _ready() -> void:
_player.global_transform = _test_world.get_player_spawn_transform()
_player.velocity = Vector3.ZERO
_player.fish_sale_service.setup( _player.fish_sale_service.setup(
_player.inventory, _player.inventory,
_player.wallet _player.wallet

View file

@ -1,110 +1,73 @@
# NETFISHING holdover world # NETFISHING test world
`world/test_world.tscn` remains the active world. It composes the complete `world/test_world.tscn` remains the active world composition. It currently
temporary map, lighting, paths, bounds, and six region scenes. The practical instances `world/regions/starter_island_region.tscn`, a Godot-owned gameplay
footprint is approximately 180 × 220 world units, including the coastal water wrapper around the human-authored starter-island GLB.
and outer collision bounds.
## Composition ## Starter-island ownership
```text ```text
TestWorld TestWorld
├── Environment ├── Environment
├── SeabedBoundary
├── Regions ├── Regions
│ ├── VillageRegion (0, 0, 15) │ └── StarterIslandRegion
│ ├── StarterPondRegion (-42, 0, 15) │ ├── Visuals
│ ├── RiverRegion (0, 0, -40) │ │ ├── StarterIslandModel
│ ├── LakeRegion (53, 0, -25) │ │ ├── OceanWater
│ ├── MarshRegion (56, 0, 38) │ │ └── PondWater
│ └── CoastalDockRegion (0, 0, -103) │ ├── StaticCollision
├── Connectors │ ├── FishingWater
│ ├── WaterRecovery
│ ├── SafeRespawns
│ ├── PlayerSpawn
│ └── Interactables
├── Safety ├── Safety
└── WorldBounds └── WorldBounds
``` ```
Every region uses the same ownership groups: 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.
- `Visuals`: replaceable graybox meshes and labels. Move the complete `StarterIslandRegion` root to keep visuals and gameplay
- `StaticCollision`: simple gameplay collision paired with the visuals. volumes synchronized. When editing inside the wrapper, keep each water mesh
- `FishingWater`: explicit `FishableWaterRegion` children. aligned with its matching `FishingWater` and `WaterRecovery` shapes. Safe
- `WaterRecovery`: explicit `PlayerWaterTrigger` children. respawns and `PlayerSpawn` must remain on broad upper terrain.
- `SafeRespawns`: known-safe `SafeRespawnPoint` markers.
- `Interactables`: region-owned services, currently used by the village.
`GrayboxRegion` only exposes those explicit child groups plus a stable region
ID. `TestWorld` is the aggregation boundary; regions do not select fish,
control recovery, own progression, register globally, or stream themselves.
## Safe editing
Move a whole region by moving its region root under `TestWorld/Regions`. This
keeps visuals, collision, water, recovery triggers, safe points, and
interactables synchronized. Moving only a visual mesh does not move collision
or gameplay volumes, so update its paired collision intentionally when editing
inside a region.
Safe designer targets:
- Entire region roots under `TestWorld/Regions`
- Children of `Visuals`, together with paired `StaticCollision`
- Safe-respawn marker transforms
- Landmark and label transforms
- Connector transforms and their complete StaticBody children
Structural land and route blocks extend from the common walkable elevation at
`y=0` down to approximately `y=-6`. Adjacent blocks meet at deliberate shared
edges instead of stacking collision surfaces. Decorative plaza/path color is
non-colliding and sits just above the authoritative ground.
Gameplay-critical children that must stay aligned:
- A water plane, its `FishingWater` Area3D, and its `WaterRecovery` Area3D
- A dock or bank mesh and its paired shape in `StaticCollision`
- Safe points and the land/dock they target
- The Fishing Shop visual root and `FishingShopInteraction`
Rename-sensitive paths: Rename-sensitive paths:
- `TestWorld/Regions` - `TestWorld/Regions`
- `VillageRegion/Interactables/FishingShopWorld/FishingShopInteraction` - `TestWorld/Regions/StarterIslandRegion`
- `VillageRegion/Interactables/PelicanCoolerPerch` - the NodePaths exported by `StarterIslandRegion`
- Each region's `FishingWater`, `WaterRecovery`, and `SafeRespawns` roots, - each region's `FishingWater`, `WaterRecovery`, and `SafeRespawns` roots
unless its exported NodePaths are updated at the same time
## Adding water and recovery ## Reverting to the modular graybox
1. Add a `FishableWaterRegion` Area3D under the region's `FishingWater`. The previous region scenes remain unchanged under `world/regions/`. To restore
2. Give it collision layer 4, a clear location tag, and an explicit fish pool. the prior holdover world, restore `world/test_world.tscn` and
3. Add a matching `PlayerWaterTrigger` under `WaterRecovery`. `world/test_world.gd` from commit `633bbd9`, then remove the player-spawn
4. Give the trigger collision layer 8, mask 2, matching horizontal coverage, composition line added to `main/main.gd`. That composition instances:
and the correct `surface_height`.
5. Place two or more safe respawns on nearby broad walkable land.
6. Validate casting, shoreline collision, recovery entry, and nearest-point
selection from every side.
`TestWorld/Safety/BelowWorldFailsafe` is a temporary whole-map recovery net. - `village_region.tscn`
It catches seam and below-world falls that escape normal regional water - `starter_pond_region.tscn`
coverage. It supplements rather than replaces the five region-local triggers; - `river_region.tscn`
the recovery controller still permits only one recovery sequence at a time. - `lake_region.tscn`
- `marsh_region.tscn`
- `coastal_dock_region.tscn`
## Services No region asset needs to be reconstructed or recovered from deleted content.
The Fishing Shop is an instanced scene at the east side of the village plaza. ## Water and recovery
Move the complete `FishingShopWorld` instance, not only its booth meshes.
The Pelican perch is decorative signage, not an interaction NPC. Its sign says The pond and surrounding ocean remain separate fishable regions using the
“Sell to Pelicans from the Cooler”; the existing 0.25× Pelican sale remains existing test pool. Ocean fishing and recovery use four collision shapes so
available from the Cooler anywhere in the world. Moving or removing the the raised island interior is not classified as ocean. Regional recovery is
decorative perch does not change that service. supplemented by `TestWorld/Safety/BelowWorldFailsafe`.
## Temporary by design 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.
All terrain, buildings, docks, reeds, landmarks, signage, palette, and lighting The Fishing Shop remains a complete instanced interactable. The Pelican perch
are primitive holdover presentation. A future artist or level designer can remains convenience signage only; Pelican selling is available through the
replace `Visuals` and paired static collision without changing fishing, Cooler from anywhere.
recovery, shop, save, economy, or player progression code. Region IDs and
gameplay volume ownership should remain stable while visuals are replaced.
Water surfaces sit near `y=0.2`; the shared graybox seabed is near `y=-6`.
There is no structural walkable layer directly below the fishable surfaces.

View file

@ -6,3 +6,4 @@ const FishPoolType = preload("res://fish/fish_pool.gd")
@export var location_tags: Array[StringName] = [] @export var location_tags: Array[StringName] = []
@export var fish_pool: FishPoolType @export var fish_pool: FishPoolType
@export var selection_priority: int = 0 @export var selection_priority: int = 0
@export var surface_height: float = 0.3

View file

@ -0,0 +1,66 @@
class_name StarterIslandRegion
extends GrayboxRegion
const FishingShopInteractionType = preload(
"res://world/fishing_shop_interaction.gd"
)
@export var visual_mesh_path: NodePath = (
^"Visuals/StarterIslandModel/starter_island"
)
@export var terrain_collision_shape_path: NodePath = (
^"StaticCollision/Terrain/Shape"
)
@export var player_spawn_path: NodePath = ^"PlayerSpawn"
@export var fishing_shop_path: NodePath = (
^"Interactables/FishingShopWorld/FishingShopInteraction"
)
@export var pelican_landmark_path: NodePath = (
^"Interactables/PelicanCoolerPerch"
)
func _ready() -> void:
_build_terrain_collision()
func get_player_spawn_transform() -> Transform3D:
var spawn: Marker3D = get_node_or_null(player_spawn_path) as Marker3D
return spawn.global_transform if spawn != null else global_transform
func get_fishing_shop() -> FishingShopInteractionType:
return get_node_or_null(fishing_shop_path) as FishingShopInteractionType
func get_pelican_landmark() -> Node3D:
return get_node_or_null(pelican_landmark_path) as Node3D
func has_terrain_collision() -> bool:
var collision_shape: CollisionShape3D = (
get_node_or_null(terrain_collision_shape_path) as CollisionShape3D
)
return collision_shape != null and collision_shape.shape != null
func _build_terrain_collision() -> void:
var visual_mesh: MeshInstance3D = (
get_node_or_null(visual_mesh_path) as MeshInstance3D
)
var collision_shape: CollisionShape3D = (
get_node_or_null(terrain_collision_shape_path) as CollisionShape3D
)
if visual_mesh == null or visual_mesh.mesh == null:
push_error("Starter island visual mesh is unavailable.")
return
if collision_shape == null:
push_error("Starter island collision owner is unavailable.")
return
var terrain_shape: ConcavePolygonShape3D = (
visual_mesh.mesh.create_trimesh_shape()
)
if terrain_shape == null or terrain_shape.get_faces().is_empty():
push_error("Starter island terrain collision could not be created.")
return
collision_shape.shape = terrain_shape

View file

@ -0,0 +1 @@
uid://j8syuqdau7vl

View file

@ -0,0 +1,185 @@
[gd_scene load_steps=20 format=3]
[ext_resource type="Script" path="res://world/regions/starter_island_region.gd" id="1_region"]
[ext_resource type="PackedScene" path="res://art/exported/environment/terrain/starter_island.glb" id="2_island"]
[ext_resource type="Script" path="res://world/fishable_water_region.gd" id="3_water"]
[ext_resource type="Resource" path="res://fish/pools/test_water_pool.tres" id="4_pool"]
[ext_resource type="Script" path="res://world/player_water_trigger.gd" id="5_trigger"]
[ext_resource type="Script" path="res://world/safe_respawn_point.gd" id="6_safe"]
[ext_resource type="PackedScene" path="res://world/interactables/fishing_shop_world.tscn" id="7_shop"]
[ext_resource type="PackedScene" path="res://world/interactables/pelican_buyer_world.tscn" id="8_pelican"]
[sub_resource type="StandardMaterial3D" id="WaterMaterial"]
transparency = 1
albedo_color = Color(0.10, 0.50, 0.72, 0.76)
roughness = 0.22
[sub_resource type="PlaneMesh" id="OceanWaterMesh"]
size = Vector2(120, 90)
[sub_resource type="PlaneMesh" id="PondWaterMesh"]
size = Vector2(11.5, 8.5)
[sub_resource type="BoxShape3D" id="OceanWestShape"]
size = Vector3(17, 2, 80)
[sub_resource type="BoxShape3D" id="OceanEastShape"]
size = Vector3(42, 2, 80)
[sub_resource type="BoxShape3D" id="OceanNorthSouthShape"]
size = Vector3(48, 2, 18)
[sub_resource type="BoxShape3D" id="PondFishingShape"]
size = Vector3(11.5, 4, 8.5)
[sub_resource type="BoxShape3D" id="OceanWestRecoveryShape"]
size = Vector3(17, 5, 80)
[sub_resource type="BoxShape3D" id="OceanEastRecoveryShape"]
size = Vector3(42, 5, 80)
[sub_resource type="BoxShape3D" id="OceanNorthSouthRecoveryShape"]
size = Vector3(48, 5, 18)
[sub_resource type="BoxShape3D" id="PondRecoveryShape"]
size = Vector3(11.5, 4.8, 8.5)
[node name="StarterIslandRegion" type="Node3D"]
script = ExtResource("1_region")
region_id = &"starter_island"
[node name="Visuals" type="Node3D" parent="."]
[node name="StarterIslandModel" parent="Visuals" instance=ExtResource("2_island")]
[node name="OceanWater" type="MeshInstance3D" parent="Visuals"]
position = Vector3(12, -0.45, 0)
mesh = SubResource("OceanWaterMesh")
material_override = SubResource("WaterMaterial")
[node name="PondWater" type="MeshInstance3D" parent="Visuals"]
position = Vector3(-9.4, 2.1, 2.1)
mesh = SubResource("PondWaterMesh")
material_override = SubResource("WaterMaterial")
[node name="StaticCollision" type="Node3D" parent="."]
[node name="Terrain" type="StaticBody3D" parent="StaticCollision"]
[node name="Shape" type="CollisionShape3D" parent="StaticCollision/Terrain"]
[node name="FishingWater" type="Node3D" parent="."]
[node name="PondWater" type="Area3D" parent="FishingWater"]
position = Vector3(-9.4, 2.1, 2.1)
collision_layer = 4
collision_mask = 0
monitoring = false
script = ExtResource("3_water")
location_tags = Array[StringName]([&"starter_pond"])
fish_pool = ExtResource("4_pool")
selection_priority = 1
surface_height = 2.1
[node name="Shape" type="CollisionShape3D" parent="FishingWater/PondWater"]
shape = SubResource("PondFishingShape")
[node name="OceanWater" type="Area3D" parent="FishingWater"]
position = Vector3(0, -0.45, 0)
collision_layer = 4
collision_mask = 0
monitoring = false
script = ExtResource("3_water")
location_tags = Array[StringName]([&"coast", &"ocean"])
fish_pool = ExtResource("4_pool")
surface_height = -0.45
[node name="WestShape" type="CollisionShape3D" parent="FishingWater/OceanWater"]
position = Vector3(-33.5, 0, 0)
shape = SubResource("OceanWestShape")
[node name="EastShape" type="CollisionShape3D" parent="FishingWater/OceanWater"]
position = Vector3(44, 0, 0)
shape = SubResource("OceanEastShape")
[node name="NorthShape" type="CollisionShape3D" parent="FishingWater/OceanWater"]
position = Vector3(-1, 0, 31)
shape = SubResource("OceanNorthSouthShape")
[node name="SouthShape" type="CollisionShape3D" parent="FishingWater/OceanWater"]
position = Vector3(-1, 0, -31)
shape = SubResource("OceanNorthSouthShape")
[node name="WaterRecovery" type="Node3D" parent="."]
[node name="PondRecovery" type="Area3D" parent="WaterRecovery"]
position = Vector3(-9.4, -0.3, 2.1)
collision_layer = 8
collision_mask = 2
script = ExtResource("5_trigger")
surface_height = 2.1
[node name="Shape" type="CollisionShape3D" parent="WaterRecovery/PondRecovery"]
shape = SubResource("PondRecoveryShape")
[node name="OceanRecovery" type="Area3D" parent="WaterRecovery"]
position = Vector3(0, -2.95, 0)
collision_layer = 8
collision_mask = 2
script = ExtResource("5_trigger")
surface_height = -0.45
[node name="WestShape" type="CollisionShape3D" parent="WaterRecovery/OceanRecovery"]
position = Vector3(-33.5, 0, 0)
shape = SubResource("OceanWestRecoveryShape")
[node name="EastShape" type="CollisionShape3D" parent="WaterRecovery/OceanRecovery"]
position = Vector3(44, 0, 0)
shape = SubResource("OceanEastRecoveryShape")
[node name="NorthShape" type="CollisionShape3D" parent="WaterRecovery/OceanRecovery"]
position = Vector3(-1, 0, 31)
shape = SubResource("OceanNorthSouthRecoveryShape")
[node name="SouthShape" type="CollisionShape3D" parent="WaterRecovery/OceanRecovery"]
position = Vector3(-1, 0, -31)
shape = SubResource("OceanNorthSouthRecoveryShape")
[node name="SafeRespawns" type="Node3D" parent="."]
[node name="SpawnPlateau" type="Marker3D" parent="SafeRespawns"]
position = Vector3(0, 3.95, 13)
script = ExtResource("6_safe")
[node name="PondEast" type="Marker3D" parent="SafeRespawns"]
position = Vector3(-0.5, 3.95, 2)
script = ExtResource("6_safe")
[node name="PondSouth" type="Marker3D" parent="SafeRespawns"]
position = Vector3(-9, 3.95, 11.5)
script = ExtResource("6_safe")
[node name="ShopApproach" type="Marker3D" parent="SafeRespawns"]
position = Vector3(13.5, 3.95, 6)
script = ExtResource("6_safe")
[node name="SouthPlateau" type="Marker3D" parent="SafeRespawns"]
position = Vector3(5, 3.95, 15)
script = ExtResource("6_safe")
[node name="EastShoreApproach" type="Marker3D" parent="SafeRespawns"]
position = Vector3(15, 3.95, -11)
script = ExtResource("6_safe")
[node name="PlayerSpawn" type="Marker3D" parent="."]
position = Vector3(0, 3.95, 13)
[node name="Interactables" type="Node3D" parent="."]
[node name="FishingShopWorld" parent="Interactables" instance=ExtResource("7_shop")]
position = Vector3(8, 3.42, 6)
rotation_degrees = Vector3(0, -25, 0)
[node name="PelicanCoolerPerch" parent="Interactables" instance=ExtResource("8_pelican")]
position = Vector3(18, 0.35, -16)
rotation_degrees = Vector3(0, -35, 0)

View file

@ -6,11 +6,14 @@ const FishingShopInteractionType = preload(
) )
@onready var _regions_root: Node3D = $Regions @onready var _regions_root: Node3D = $Regions
@onready var _starter_island: StarterIslandRegion = (
$Regions/StarterIslandRegion
)
@onready var _below_world_failsafe: PlayerWaterTrigger = ( @onready var _below_world_failsafe: PlayerWaterTrigger = (
$Safety/BelowWorldFailsafe $Safety/BelowWorldFailsafe
) )
@onready var _fishing_shop: FishingShopInteractionType = ( @onready var _fishing_shop: FishingShopInteractionType = (
$Regions/VillageRegion/Interactables/FishingShopWorld/FishingShopInteraction _starter_island.get_fishing_shop()
) )
@ -33,6 +36,10 @@ func get_fishing_shop() -> FishingShopInteractionType:
return _fishing_shop return _fishing_shop
func get_player_spawn_transform() -> Transform3D:
return _starter_island.get_player_spawn_transform()
func get_fishable_water_regions() -> Array[FishableWaterRegion]: func get_fishable_water_regions() -> Array[FishableWaterRegion]:
var waters: Array[FishableWaterRegion] = [] var waters: Array[FishableWaterRegion] = []
for region: GrayboxRegion in _get_regions(): for region: GrayboxRegion in _get_regions():
@ -41,10 +48,7 @@ func get_fishable_water_regions() -> Array[FishableWaterRegion]:
func get_pelican_convenience_landmark() -> Node3D: func get_pelican_convenience_landmark() -> Node3D:
return ( return _starter_island.get_pelican_landmark()
$Regions/VillageRegion/Interactables/PelicanCoolerPerch
as Node3D
)
func _get_regions() -> Array[GrayboxRegion]: func _get_regions() -> Array[GrayboxRegion]:

View file

@ -1,13 +1,8 @@
[gd_scene load_steps=16 format=3] [gd_scene load_steps=10 format=3]
[ext_resource type="Script" path="res://world/test_world.gd" id="1_world"] [ext_resource type="Script" path="res://world/test_world.gd" id="1_world"]
[ext_resource type="PackedScene" path="res://world/regions/village_region.tscn" id="2_village"] [ext_resource type="PackedScene" path="res://world/regions/starter_island_region.tscn" id="2_island"]
[ext_resource type="PackedScene" path="res://world/regions/starter_pond_region.tscn" id="3_pond"] [ext_resource type="Script" path="res://world/player_water_trigger.gd" id="3_water_trigger"]
[ext_resource type="PackedScene" path="res://world/regions/river_region.tscn" id="4_river"]
[ext_resource type="PackedScene" path="res://world/regions/lake_region.tscn" id="5_lake"]
[ext_resource type="PackedScene" path="res://world/regions/marsh_region.tscn" id="6_marsh"]
[ext_resource type="PackedScene" path="res://world/regions/coastal_dock_region.tscn" id="7_coast"]
[ext_resource type="Script" path="res://world/player_water_trigger.gd" id="8_water_trigger"]
[sub_resource type="Environment" id="Environment"] [sub_resource type="Environment" id="Environment"]
background_mode = 1 background_mode = 1
@ -16,30 +11,14 @@ ambient_light_source = 3
ambient_light_color = Color(0.72, 0.78, 0.84, 1) ambient_light_color = Color(0.72, 0.78, 0.84, 1)
ambient_light_energy = 0.72 ambient_light_energy = 0.72
[sub_resource type="BoxShape3D" id="SeabedShape"]
size = Vector3(180, 1, 220)
[sub_resource type="BoxMesh" id="SeabedMesh"]
size = Vector3(180, 1, 220)
[sub_resource type="StandardMaterial3D" id="SeabedMaterial"]
albedo_color = Color(0.18, 0.36, 0.27, 1)
[sub_resource type="BoxShape3D" id="RiverPathShape"]
size = Vector3(40, 6, 8)
[sub_resource type="BoxMesh" id="RiverPathMesh"]
size = Vector3(40, 6, 8)
[sub_resource type="BoxShape3D" id="MarshPathShape"]
size = Vector3(5, 6, 10)
[sub_resource type="BoxMesh" id="MarshPathMesh"]
size = Vector3(5, 6, 10)
[sub_resource type="StandardMaterial3D" id="PathMaterial"]
albedo_color = Color(0.72, 0.62, 0.43, 1)
[sub_resource type="BoxShape3D" id="NorthSouthBoundsShape"] [sub_resource type="BoxShape3D" id="NorthSouthBoundsShape"]
size = Vector3(180, 12, 2) size = Vector3(120, 14, 2)
[sub_resource type="BoxShape3D" id="EastWestBoundsShape"] [sub_resource type="BoxShape3D" id="EastWestBoundsShape"]
size = Vector3(2, 12, 220) size = Vector3(2, 14, 90)
[sub_resource type="BoxShape3D" id="FailsafeShape"] [sub_resource type="BoxShape3D" id="FailsafeShape"]
size = Vector3(178, 5, 218) size = Vector3(118, 4, 88)
[node name="TestWorld" type="Node3D"] [node name="TestWorld" type="Node3D"]
script = ExtResource("1_world") script = ExtResource("1_world")
@ -54,62 +33,18 @@ rotation_degrees = Vector3(-54, -32, 0)
light_energy = 1.1 light_energy = 1.1
shadow_enabled = true shadow_enabled = true
[node name="SeabedBoundary" type="StaticBody3D" parent="."]
position = Vector3(0, -6.5, -38)
[node name="CollisionShape3D" type="CollisionShape3D" parent="SeabedBoundary"]
shape = SubResource("SeabedShape")
[node name="MeshInstance3D" type="MeshInstance3D" parent="SeabedBoundary"]
mesh = SubResource("SeabedMesh")
material_override = SubResource("SeabedMaterial")
[node name="Regions" type="Node3D" parent="."] [node name="Regions" type="Node3D" parent="."]
[node name="VillageRegion" parent="Regions" instance=ExtResource("2_village")] [node name="StarterIslandRegion" parent="Regions" instance=ExtResource("2_island")]
position = Vector3(0, 0, 15)
[node name="StarterPondRegion" parent="Regions" instance=ExtResource("3_pond")]
position = Vector3(-42, 0, 15)
[node name="RiverRegion" parent="Regions" instance=ExtResource("4_river")]
position = Vector3(0, 0, -40)
[node name="LakeRegion" parent="Regions" instance=ExtResource("5_lake")]
position = Vector3(53, 0, -25)
[node name="MarshRegion" parent="Regions" instance=ExtResource("6_marsh")]
position = Vector3(56, 0, 38)
[node name="CoastalDockRegion" parent="Regions" instance=ExtResource("7_coast")]
position = Vector3(0, 0, -103)
[node name="Connectors" type="Node3D" parent="."]
[node name="VillageRiverPath" type="StaticBody3D" parent="Connectors"]
position = Vector3(0, -3, -7)
[node name="Shape" type="CollisionShape3D" parent="Connectors/VillageRiverPath"]
shape = SubResource("RiverPathShape")
[node name="Mesh" type="MeshInstance3D" parent="Connectors/VillageRiverPath"]
mesh = SubResource("RiverPathMesh")
material_override = SubResource("PathMaterial")
[node name="VillageMarshPath" type="StaticBody3D" parent="Connectors"]
position = Vector3(26.5, -3, 28)
[node name="Shape" type="CollisionShape3D" parent="Connectors/VillageMarshPath"]
shape = SubResource("MarshPathShape")
[node name="Mesh" type="MeshInstance3D" parent="Connectors/VillageMarshPath"]
mesh = SubResource("MarshPathMesh")
material_override = SubResource("PathMaterial")
[node name="Safety" type="Node3D" parent="."] [node name="Safety" type="Node3D" parent="."]
[node name="BelowWorldFailsafe" type="Area3D" parent="Safety"] [node name="BelowWorldFailsafe" type="Area3D" parent="Safety"]
position = Vector3(0, -5, -38) position = Vector3(12, -7, 0)
collision_layer = 8 collision_layer = 8
collision_mask = 2 collision_mask = 2
script = ExtResource("8_water_trigger") script = ExtResource("3_water_trigger")
surface_height = 0.2 surface_height = 0.3
[node name="FailsafeShape" type="CollisionShape3D" parent="Safety/BelowWorldFailsafe"] [node name="FailsafeShape" type="CollisionShape3D" parent="Safety/BelowWorldFailsafe"]
shape = SubResource("FailsafeShape") shape = SubResource("FailsafeShape")
@ -117,21 +52,25 @@ shape = SubResource("FailsafeShape")
[node name="WorldBounds" type="Node3D" parent="."] [node name="WorldBounds" type="Node3D" parent="."]
[node name="North" type="StaticBody3D" parent="WorldBounds"] [node name="North" type="StaticBody3D" parent="WorldBounds"]
position = Vector3(0, 5, 72) position = Vector3(12, 5, 45)
[node name="Shape" type="CollisionShape3D" parent="WorldBounds/North"] [node name="Shape" type="CollisionShape3D" parent="WorldBounds/North"]
shape = SubResource("NorthSouthBoundsShape") shape = SubResource("NorthSouthBoundsShape")
[node name="South" type="StaticBody3D" parent="WorldBounds"] [node name="South" type="StaticBody3D" parent="WorldBounds"]
position = Vector3(0, 5, -148) position = Vector3(12, 5, -45)
[node name="Shape" type="CollisionShape3D" parent="WorldBounds/South"] [node name="Shape" type="CollisionShape3D" parent="WorldBounds/South"]
shape = SubResource("NorthSouthBoundsShape") shape = SubResource("NorthSouthBoundsShape")
[node name="West" type="StaticBody3D" parent="WorldBounds"] [node name="West" type="StaticBody3D" parent="WorldBounds"]
position = Vector3(-90, 5, -38) position = Vector3(-48, 5, 0)
[node name="Shape" type="CollisionShape3D" parent="WorldBounds/West"] [node name="Shape" type="CollisionShape3D" parent="WorldBounds/West"]
shape = SubResource("EastWestBoundsShape") shape = SubResource("EastWestBoundsShape")
[node name="East" type="StaticBody3D" parent="WorldBounds"] [node name="East" type="StaticBody3D" parent="WorldBounds"]
position = Vector3(90, 5, -38) position = Vector3(72, 5, 0)
[node name="Shape" type="CollisionShape3D" parent="WorldBounds/East"] [node name="Shape" type="CollisionShape3D" parent="WorldBounds/East"]
shape = SubResource("EastWestBoundsShape") shape = SubResource("EastWestBoundsShape")