Add starter RV progression and fishing feedback
This commit is contained in:
parent
eed361681a
commit
d8bf59bca0
47 changed files with 2268 additions and 467 deletions
|
|
@ -12,6 +12,9 @@ const PlayerStorageInteractionType = preload(
|
|||
const DecorShopInteractionType = preload(
|
||||
"res://world/decor_shop_interaction.gd"
|
||||
)
|
||||
const RVUpgradeInteractionType = preload(
|
||||
"res://world/rv_upgrade_interaction.gd"
|
||||
)
|
||||
const PrecipitationOcclusionType = preload(
|
||||
"res://world/environment/precipitation_occlusion.gd"
|
||||
)
|
||||
|
|
@ -52,6 +55,8 @@ const WATER_RECOVERY_FOOTPRINT_RADIUS := 0.6
|
|||
const WATER_RECOVERY_INSET_STEP := 0.25
|
||||
const WATER_RECOVERY_MAXIMUM_INSET := 1.5
|
||||
const WATER_RECOVERY_SEARCH_EXPANSIONS: Array[float] = [1.5, 4.0, 12.0]
|
||||
const HOME_GROUND_HEIGHT_TOLERANCE := 0.5
|
||||
const HOME_ELEVATION_HEIGHT_TOLERANCE := 0.6
|
||||
const PROP_SURFACE_SAMPLE_DIRECTIONS: Array[Vector2] = [
|
||||
Vector2(1.0, 0.0),
|
||||
Vector2(0.70710678, 0.70710678),
|
||||
|
|
@ -86,9 +91,13 @@ const PROCEDURAL_PROP_GROUPS: Array[StringName] = [
|
|||
@onready var _decor_shop: DecorShopInteractionType = (
|
||||
$Interactables/DecorShopWorld/InteractionArea
|
||||
)
|
||||
@onready var _rv_upgrade_shop: RVUpgradeInteractionType = (
|
||||
$Interactables/RVUpgradeShopWorld/InteractionArea
|
||||
)
|
||||
@onready var _shop_root: Node3D = %FishingShopWorld
|
||||
@onready var _storage_root: Node3D = %PlayerStorageBox
|
||||
@onready var _decor_shop_root: Node3D = %DecorShopWorld
|
||||
@onready var _rv_upgrade_shop_root: Node3D = %RVUpgradeShopWorld
|
||||
@onready var _decorations: Node3D = %Decorations
|
||||
@onready var _tree_anchors: GatherableAnchorSet3D = %ReachableTreeTrunks
|
||||
@onready var _diggable_beach: DiggableArea3D = %DiggableBeach
|
||||
|
|
@ -104,6 +113,7 @@ var _placed_prop_groups: Array[StringName] = []
|
|||
var _placed_group_coordinates: Dictionary[StringName, Array] = {}
|
||||
var _biome_assignments: Dictionary[Vector2i, StringName] = {}
|
||||
var _water_recovery_triangles_by_coordinate: Dictionary[Vector2i, Array] = {}
|
||||
var _home_accessible_elevations_by_coordinate: Dictionary[Vector2i, Array] = {}
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
|
|
@ -159,6 +169,10 @@ func get_decor_shop() -> DecorShopInteractionType:
|
|||
return _decor_shop
|
||||
|
||||
|
||||
func get_rv_upgrade_shop() -> RVUpgradeInteractionType:
|
||||
return _rv_upgrade_shop
|
||||
|
||||
|
||||
func get_saltwater_shoreline_mesh() -> MeshInstance3D:
|
||||
return _shoreline_reference
|
||||
|
||||
|
|
@ -184,6 +198,7 @@ func get_spawn_surface_triangles(
|
|||
material_names: Array[StringName],
|
||||
minimum_global_y: float,
|
||||
minimum_up_dot: float = 0.6,
|
||||
maximum_global_y: float = 100.0,
|
||||
) -> Array[PackedVector3Array]:
|
||||
var triangles: Array[PackedVector3Array] = []
|
||||
if material_names.is_empty():
|
||||
|
|
@ -204,10 +219,27 @@ func get_spawn_surface_triangles(
|
|||
mesh.surface_get_arrays(surface_index),
|
||||
minimum_global_y,
|
||||
minimum_up_dot,
|
||||
maximum_global_y,
|
||||
)
|
||||
return triangles
|
||||
|
||||
|
||||
func is_home_exterior_position_accessible(position: Vector3) -> bool:
|
||||
var local_position := _generator.to_local(position)
|
||||
if local_position.y <= HOME_GROUND_HEIGHT_TOLERANCE:
|
||||
return true
|
||||
var coordinate := _generator.coordinate_for_local_position(local_position)
|
||||
for value: Variant in _home_accessible_elevations_by_coordinate.get(
|
||||
coordinate,
|
||||
[],
|
||||
):
|
||||
if absf(local_position.y - float(value)) <= (
|
||||
HOME_ELEVATION_HEIGHT_TOLERANCE
|
||||
):
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
func get_water_recovery_position(
|
||||
entry_position: Vector3,
|
||||
fallback_position: Vector3,
|
||||
|
|
@ -242,6 +274,7 @@ func get_water_recovery_position(
|
|||
func _on_generation_completed(summary: Dictionary) -> void:
|
||||
_diggable_beach.invalidate_surface_cache()
|
||||
var records: Array[Dictionary] = _generator.placement_records()
|
||||
_cache_home_accessible_elevations(records)
|
||||
_assign_biomes(records, summary)
|
||||
var spawn_position := Vector3.ZERO
|
||||
_clear_children(_decorations)
|
||||
|
|
@ -388,6 +421,97 @@ func _on_generation_completed(summary: Dictionary) -> void:
|
|||
world_generated.emit(_current_seed, summary)
|
||||
|
||||
|
||||
func _cache_home_accessible_elevations(
|
||||
records: Array[Dictionary],
|
||||
) -> void:
|
||||
_home_accessible_elevations_by_coordinate.clear()
|
||||
var records_by_coordinate: Dictionary[Vector2i, Dictionary] = {}
|
||||
var elevation_tiers: Dictionary[int, bool] = {}
|
||||
for record: Dictionary in records:
|
||||
var coordinate: Vector2i = record.get(
|
||||
"coordinate",
|
||||
Vector2i(-1, -1),
|
||||
)
|
||||
records_by_coordinate[coordinate] = record
|
||||
for tier: int in _elevation_tiers_for_tags(
|
||||
record.get("tags", PackedStringArray())
|
||||
):
|
||||
elevation_tiers[tier] = true
|
||||
var visited: Dictionary[String, bool] = {}
|
||||
for tier: int in elevation_tiers:
|
||||
var elevation_tag := "elevation_%d" % tier
|
||||
for coordinate: Vector2i in records_by_coordinate:
|
||||
var visit_key := _home_elevation_visit_key(coordinate, tier)
|
||||
if visited.has(visit_key):
|
||||
continue
|
||||
var record: Dictionary = records_by_coordinate[coordinate]
|
||||
var tags: PackedStringArray = record.get(
|
||||
"tags",
|
||||
PackedStringArray(),
|
||||
)
|
||||
if elevation_tag not in tags:
|
||||
continue
|
||||
var component: Array[Vector2i] = []
|
||||
var pending: Array[Vector2i] = [coordinate]
|
||||
var has_ramp := false
|
||||
while not pending.is_empty():
|
||||
var current: Vector2i = pending.pop_back()
|
||||
var current_key := _home_elevation_visit_key(current, tier)
|
||||
if visited.has(current_key):
|
||||
continue
|
||||
var current_record: Dictionary = records_by_coordinate.get(
|
||||
current,
|
||||
{},
|
||||
)
|
||||
var current_tags: PackedStringArray = current_record.get(
|
||||
"tags",
|
||||
PackedStringArray(),
|
||||
)
|
||||
if elevation_tag not in current_tags:
|
||||
continue
|
||||
visited[current_key] = true
|
||||
component.append(current)
|
||||
has_ramp = has_ramp or "ramp" in current_tags
|
||||
for offset: Vector2i in [
|
||||
Vector2i.LEFT,
|
||||
Vector2i.RIGHT,
|
||||
Vector2i.UP,
|
||||
Vector2i.DOWN,
|
||||
]:
|
||||
pending.append(current + offset)
|
||||
if not has_ramp:
|
||||
continue
|
||||
var surface_height := (
|
||||
float(tier - 1) * _generator.elevated_cliff_level_height
|
||||
)
|
||||
for component_coordinate: Vector2i in component:
|
||||
var heights: Array = (
|
||||
_home_accessible_elevations_by_coordinate.get(
|
||||
component_coordinate,
|
||||
[],
|
||||
)
|
||||
)
|
||||
heights.append(surface_height)
|
||||
_home_accessible_elevations_by_coordinate[
|
||||
component_coordinate
|
||||
] = heights
|
||||
|
||||
|
||||
func _elevation_tiers_for_tags(tags: PackedStringArray) -> Array[int]:
|
||||
var tiers: Array[int] = []
|
||||
for tag_value: String in tags:
|
||||
if not tag_value.begins_with("elevation_"):
|
||||
continue
|
||||
var suffix := tag_value.trim_prefix("elevation_")
|
||||
if suffix.is_valid_int():
|
||||
tiers.append(suffix.to_int())
|
||||
return tiers
|
||||
|
||||
|
||||
func _home_elevation_visit_key(coordinate: Vector2i, tier: int) -> String:
|
||||
return "%d:%d:%d" % [tier, coordinate.x, coordinate.y]
|
||||
|
||||
|
||||
func _mark_precipitation_occluders() -> void:
|
||||
for prop: Node in _decorations.get_children():
|
||||
var prop_group := prop.get_meta(&"terrain_prop_group", &"") as StringName
|
||||
|
|
@ -441,6 +565,8 @@ func _place_spawn_amenities(center: Vector3) -> void:
|
|||
_storage_root.rotation.y = PI * 0.5
|
||||
_decor_shop_root.position = center + Vector3(-2.4, 0.0, 1.2)
|
||||
_decor_shop_root.rotation.y = PI * 0.5
|
||||
_rv_upgrade_shop_root.position = center + Vector3(-2.35, 0.0, -1.35)
|
||||
_rv_upgrade_shop_root.rotation.y = PI
|
||||
|
||||
|
||||
func _configure_static_water() -> void:
|
||||
|
|
@ -1304,6 +1430,7 @@ func _terrain_surface_triangles_by_coordinate(
|
|||
mesh_instance.mesh.surface_get_arrays(surface_index),
|
||||
-INF,
|
||||
0.35,
|
||||
100.0,
|
||||
)
|
||||
if triangles.is_empty():
|
||||
continue
|
||||
|
|
@ -1651,6 +1778,7 @@ func _append_surface_triangles(
|
|||
arrays: Array,
|
||||
minimum_global_y: float,
|
||||
minimum_up_dot: float,
|
||||
maximum_global_y: float,
|
||||
) -> void:
|
||||
if arrays.size() <= Mesh.ARRAY_INDEX:
|
||||
return
|
||||
|
|
@ -1660,10 +1788,28 @@ func _append_surface_triangles(
|
|||
return
|
||||
if indices.is_empty():
|
||||
for index: int in range(0, vertices.size() - 2, 3):
|
||||
_append_triangle(result, mesh_instance, vertices[index], vertices[index + 1], vertices[index + 2], minimum_global_y, minimum_up_dot)
|
||||
_append_triangle(
|
||||
result,
|
||||
mesh_instance,
|
||||
vertices[index],
|
||||
vertices[index + 1],
|
||||
vertices[index + 2],
|
||||
minimum_global_y,
|
||||
minimum_up_dot,
|
||||
maximum_global_y,
|
||||
)
|
||||
return
|
||||
for index: int in range(0, indices.size() - 2, 3):
|
||||
_append_triangle(result, mesh_instance, vertices[indices[index]], vertices[indices[index + 1]], vertices[indices[index + 2]], minimum_global_y, minimum_up_dot)
|
||||
_append_triangle(
|
||||
result,
|
||||
mesh_instance,
|
||||
vertices[indices[index]],
|
||||
vertices[indices[index + 1]],
|
||||
vertices[indices[index + 2]],
|
||||
minimum_global_y,
|
||||
minimum_up_dot,
|
||||
maximum_global_y,
|
||||
)
|
||||
|
||||
|
||||
func _append_triangle(
|
||||
|
|
@ -1674,11 +1820,15 @@ func _append_triangle(
|
|||
local_c: Vector3,
|
||||
minimum_global_y: float,
|
||||
minimum_up_dot: float,
|
||||
maximum_global_y: float,
|
||||
) -> void:
|
||||
var a := mesh_instance.to_global(local_a)
|
||||
var b := mesh_instance.to_global(local_b)
|
||||
var c := mesh_instance.to_global(local_c)
|
||||
if minf(a.y, minf(b.y, c.y)) <= minimum_global_y:
|
||||
if (
|
||||
maxf(a.y, maxf(b.y, c.y)) <= minimum_global_y
|
||||
or minf(a.y, minf(b.y, c.y)) >= maximum_global_y
|
||||
):
|
||||
return
|
||||
var cross := (b - a).cross(c - a)
|
||||
if cross.length_squared() <= 0.0000001:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=15 format=3]
|
||||
[gd_scene load_steps=16 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://world/generation/generated_world_region.gd" id="1_region"]
|
||||
[ext_resource type="Script" path="res://world/generation/terrain_chunk_generator.gd" id="2_generator"]
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
[ext_resource type="Resource" path="res://world/generation/props/terrain_prop_catalog.tres" id="12_prop_catalog"]
|
||||
[ext_resource type="Resource" path="res://world/generation/biomes/terrain_biome_catalog.tres" id="13_biome_catalog"]
|
||||
[ext_resource type="PackedScene" path="res://world/interactables/decor_shop_world.tscn" id="14_decor_shop"]
|
||||
[ext_resource type="PackedScene" path="res://world/interactables/rv_upgrade_shop_world.tscn" id="15_rv_upgrade"]
|
||||
|
||||
[node name="GeneratedWorldRegion" type="Node3D"]
|
||||
script = ExtResource("1_region")
|
||||
|
|
@ -102,6 +103,9 @@ unique_name_in_owner = true
|
|||
[node name="DecorShopWorld" parent="Interactables" instance=ExtResource("14_decor_shop")]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="RVUpgradeShopWorld" parent="Interactables" instance=ExtResource("15_rv_upgrade")]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="Decorations" type="Node3D" parent="."]
|
||||
unique_name_in_owner = true
|
||||
|
||||
|
|
|
|||
|
|
@ -4414,6 +4414,19 @@ func chunk_position(coordinate: Vector2i) -> Vector3:
|
|||
)
|
||||
|
||||
|
||||
func coordinate_for_local_position(position: Vector3) -> Vector2i:
|
||||
if catalog == null or catalog.chunk_size <= 0.0:
|
||||
return Vector2i(-1, -1)
|
||||
var half_grid := Vector2(
|
||||
float(grid_size.x - 1) * 0.5,
|
||||
float(grid_size.y - 1) * 0.5,
|
||||
)
|
||||
return Vector2i(
|
||||
roundi(position.x / catalog.chunk_size + half_grid.x),
|
||||
roundi(position.z / catalog.chunk_size + half_grid.y),
|
||||
)
|
||||
|
||||
|
||||
func get_generated_chunks_root() -> Node3D:
|
||||
return _generated_chunks
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue