Add playable starter island
This commit is contained in:
parent
633bbd9a88
commit
8032d266ec
14 changed files with 402 additions and 173 deletions
BIN
art/exported/environment/terrain/starter_island.glb
Normal file
BIN
art/exported/environment/terrain/starter_island.glb
Normal file
Binary file not shown.
45
art/exported/environment/terrain/starter_island.glb.import
Normal file
45
art/exported/environment/terrain/starter_island.glb.import
Normal 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
|
||||||
0
art/source/environment/terrain/.gdignore
Normal file
0
art/source/environment/terrain/.gdignore
Normal file
BIN
art/source/environment/terrain/starter_island.blend
Normal file
BIN
art/source/environment/terrain/starter_island.blend
Normal file
Binary file not shown.
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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.
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
66
world/regions/starter_island_region.gd
Normal file
66
world/regions/starter_island_region.gd
Normal 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
|
||||||
1
world/regions/starter_island_region.gd.uid
Normal file
1
world/regions/starter_island_region.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://j8syuqdau7vl
|
||||||
185
world/regions/starter_island_region.tscn
Normal file
185
world/regions/starter_island_region.tscn
Normal 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)
|
||||||
|
|
@ -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]:
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue