Compare commits
No commits in common. "a4e612c1d37e9f4c650c66704509614d0fc3e2c8" and "1dabdd0d232d05df1ad78c4599ed9e7b95770f1d" have entirely different histories.
a4e612c1d3
...
1dabdd0d23
30 changed files with 1106 additions and 746 deletions
Binary file not shown.
|
Before Width: | Height: | Size: 554 B |
|
|
@ -1,41 +0,0 @@
|
||||||
[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
|
|
||||||
Binary file not shown.
|
|
@ -118,7 +118,7 @@ var _new_cast_press_armed: bool = true
|
||||||
var _bobber_water_position: Vector3
|
var _bobber_water_position: Vector3
|
||||||
var _fight_start_position: Vector3
|
var _fight_start_position: Vector3
|
||||||
var _cooldown_status: String = ""
|
var _cooldown_status: String = ""
|
||||||
var _fishable_query_shape: CylinderShape3D = CylinderShape3D.new()
|
var _fishable_query_shape: SphereShape3D = SphereShape3D.new()
|
||||||
var _fish_selector: FishSelectorType = FishSelectorType.new()
|
var _fish_selector: FishSelectorType = FishSelectorType.new()
|
||||||
var _selected_water_region: FishableWaterRegionType
|
var _selected_water_region: FishableWaterRegionType
|
||||||
var _selection_context: FishingContextType
|
var _selection_context: FishingContextType
|
||||||
|
|
@ -966,7 +966,7 @@ func _calculate_cast_target(distance: float) -> Vector3:
|
||||||
target
|
target
|
||||||
)
|
)
|
||||||
if water_region != null:
|
if water_region != null:
|
||||||
target.y = water_region.get_surface_height()
|
target.y = water_region.surface_height
|
||||||
_presentation.set_water_surface_height(target.y)
|
_presentation.set_water_surface_height(target.y)
|
||||||
else:
|
else:
|
||||||
_presentation.reset_water_surface_height()
|
_presentation.reset_water_surface_height()
|
||||||
|
|
@ -982,12 +982,11 @@ func get_fishable_water_region(
|
||||||
target: Vector3,
|
target: Vector3,
|
||||||
) -> FishableWaterRegionType:
|
) -> FishableWaterRegionType:
|
||||||
_fishable_query_shape.radius = fishable_query_radius
|
_fishable_query_shape.radius = fishable_query_radius
|
||||||
_fishable_query_shape.height = preview_ray_length
|
|
||||||
var query := PhysicsShapeQueryParameters3D.new()
|
var query := PhysicsShapeQueryParameters3D.new()
|
||||||
query.shape = _fishable_query_shape
|
query.shape = _fishable_query_shape
|
||||||
query.transform = Transform3D(
|
query.transform = Transform3D(
|
||||||
Basis.IDENTITY,
|
Basis.IDENTITY,
|
||||||
Vector3(target.x, target.y, target.z)
|
Vector3(target.x, _presentation.get_water_surface_height(), target.z)
|
||||||
)
|
)
|
||||||
query.collision_mask = fishable_surface_mask
|
query.collision_mask = fishable_surface_mask
|
||||||
query.collide_with_areas = true
|
query.collide_with_areas = true
|
||||||
|
|
|
||||||
|
|
@ -1,88 +0,0 @@
|
||||||
# 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.
|
|
||||||
73
world/README-WORLD-GRAYBOX.md
Normal file
73
world/README-WORLD-GRAYBOX.md
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
# 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.
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
@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 +0,0 @@
|
||||||
uid://b71576njgcgyw
|
|
||||||
|
|
@ -1,38 +1,9 @@
|
||||||
@tool
|
|
||||||
class_name FishableWaterRegion
|
class_name FishableWaterRegion
|
||||||
extends Area3D
|
extends Area3D
|
||||||
|
|
||||||
const FishPoolType = preload("res://fish/fish_pool.gd")
|
const FishPoolType = preload("res://fish/fish_pool.gd")
|
||||||
|
|
||||||
enum SurfaceHeightMode {
|
|
||||||
EXPLICIT,
|
|
||||||
PARENT_GLOBAL_Y,
|
|
||||||
}
|
|
||||||
|
|
||||||
@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_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
|
@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,78 +1,64 @@
|
||||||
[gd_scene load_steps=11 format=3]
|
[gd_scene load_steps=10 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://world/fishing_shop_interaction.gd" id="1_shop"]
|
[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"]
|
[sub_resource type="BoxMesh" id="CounterMesh"]
|
||||||
resource_local_to_scene = true
|
|
||||||
size = Vector3(4.2, 1.25, 1.8)
|
size = Vector3(4.2, 1.25, 1.8)
|
||||||
|
|
||||||
[sub_resource type="BoxMesh" id="RoofMesh"]
|
[sub_resource type="BoxMesh" id="RoofMesh"]
|
||||||
resource_local_to_scene = true
|
|
||||||
size = Vector3(5.2, 0.35, 3.2)
|
size = Vector3(5.2, 0.35, 3.2)
|
||||||
|
|
||||||
[sub_resource type="BoxMesh" id="PostMesh"]
|
[sub_resource type="BoxMesh" id="PostMesh"]
|
||||||
resource_local_to_scene = true
|
|
||||||
size = Vector3(0.28, 3.2, 0.28)
|
size = Vector3(0.28, 3.2, 0.28)
|
||||||
|
|
||||||
[sub_resource type="BoxMesh" id="BackMesh"]
|
[sub_resource type="BoxMesh" id="BackMesh"]
|
||||||
resource_local_to_scene = true
|
|
||||||
size = Vector3(5, 2.8, 0.25)
|
size = Vector3(5, 2.8, 0.25)
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="PrimaryMaterial"]
|
[sub_resource type="StandardMaterial3D" id="PrimaryMaterial"]
|
||||||
resource_local_to_scene = true
|
|
||||||
albedo_color = Color(0.12, 0.68, 0.62, 1)
|
albedo_color = Color(0.12, 0.68, 0.62, 1)
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="AccentMaterial"]
|
[sub_resource type="StandardMaterial3D" id="AccentMaterial"]
|
||||||
resource_local_to_scene = true
|
|
||||||
albedo_color = Color(1, 0.68, 0.18, 1)
|
albedo_color = Color(1, 0.68, 0.18, 1)
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="BackMaterial"]
|
[sub_resource type="StandardMaterial3D" id="BackMaterial"]
|
||||||
resource_local_to_scene = true
|
|
||||||
albedo_color = Color(0.13, 0.34, 0.38, 1)
|
albedo_color = Color(0.13, 0.34, 0.38, 1)
|
||||||
|
|
||||||
[sub_resource type="SphereShape3D" id="InteractionShape"]
|
[sub_resource type="SphereShape3D" id="InteractionShape"]
|
||||||
resource_local_to_scene = true
|
|
||||||
radius = 3.0
|
radius = 3.0
|
||||||
|
|
||||||
[sub_resource type="BoxShape3D" id="CounterShape"]
|
[sub_resource type="BoxShape3D" id="CounterShape"]
|
||||||
resource_local_to_scene = true
|
|
||||||
size = Vector3(4.2, 1.25, 1.8)
|
size = Vector3(4.2, 1.25, 1.8)
|
||||||
|
|
||||||
[node name="FishingShopWorld" type="Node3D"]
|
[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="Visual" type="Node3D" parent="."]
|
[node name="Visuals" type="Node3D" parent="."]
|
||||||
|
|
||||||
[node name="Counter" type="MeshInstance3D" parent="Visual"]
|
[node name="Counter" type="MeshInstance3D" parent="Visuals"]
|
||||||
position = Vector3(0, 0.625, 0)
|
position = Vector3(0, 0.625, 0)
|
||||||
mesh = SubResource("CounterMesh")
|
mesh = SubResource("CounterMesh")
|
||||||
material_override = SubResource("PrimaryMaterial")
|
material_override = SubResource("PrimaryMaterial")
|
||||||
|
|
||||||
[node name="Back" type="MeshInstance3D" parent="Visual"]
|
[node name="Back" type="MeshInstance3D" parent="Visuals"]
|
||||||
position = Vector3(0, 1.4, 1.25)
|
position = Vector3(0, 1.4, 1.25)
|
||||||
mesh = SubResource("BackMesh")
|
mesh = SubResource("BackMesh")
|
||||||
material_override = SubResource("BackMaterial")
|
material_override = SubResource("BackMaterial")
|
||||||
|
|
||||||
[node name="Roof" type="MeshInstance3D" parent="Visual"]
|
[node name="Roof" type="MeshInstance3D" parent="Visuals"]
|
||||||
position = Vector3(0, 3.15, 0.35)
|
position = Vector3(0, 3.15, 0.35)
|
||||||
mesh = SubResource("RoofMesh")
|
mesh = SubResource("RoofMesh")
|
||||||
material_override = SubResource("AccentMaterial")
|
material_override = SubResource("AccentMaterial")
|
||||||
|
|
||||||
[node name="WestPost" type="MeshInstance3D" parent="Visual"]
|
[node name="WestPost" type="MeshInstance3D" parent="Visuals"]
|
||||||
position = Vector3(-2.15, 1.6, -0.8)
|
position = Vector3(-2.15, 1.6, -0.8)
|
||||||
mesh = SubResource("PostMesh")
|
mesh = SubResource("PostMesh")
|
||||||
material_override = SubResource("PrimaryMaterial")
|
material_override = SubResource("PrimaryMaterial")
|
||||||
|
|
||||||
[node name="EastPost" type="MeshInstance3D" parent="Visual"]
|
[node name="EastPost" type="MeshInstance3D" parent="Visuals"]
|
||||||
position = Vector3(2.15, 1.6, -0.8)
|
position = Vector3(2.15, 1.6, -0.8)
|
||||||
mesh = SubResource("PostMesh")
|
mesh = SubResource("PostMesh")
|
||||||
material_override = SubResource("PrimaryMaterial")
|
material_override = SubResource("PrimaryMaterial")
|
||||||
|
|
||||||
[node name="ShopName" type="Label3D" parent="Visual"]
|
[node name="ShopName" type="Label3D" parent="Visuals"]
|
||||||
position = Vector3(0, 3.7, 0)
|
position = Vector3(0, 3.7, 0)
|
||||||
text = "fishing shop"
|
text = "fishing shop"
|
||||||
font_size = 42
|
font_size = 42
|
||||||
|
|
@ -80,21 +66,18 @@ outline_size = 9
|
||||||
billboard = 1
|
billboard = 1
|
||||||
no_depth_test = true
|
no_depth_test = true
|
||||||
|
|
||||||
[node name="Collision" type="StaticBody3D" parent="."]
|
[node name="StaticCollision" type="StaticBody3D" parent="."]
|
||||||
|
|
||||||
[node name="CounterShape" type="CollisionShape3D" parent="Collision"]
|
[node name="CounterShape" type="CollisionShape3D" parent="StaticCollision"]
|
||||||
position = Vector3(0, 0.625, 0)
|
position = Vector3(0, 0.625, 0)
|
||||||
shape = SubResource("CounterShape")
|
shape = SubResource("CounterShape")
|
||||||
|
|
||||||
[node name="InteractionArea" type="Area3D" parent="."]
|
[node name="FishingShopInteraction" type="Area3D" parent="."]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
position = Vector3(0, 1, -0.3)
|
position = Vector3(0, 1, -0.3)
|
||||||
collision_layer = 0
|
collision_layer = 0
|
||||||
collision_mask = 2
|
collision_mask = 2
|
||||||
script = ExtResource("1_shop")
|
script = ExtResource("1_shop")
|
||||||
|
|
||||||
[node name="InteractionShape" type="CollisionShape3D" parent="InteractionArea"]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="FishingShopInteraction"]
|
||||||
shape = SubResource("InteractionShape")
|
shape = SubResource("InteractionShape")
|
||||||
|
|
||||||
[node name="EntranceMarker" type="Marker3D" parent="."]
|
|
||||||
position = Vector3(0, 0, -2)
|
|
||||||
|
|
|
||||||
|
|
@ -1,46 +1,39 @@
|
||||||
[gd_scene load_steps=6 format=3]
|
[gd_scene load_steps=5 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://world/world_prop.gd" id="1_prop"]
|
|
||||||
|
|
||||||
[sub_resource type="BoxMesh" id="PerchMesh"]
|
[sub_resource type="BoxMesh" id="PerchMesh"]
|
||||||
resource_local_to_scene = true
|
|
||||||
size = Vector3(5, 0.7, 2.2)
|
size = Vector3(5, 0.7, 2.2)
|
||||||
|
|
||||||
[sub_resource type="CylinderMesh" id="PostMesh"]
|
[sub_resource type="CylinderMesh" id="PostMesh"]
|
||||||
resource_local_to_scene = true
|
|
||||||
top_radius = 0.18
|
top_radius = 0.18
|
||||||
bottom_radius = 0.24
|
bottom_radius = 0.24
|
||||||
height = 2.5
|
height = 2.5
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="WoodMaterial"]
|
[sub_resource type="StandardMaterial3D" id="WoodMaterial"]
|
||||||
resource_local_to_scene = true
|
|
||||||
albedo_color = Color(0.46, 0.28, 0.13, 1)
|
albedo_color = Color(0.46, 0.28, 0.13, 1)
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="SignMaterial"]
|
[sub_resource type="StandardMaterial3D" id="SignMaterial"]
|
||||||
resource_local_to_scene = true
|
|
||||||
albedo_color = Color(0.95, 0.82, 0.42, 1)
|
albedo_color = Color(0.95, 0.82, 0.42, 1)
|
||||||
|
|
||||||
[node name="PelicanCoolerPerch" type="Node3D"]
|
[node name="PelicanCoolerPerch" type="Node3D"]
|
||||||
script = ExtResource("1_prop")
|
|
||||||
|
|
||||||
[node name="Visual" type="Node3D" parent="."]
|
[node name="Visuals" type="Node3D" parent="."]
|
||||||
|
|
||||||
[node name="Perch" type="MeshInstance3D" parent="Visual"]
|
[node name="Perch" type="MeshInstance3D" parent="Visuals"]
|
||||||
position = Vector3(0, 1.65, 0)
|
position = Vector3(0, 1.65, 0)
|
||||||
mesh = SubResource("PerchMesh")
|
mesh = SubResource("PerchMesh")
|
||||||
material_override = SubResource("WoodMaterial")
|
material_override = SubResource("WoodMaterial")
|
||||||
|
|
||||||
[node name="WestPost" type="MeshInstance3D" parent="Visual"]
|
[node name="WestPost" type="MeshInstance3D" parent="Visuals"]
|
||||||
position = Vector3(-1.8, 0.7, 0)
|
position = Vector3(-1.8, 0.7, 0)
|
||||||
mesh = SubResource("PostMesh")
|
mesh = SubResource("PostMesh")
|
||||||
material_override = SubResource("WoodMaterial")
|
material_override = SubResource("WoodMaterial")
|
||||||
|
|
||||||
[node name="EastPost" type="MeshInstance3D" parent="Visual"]
|
[node name="EastPost" type="MeshInstance3D" parent="Visuals"]
|
||||||
position = Vector3(1.8, 0.7, 0)
|
position = Vector3(1.8, 0.7, 0)
|
||||||
mesh = SubResource("PostMesh")
|
mesh = SubResource("PostMesh")
|
||||||
material_override = SubResource("WoodMaterial")
|
material_override = SubResource("WoodMaterial")
|
||||||
|
|
||||||
[node name="Sign" type="Label3D" parent="Visual"]
|
[node name="Sign" type="Label3D" parent="Visuals"]
|
||||||
position = Vector3(0, 2.55, 0)
|
position = Vector3(0, 2.55, 0)
|
||||||
text = "sell to pelicans\nfrom the cooler"
|
text = "sell to pelicans\nfrom the cooler"
|
||||||
font_size = 30
|
font_size = 30
|
||||||
|
|
@ -48,7 +41,7 @@ outline_size = 8
|
||||||
billboard = 1
|
billboard = 1
|
||||||
no_depth_test = true
|
no_depth_test = true
|
||||||
|
|
||||||
[node name="ConvenienceLabel" type="Label3D" parent="Visual"]
|
[node name="ConvenienceLabel" type="Label3D" parent="Visuals"]
|
||||||
position = Vector3(0, 1.65, -1.15)
|
position = Vector3(0, 1.65, -1.15)
|
||||||
text = "available anywhere • 0.25x"
|
text = "available anywhere • 0.25x"
|
||||||
font_size = 20
|
font_size = 20
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
[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,24 +1,9 @@
|
||||||
@tool
|
|
||||||
class_name PlayerWaterTrigger
|
class_name PlayerWaterTrigger
|
||||||
extends Area3D
|
extends Area3D
|
||||||
|
|
||||||
signal recovery_requested(player: Player, surface_height: float)
|
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 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
|
@export_range(0.0, 2.0, 0.05) var entry_depth_threshold: float = 0.35
|
||||||
|
|
||||||
var _tracked_players: Array[Player] = []
|
var _tracked_players: Array[Player] = []
|
||||||
|
|
@ -26,15 +11,11 @@ var _triggered_players: Dictionary[StringName, bool] = {}
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
if Engine.is_editor_hint():
|
|
||||||
set_physics_process(false)
|
|
||||||
return
|
|
||||||
body_entered.connect(_on_body_entered)
|
body_entered.connect(_on_body_entered)
|
||||||
body_exited.connect(_on_body_exited)
|
body_exited.connect(_on_body_exited)
|
||||||
|
|
||||||
|
|
||||||
func _physics_process(_delta: float) -> void:
|
func _physics_process(_delta: float) -> void:
|
||||||
var active_surface_height: float = get_surface_height()
|
|
||||||
for player: Player in _tracked_players.duplicate():
|
for player: Player in _tracked_players.duplicate():
|
||||||
if not is_instance_valid(player):
|
if not is_instance_valid(player):
|
||||||
_tracked_players.erase(player)
|
_tracked_players.erase(player)
|
||||||
|
|
@ -44,26 +25,10 @@ func _physics_process(_delta: float) -> void:
|
||||||
continue
|
continue
|
||||||
if (
|
if (
|
||||||
player.get_body_center_position().y
|
player.get_body_center_position().y
|
||||||
<= active_surface_height - entry_depth_threshold
|
<= surface_height - entry_depth_threshold
|
||||||
):
|
):
|
||||||
_triggered_players[player_key] = true
|
_triggered_players[player_key] = true
|
||||||
recovery_requested.emit(player, active_surface_height)
|
recovery_requested.emit(player, 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:
|
func _on_body_entered(body: Node3D) -> void:
|
||||||
|
|
|
||||||
140
world/regions/coastal_dock_region.tscn
Normal file
140
world/regions/coastal_dock_region.tscn
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
[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,5 +1,4 @@
|
||||||
@tool
|
class_name GrayboxRegion
|
||||||
class_name WorldRegion
|
|
||||||
extends Node3D
|
extends Node3D
|
||||||
|
|
||||||
@export var region_id: StringName
|
@export var region_id: StringName
|
||||||
|
|
@ -13,7 +12,10 @@ func get_fishable_water_regions() -> Array[FishableWaterRegion]:
|
||||||
var root: Node = get_node_or_null(fishable_water_root)
|
var root: Node = get_node_or_null(fishable_water_root)
|
||||||
if root == null:
|
if root == null:
|
||||||
return regions
|
return regions
|
||||||
_collect_fishable_water_regions(root, regions)
|
for child: Node in root.get_children():
|
||||||
|
var water: FishableWaterRegion = child as FishableWaterRegion
|
||||||
|
if water != null:
|
||||||
|
regions.append(water)
|
||||||
return regions
|
return regions
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -22,7 +24,10 @@ func get_water_recovery_triggers() -> Array[PlayerWaterTrigger]:
|
||||||
var root: Node = get_node_or_null(water_recovery_root)
|
var root: Node = get_node_or_null(water_recovery_root)
|
||||||
if root == null:
|
if root == null:
|
||||||
return triggers
|
return triggers
|
||||||
_collect_water_recovery_triggers(root, triggers)
|
for child: Node in root.get_children():
|
||||||
|
var trigger: PlayerWaterTrigger = child as PlayerWaterTrigger
|
||||||
|
if trigger != null:
|
||||||
|
triggers.append(trigger)
|
||||||
return triggers
|
return triggers
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -36,25 +41,3 @@ func get_safe_respawn_points() -> Array[SafeRespawnPoint]:
|
||||||
if point != null:
|
if point != null:
|
||||||
points.append(point)
|
points.append(point)
|
||||||
return points
|
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)
|
|
||||||
141
world/regions/lake_region.tscn
Normal file
141
world/regions/lake_region.tscn
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
[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")
|
||||||
164
world/regions/marsh_region.tscn
Normal file
164
world/regions/marsh_region.tscn
Normal file
|
|
@ -0,0 +1,164 @@
|
||||||
|
[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")
|
||||||
143
world/regions/river_region.tscn
Normal file
143
world/regions/river_region.tscn
Normal file
|
|
@ -0,0 +1,143 @@
|
||||||
|
[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,41 +1,27 @@
|
||||||
@tool
|
|
||||||
class_name StarterIslandRegion
|
class_name StarterIslandRegion
|
||||||
extends WorldRegion
|
extends GrayboxRegion
|
||||||
|
|
||||||
const FishingShopInteractionType = preload(
|
const FishingShopInteractionType = preload(
|
||||||
"res://world/fishing_shop_interaction.gd"
|
"res://world/fishing_shop_interaction.gd"
|
||||||
)
|
)
|
||||||
|
|
||||||
@export_group("Owned Nodes")
|
@export var visual_mesh_path: NodePath = (
|
||||||
@export_node_path("MeshInstance3D")
|
^"Visuals/StarterIslandModel/starter_island"
|
||||||
var visual_mesh_path: NodePath = (
|
|
||||||
^"Terrain/Visual/starter_island"
|
|
||||||
)
|
)
|
||||||
@export_node_path("CollisionShape3D")
|
@export var terrain_collision_shape_path: NodePath = (
|
||||||
var terrain_collision_shape_path: NodePath = (
|
^"StaticCollision/Terrain/Shape"
|
||||||
^"Terrain/Collision/Shape"
|
|
||||||
)
|
)
|
||||||
@export_node_path("Marker3D")
|
@export var player_spawn_path: NodePath = ^"PlayerSpawn"
|
||||||
var player_spawn_path: NodePath = ^"PlayerSpawn"
|
@export var fishing_shop_path: NodePath = (
|
||||||
@export_node_path("Area3D")
|
^"Interactables/FishingShopWorld/FishingShopInteraction"
|
||||||
var fishing_shop_path: NodePath = (
|
|
||||||
^"Interactables/FishingShopWorld/InteractionArea"
|
|
||||||
)
|
)
|
||||||
@export_node_path("Node3D")
|
@export var pelican_landmark_path: NodePath = (
|
||||||
var pelican_landmark_path: NodePath = (
|
|
||||||
^"Interactables/PelicanCoolerPerch"
|
^"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:
|
func _ready() -> void:
|
||||||
_apply_grass_material()
|
|
||||||
_build_terrain_collision()
|
_build_terrain_collision()
|
||||||
if Engine.is_editor_hint():
|
|
||||||
update_configuration_warnings()
|
|
||||||
|
|
||||||
|
|
||||||
func get_player_spawn_transform() -> Transform3D:
|
func get_player_spawn_transform() -> Transform3D:
|
||||||
|
|
@ -58,28 +44,6 @@ func has_terrain_collision() -> bool:
|
||||||
return collision_shape != null and collision_shape.shape != null
|
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:
|
func _build_terrain_collision() -> void:
|
||||||
var visual_mesh: MeshInstance3D = (
|
var visual_mesh: MeshInstance3D = (
|
||||||
get_node_or_null(visual_mesh_path) as MeshInstance3D
|
get_node_or_null(visual_mesh_path) as MeshInstance3D
|
||||||
|
|
@ -100,25 +64,3 @@ func _build_terrain_collision() -> void:
|
||||||
push_error("Starter island terrain collision could not be created.")
|
push_error("Starter island terrain collision could not be created.")
|
||||||
return
|
return
|
||||||
collision_shape.shape = terrain_shape
|
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
114
world/regions/starter_pond_region.tscn
Normal file
114
world/regions/starter_pond_region.tscn
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
[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")
|
||||||
179
world/regions/village_region.tscn
Normal file
179
world/regions/village_region.tscn
Normal file
|
|
@ -0,0 +1,179 @@
|
||||||
|
[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)
|
||||||
|
|
@ -19,7 +19,7 @@ const FishingShopInteractionType = preload(
|
||||||
|
|
||||||
func get_player_water_triggers() -> Array[PlayerWaterTrigger]:
|
func get_player_water_triggers() -> Array[PlayerWaterTrigger]:
|
||||||
var triggers: Array[PlayerWaterTrigger] = []
|
var triggers: Array[PlayerWaterTrigger] = []
|
||||||
for region: WorldRegion in _get_regions():
|
for region: GrayboxRegion in _get_regions():
|
||||||
triggers.append_array(region.get_water_recovery_triggers())
|
triggers.append_array(region.get_water_recovery_triggers())
|
||||||
triggers.append(_below_world_failsafe)
|
triggers.append(_below_world_failsafe)
|
||||||
return triggers
|
return triggers
|
||||||
|
|
@ -27,7 +27,7 @@ func get_player_water_triggers() -> Array[PlayerWaterTrigger]:
|
||||||
|
|
||||||
func get_safe_respawn_points() -> Array[SafeRespawnPoint]:
|
func get_safe_respawn_points() -> Array[SafeRespawnPoint]:
|
||||||
var points: Array[SafeRespawnPoint] = []
|
var points: Array[SafeRespawnPoint] = []
|
||||||
for region: WorldRegion in _get_regions():
|
for region: GrayboxRegion in _get_regions():
|
||||||
points.append_array(region.get_safe_respawn_points())
|
points.append_array(region.get_safe_respawn_points())
|
||||||
return points
|
return points
|
||||||
|
|
||||||
|
|
@ -42,7 +42,7 @@ func get_player_spawn_transform() -> Transform3D:
|
||||||
|
|
||||||
func get_fishable_water_regions() -> Array[FishableWaterRegion]:
|
func get_fishable_water_regions() -> Array[FishableWaterRegion]:
|
||||||
var waters: Array[FishableWaterRegion] = []
|
var waters: Array[FishableWaterRegion] = []
|
||||||
for region: WorldRegion in _get_regions():
|
for region: GrayboxRegion in _get_regions():
|
||||||
waters.append_array(region.get_fishable_water_regions())
|
waters.append_array(region.get_fishable_water_regions())
|
||||||
return waters
|
return waters
|
||||||
|
|
||||||
|
|
@ -51,10 +51,10 @@ func get_pelican_convenience_landmark() -> Node3D:
|
||||||
return _starter_island.get_pelican_landmark()
|
return _starter_island.get_pelican_landmark()
|
||||||
|
|
||||||
|
|
||||||
func _get_regions() -> Array[WorldRegion]:
|
func _get_regions() -> Array[GrayboxRegion]:
|
||||||
var regions: Array[WorldRegion] = []
|
var regions: Array[GrayboxRegion] = []
|
||||||
for child: Node in _regions_root.get_children():
|
for child: Node in _regions_root.get_children():
|
||||||
var region: WorldRegion = child as WorldRegion
|
var region: GrayboxRegion = child as GrayboxRegion
|
||||||
if region != null:
|
if region != null:
|
||||||
regions.append(region)
|
regions.append(region)
|
||||||
return regions
|
return regions
|
||||||
|
|
|
||||||
|
|
@ -2,25 +2,14 @@
|
||||||
|
|
||||||
[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/starter_island_region.tscn" id="2_island"]
|
[ext_resource type="PackedScene" path="res://world/regions/starter_island_region.tscn" id="2_island"]
|
||||||
[ext_resource type="Script" path="res://world/below_world_failsafe.gd" id="3_water_trigger"]
|
[ext_resource type="Script" path="res://world/player_water_trigger.gd" id="3_water_trigger"]
|
||||||
|
|
||||||
[sub_resource type="Environment" id="Environment"]
|
[sub_resource type="Environment" id="Environment"]
|
||||||
background_mode = 1
|
background_mode = 1
|
||||||
background_color = Color(0.58, 0.72, 0.82, 1)
|
background_color = Color(0.48, 0.74, 0.92, 1)
|
||||||
background_energy_multiplier = 0.85
|
|
||||||
ambient_light_source = 3
|
ambient_light_source = 3
|
||||||
ambient_light_color = Color(0.78, 0.84, 0.92, 1)
|
ambient_light_color = Color(0.72, 0.78, 0.84, 1)
|
||||||
ambient_light_energy = 0.95
|
ambient_light_energy = 0.72
|
||||||
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"]
|
[sub_resource type="BoxShape3D" id="NorthSouthBoundsShape"]
|
||||||
size = Vector3(120, 14, 2)
|
size = Vector3(120, 14, 2)
|
||||||
|
|
@ -41,11 +30,8 @@ environment = SubResource("Environment")
|
||||||
|
|
||||||
[node name="Sun" type="DirectionalLight3D" parent="Environment"]
|
[node name="Sun" type="DirectionalLight3D" parent="Environment"]
|
||||||
rotation_degrees = Vector3(-54, -32, 0)
|
rotation_degrees = Vector3(-54, -32, 0)
|
||||||
light_color = Color(1, 0.94, 0.88, 1)
|
light_energy = 1.1
|
||||||
light_energy = 0.68
|
|
||||||
shadow_enabled = true
|
shadow_enabled = true
|
||||||
shadow_opacity = 0.58
|
|
||||||
shadow_blur = 2.0
|
|
||||||
|
|
||||||
[node name="Regions" type="Node3D" parent="."]
|
[node name="Regions" type="Node3D" parent="."]
|
||||||
|
|
||||||
|
|
@ -60,7 +46,7 @@ collision_mask = 2
|
||||||
script = ExtResource("3_water_trigger")
|
script = ExtResource("3_water_trigger")
|
||||||
surface_height = 0.3
|
surface_height = 0.3
|
||||||
|
|
||||||
[node name="Coverage" type="CollisionShape3D" parent="Safety/BelowWorldFailsafe"]
|
[node name="FailsafeShape" type="CollisionShape3D" parent="Safety/BelowWorldFailsafe"]
|
||||||
shape = SubResource("FailsafeShape")
|
shape = SubResource("FailsafeShape")
|
||||||
|
|
||||||
[node name="WorldBounds" type="Node3D" parent="."]
|
[node name="WorldBounds" type="Node3D" parent="."]
|
||||||
|
|
|
||||||
|
|
@ -1,158 +0,0 @@
|
||||||
@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 +0,0 @@
|
||||||
uid://dtcgnxl1kmdu1
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
@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 +0,0 @@
|
||||||
uid://c1p4583452rpa
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue