Compare commits
58 Commits
Chunk
...
02311f2ac5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02311f2ac5 | ||
|
|
4408e0d933 | ||
|
|
7331b71877 | ||
|
|
4bd878d2a8 | ||
|
|
c2a6b991dd | ||
| c5232d1082 | |||
|
|
c796ea289d | ||
|
|
a18dc64a4f | ||
| c52b11388a | |||
| ce8a977541 | |||
| 8ceb6cb16b | |||
| bcf854fd74 | |||
| 10b437d236 | |||
| 9c41da14a6 | |||
| 2aa7d1f7d4 | |||
| 040ded5f0b | |||
| ddec91d515 | |||
| d8efa735dd | |||
|
|
9bc7f38d07 | ||
|
|
f4c8775a45 | ||
| 70d3dfe15c | |||
|
|
9827b98b3e | ||
|
|
977e8012aa | ||
| 72d06560b1 | |||
| 9d62d97422 | |||
| c1e99a3b8e | |||
| 8e1ba915a2 | |||
|
|
577b4570da | ||
| 36dff9c070 | |||
| 56591bb907 | |||
| 9f254d9725 | |||
| abae8434fc | |||
|
|
e211f89fca | ||
| 3c7cbdc662 | |||
| 8c7f1c3c82 | |||
| b7308c5d66 | |||
|
|
d709d9236c | ||
|
|
9ee6d08918 | ||
| ff93a7ab2c | |||
| 122ec189eb | |||
| 889334e7a3 | |||
|
|
3521839ed9 | ||
|
|
6a62f92ed5 | ||
|
|
ead4e557c4 | ||
|
|
b868584b78 | ||
| d668804038 | |||
| e8f2c4db84 | |||
| 72c933ba73 | |||
| 8f02afa796 | |||
| 211455f5da | |||
| ab87c7f478 | |||
| b95e8598b2 | |||
|
|
5ddf363368 | ||
| fda8188102 | |||
| 7470937b49 | |||
| 35618b5656 | |||
| 8b2cbab23b | |||
| 174ae98242 |
13
.idea/.gitignore
generated
vendored
Normal file
13
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Rider ignored files
|
||||||
|
/contentModel.xml
|
||||||
|
/modules.xml
|
||||||
|
/projectSettingsUpdater.xml
|
||||||
|
/.idea.tgcc.iml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
4
.idea/encodings.xml
generated
Normal file
4
.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||||
|
</project>
|
||||||
8
.idea/indexLayout.xml
generated
Normal file
8
.idea/indexLayout.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="UserContentModel">
|
||||||
|
<attachedFolders />
|
||||||
|
<explicitIncludes />
|
||||||
|
<explicitExcludes />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
51
core/ai/agents/base/ai_base.gd
Normal file
51
core/ai/agents/base/ai_base.gd
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
extends CharacterBody3D
|
||||||
|
|
||||||
|
class_name AIBase
|
||||||
|
|
||||||
|
@export var speed: float = 4.0
|
||||||
|
var _enable_state_machine: bool = true
|
||||||
|
@export var enable_state_machine: bool:
|
||||||
|
set(value):
|
||||||
|
_enable_state_machine = value
|
||||||
|
toggle_enable_state_machine()
|
||||||
|
get:
|
||||||
|
return _enable_state_machine
|
||||||
|
|
||||||
|
|
||||||
|
@onready var patrol_radius_shape: CollisionShape3D = $%PatrolRadiusShape
|
||||||
|
@onready var nav_agent: NavigationAgent3D = $%NavigationAgent3D
|
||||||
|
@onready var state_machine: StateMachine = $%StateMachine
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
randomize()
|
||||||
|
toggle_enable_state_machine()
|
||||||
|
|
||||||
|
func toggle_enable_state_machine() -> void:
|
||||||
|
state_machine.enable = _enable_state_machine
|
||||||
|
|
||||||
|
func _physics_process(delta: float) -> void:
|
||||||
|
if !_enable_state_machine:
|
||||||
|
return
|
||||||
|
|
||||||
|
state_machine.physics_process(delta)
|
||||||
|
|
||||||
|
if nav_agent.is_navigation_finished():
|
||||||
|
velocity = Vector3.ZERO
|
||||||
|
move_and_slide()
|
||||||
|
return
|
||||||
|
|
||||||
|
var next_point = nav_agent.get_next_path_position()
|
||||||
|
var direction = global_position.direction_to(next_point)
|
||||||
|
|
||||||
|
velocity.x = direction.x * speed
|
||||||
|
velocity.z = direction.z * speed
|
||||||
|
|
||||||
|
move_and_slide()
|
||||||
|
|
||||||
|
func navigate_to_random_point() -> void:
|
||||||
|
var nav_map_rid = get_world_3d().get_navigation_map()
|
||||||
|
var patrol_radius = patrol_radius_shape.shape.radius
|
||||||
|
var target_point_in_space = global_position + Vector3(randf_range(-1, 1), 0, randf_range(-1, 1)).normalized() * randf_range(0, patrol_radius)
|
||||||
|
var closest_valid_point = NavigationServer3D.map_get_closest_point(nav_map_rid, target_point_in_space)
|
||||||
|
nav_agent.target_position = closest_valid_point
|
||||||
1
core/ai/agents/base/ai_base.gd.uid
Normal file
1
core/ai/agents/base/ai_base.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://b30p1yqojbbbk
|
||||||
44
core/ai/agents/base/ai_base.tscn
Normal file
44
core/ai/agents/base/ai_base.tscn
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
[gd_scene format=3 uid="uid://clx701xdwelgx"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://b30p1yqojbbbk" path="res://core/ai/agents/base/ai_base.gd" id="1_4d1nn"]
|
||||||
|
[ext_resource type="Script" uid="uid://ps3vlu2qvmop" path="res://core/ai/framework/state_machine.gd" id="2_q1hg3"]
|
||||||
|
[ext_resource type="Script" uid="uid://nga8qx56iwgu" path="res://core/ai/agents/base/idle_state.gd" id="3_26faq"]
|
||||||
|
[ext_resource type="Script" uid="uid://bngfthvt04ivv" path="res://core/ai/agents/base/patrol_state.gd" id="4_lim44"]
|
||||||
|
|
||||||
|
[sub_resource type="CapsuleMesh" id="CapsuleMesh_mh3lg"]
|
||||||
|
|
||||||
|
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_mh3lg"]
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="SphereShape3D_lim44"]
|
||||||
|
radius = 20.0
|
||||||
|
|
||||||
|
[node name="AiBase" type="CharacterBody3D" unique_id=1228675528]
|
||||||
|
script = ExtResource("1_4d1nn")
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="." unique_id=214482161]
|
||||||
|
mesh = SubResource("CapsuleMesh_mh3lg")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=92811823]
|
||||||
|
shape = SubResource("CapsuleShape3D_mh3lg")
|
||||||
|
|
||||||
|
[node name="NavigationAgent3D" type="NavigationAgent3D" parent="." unique_id=1370024449]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
|
||||||
|
[node name="StateMachine" type="Node" parent="." unique_id=1286404264 node_paths=PackedStringArray("initial_state")]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
script = ExtResource("2_q1hg3")
|
||||||
|
initial_state = NodePath("IdleState")
|
||||||
|
|
||||||
|
[node name="IdleState" type="Node" parent="StateMachine" unique_id=763668255]
|
||||||
|
script = ExtResource("3_26faq")
|
||||||
|
state_id = &"idle"
|
||||||
|
|
||||||
|
[node name="PatrolState" type="Node" parent="StateMachine" unique_id=2054606629]
|
||||||
|
script = ExtResource("4_lim44")
|
||||||
|
state_id = &"patrol"
|
||||||
|
|
||||||
|
[node name="PatrolRadiusShape" type="CollisionShape3D" parent="." unique_id=1379515938]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
shape = SubResource("SphereShape3D_lim44")
|
||||||
|
disabled = true
|
||||||
|
debug_color = Color(1, 1, 0, 1)
|
||||||
26
core/ai/agents/base/idle_state.gd
Normal file
26
core/ai/agents/base/idle_state.gd
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
extends State
|
||||||
|
|
||||||
|
const PATROL_STATE_ID: StringName = &"patrol"
|
||||||
|
|
||||||
|
@export var wait_time: float = 3.0
|
||||||
|
|
||||||
|
var runtime_timer: Timer
|
||||||
|
|
||||||
|
func enter() -> void:
|
||||||
|
runtime_timer = Timer.new()
|
||||||
|
runtime_timer.name = "IdleTimer"
|
||||||
|
add_child(runtime_timer)
|
||||||
|
runtime_timer.one_shot = true
|
||||||
|
runtime_timer.timeout.connect(_on_timer_timeout)
|
||||||
|
runtime_timer.start(wait_time)
|
||||||
|
|
||||||
|
func exit() -> void:
|
||||||
|
if runtime_timer:
|
||||||
|
if runtime_timer.is_connected("timeout", _on_timer_timeout):
|
||||||
|
runtime_timer.timeout.disconnect(_on_timer_timeout)
|
||||||
|
|
||||||
|
runtime_timer.queue_free()
|
||||||
|
runtime_timer = null
|
||||||
|
|
||||||
|
func _on_timer_timeout() -> void:
|
||||||
|
transitioned.emit(self, PATROL_STATE_ID)
|
||||||
1
core/ai/agents/base/idle_state.gd.uid
Normal file
1
core/ai/agents/base/idle_state.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://nga8qx56iwgu
|
||||||
12
core/ai/agents/base/patrol_state.gd
Normal file
12
core/ai/agents/base/patrol_state.gd
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
extends State
|
||||||
|
|
||||||
|
const IDLE_STATE_ID: StringName = &"idle"
|
||||||
|
|
||||||
|
@onready var agent: AIBase = owner
|
||||||
|
|
||||||
|
func enter() -> void:
|
||||||
|
agent.navigate_to_random_point()
|
||||||
|
|
||||||
|
func physics_update(_delta) -> void:
|
||||||
|
if agent.nav_agent.is_navigation_finished():
|
||||||
|
transitioned.emit(self, IDLE_STATE_ID)
|
||||||
1
core/ai/agents/base/patrol_state.gd.uid
Normal file
1
core/ai/agents/base/patrol_state.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://bngfthvt04ivv
|
||||||
20
core/ai/framework/state.gd
Normal file
20
core/ai/framework/state.gd
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
class_name State
|
||||||
|
|
||||||
|
@export var state_id: StringName = &""
|
||||||
|
|
||||||
|
@warning_ignore("unused_signal")
|
||||||
|
signal transitioned(state: State, new_state_id: StringName)
|
||||||
|
|
||||||
|
func enter() -> void:
|
||||||
|
pass
|
||||||
|
|
||||||
|
func exit() -> void:
|
||||||
|
pass
|
||||||
|
|
||||||
|
func update(_delta) -> void:
|
||||||
|
pass
|
||||||
|
|
||||||
|
func physics_update(_delta) -> void:
|
||||||
|
pass
|
||||||
1
core/ai/framework/state.gd.uid
Normal file
1
core/ai/framework/state.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dpso7abi5ftyw
|
||||||
61
core/ai/framework/state_machine.gd
Normal file
61
core/ai/framework/state_machine.gd
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
class_name StateMachine
|
||||||
|
|
||||||
|
@export var initial_state: State
|
||||||
|
|
||||||
|
var current_state: State
|
||||||
|
var states: Dictionary[StringName, State] = {}
|
||||||
|
var is_initialized: bool = false
|
||||||
|
var _enabled: bool = true
|
||||||
|
var enable: bool:
|
||||||
|
set(value):
|
||||||
|
_enabled = value
|
||||||
|
_set_enabled(value)
|
||||||
|
get:
|
||||||
|
return _enabled
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
_initialize_states()
|
||||||
|
_set_enabled(enable)
|
||||||
|
|
||||||
|
func _initialize_states() -> void:
|
||||||
|
if is_initialized:
|
||||||
|
return
|
||||||
|
|
||||||
|
for state in get_children():
|
||||||
|
if state is State:
|
||||||
|
states[state.state_id] = state
|
||||||
|
state.transitioned.connect(_on_state_transition)
|
||||||
|
|
||||||
|
is_initialized = true
|
||||||
|
|
||||||
|
func _set_enabled(value: bool) -> void:
|
||||||
|
_enabled = value
|
||||||
|
|
||||||
|
if not _enabled:
|
||||||
|
return
|
||||||
|
|
||||||
|
_initialize_states()
|
||||||
|
|
||||||
|
if initial_state and current_state == null:
|
||||||
|
current_state = initial_state
|
||||||
|
current_state.enter()
|
||||||
|
|
||||||
|
func physics_process(delta) -> void:
|
||||||
|
if current_state and _enabled:
|
||||||
|
current_state.physics_update(delta)
|
||||||
|
|
||||||
|
func _on_state_transition(state: State, new_state_id: StringName) -> void:
|
||||||
|
if state != current_state:
|
||||||
|
return
|
||||||
|
|
||||||
|
var new_state = states.get(new_state_id)
|
||||||
|
if not new_state:
|
||||||
|
return
|
||||||
|
|
||||||
|
if current_state:
|
||||||
|
current_state.exit()
|
||||||
|
|
||||||
|
current_state = new_state
|
||||||
|
current_state.enter()
|
||||||
1
core/ai/framework/state_machine.gd.uid
Normal file
1
core/ai/framework/state_machine.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://ps3vlu2qvmop
|
||||||
31
core/audio/audio_manager.gd
Normal file
31
core/audio/audio_manager.gd
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
const MIN_VOLUME: float = 0.0
|
||||||
|
const MAX_VOLUME: float = 1.0
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
load_save_data()
|
||||||
|
|
||||||
|
func load_save_data() -> void:
|
||||||
|
for bus_name in GameState.save_data.audio_bus_volumes:
|
||||||
|
_apply_audio_bus_volume(bus_name, GameState.save_data.audio_bus_volumes[bus_name])
|
||||||
|
|
||||||
|
func set_audio_bus_volume(bus_name: StringName, linear_value: float) -> void:
|
||||||
|
var normalized_bus_name := str(bus_name)
|
||||||
|
var clamped_value := clampf(linear_value, MIN_VOLUME, MAX_VOLUME)
|
||||||
|
|
||||||
|
GameState.save_data.audio_bus_volumes[normalized_bus_name] = clamped_value
|
||||||
|
_apply_audio_bus_volume(normalized_bus_name, clamped_value)
|
||||||
|
GameState.save_game()
|
||||||
|
|
||||||
|
func get_audio_bus_volume(bus_name: StringName, default_value: float = 1.0) -> float:
|
||||||
|
return float(GameState.save_data.audio_bus_volumes.get(str(bus_name), default_value))
|
||||||
|
|
||||||
|
func _apply_audio_bus_volume(bus_name: String, linear_value: float) -> void:
|
||||||
|
var bus_index := AudioServer.get_bus_index(bus_name)
|
||||||
|
if bus_index == -1:
|
||||||
|
return
|
||||||
|
|
||||||
|
var clamped_value := clampf(linear_value, MIN_VOLUME, MAX_VOLUME)
|
||||||
|
AudioServer.set_bus_volume_db(bus_index, linear_to_db(clamped_value))
|
||||||
|
AudioServer.set_bus_mute(bus_index, is_zero_approx(clamped_value))
|
||||||
1
core/audio/audio_manager.gd.uid
Normal file
1
core/audio/audio_manager.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dcttbbavtwtsg
|
||||||
56
core/audio/settings/audio_option.gd
Normal file
56
core/audio/settings/audio_option.gd
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
extends VBoxContainer
|
||||||
|
|
||||||
|
class_name AudioOption
|
||||||
|
|
||||||
|
const MIN_VOLUME: float = 0.0
|
||||||
|
const MAX_VOLUME: float = 1.0
|
||||||
|
|
||||||
|
@export var bus_name: StringName = &"Master"
|
||||||
|
@export var label_text: String = "Master Volume"
|
||||||
|
@export_range(0.0, 1.0, 0.01) var default_volume: float = 1.0
|
||||||
|
|
||||||
|
@onready var label: Label = $Label
|
||||||
|
@onready var slider: HSlider = $HSlider
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
slider.min_value = MIN_VOLUME
|
||||||
|
slider.max_value = MAX_VOLUME
|
||||||
|
slider.step = 0.01
|
||||||
|
slider.value_changed.connect(_on_slider_value_changed)
|
||||||
|
refresh()
|
||||||
|
|
||||||
|
func refresh() -> void:
|
||||||
|
label.text = label_text
|
||||||
|
|
||||||
|
if not has_bus():
|
||||||
|
slider.set_value_no_signal(default_volume)
|
||||||
|
slider.editable = false
|
||||||
|
label.text = "%s (bus missing)" % label_text
|
||||||
|
return
|
||||||
|
|
||||||
|
slider.editable = true
|
||||||
|
var saved_volume := AudioManager.get_audio_bus_volume(bus_name, default_volume)
|
||||||
|
slider.set_value_no_signal(saved_volume)
|
||||||
|
apply_current_value()
|
||||||
|
|
||||||
|
func reset_to_default() -> void:
|
||||||
|
slider.value = default_volume
|
||||||
|
|
||||||
|
func apply_current_value() -> void:
|
||||||
|
_set_bus_volume(slider.value)
|
||||||
|
|
||||||
|
func has_bus() -> bool:
|
||||||
|
return get_bus_index() != -1
|
||||||
|
|
||||||
|
func get_bus_index() -> int:
|
||||||
|
return AudioServer.get_bus_index(bus_name)
|
||||||
|
|
||||||
|
func _set_bus_volume(linear_value: float) -> void:
|
||||||
|
if not has_bus():
|
||||||
|
return
|
||||||
|
|
||||||
|
var clamped_value := clampf(linear_value, MIN_VOLUME, MAX_VOLUME)
|
||||||
|
AudioManager.set_audio_bus_volume(bus_name, clamped_value)
|
||||||
|
|
||||||
|
func _on_slider_value_changed(value: float) -> void:
|
||||||
|
_set_bus_volume(value)
|
||||||
1
core/audio/settings/audio_option.gd.uid
Normal file
1
core/audio/settings/audio_option.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://bnh1y560h55vc
|
||||||
14
core/audio/settings/audio_option.tscn
Normal file
14
core/audio/settings/audio_option.tscn
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[gd_scene format=3 uid="uid://cescrovsjlwke"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://bnh1y560h55vc" path="res://core/audio/settings/audio_option.gd" id="1_orafl"]
|
||||||
|
|
||||||
|
[node name="AudioOption" type="VBoxContainer" unique_id=1509773712]
|
||||||
|
custom_minimum_size = Vector2(300, 0)
|
||||||
|
script = ExtResource("1_orafl")
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="." unique_id=781845786]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Master Volume"
|
||||||
|
|
||||||
|
[node name="HSlider" type="HSlider" parent="." unique_id=1286896253]
|
||||||
|
layout_mode = 2
|
||||||
36
core/audio/settings/settings_menu.gd
Normal file
36
core/audio/settings/settings_menu.gd
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
class_name SettingsMenu
|
||||||
|
|
||||||
|
@onready var audio_options_container: VBoxContainer = $%AudioOptionsContainer
|
||||||
|
@onready var reset_button: Button = $%ResetToDefault_Button
|
||||||
|
@onready var close_button: Button = $%Close_Button
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
reset_button.pressed.connect(_on_reset_to_default_button_pressed)
|
||||||
|
close_button.pressed.connect(_on_close_button_pressed)
|
||||||
|
_refresh_audio_options()
|
||||||
|
|
||||||
|
func _get_audio_options() -> Array[AudioOption]:
|
||||||
|
var audio_options: Array[AudioOption] = []
|
||||||
|
|
||||||
|
for child in audio_options_container.get_children():
|
||||||
|
if child is AudioOption:
|
||||||
|
audio_options.append(child)
|
||||||
|
|
||||||
|
return audio_options
|
||||||
|
|
||||||
|
func _refresh_audio_options() -> void:
|
||||||
|
for audio_option in _get_audio_options():
|
||||||
|
audio_option.refresh()
|
||||||
|
|
||||||
|
func _apply_current_audio_values() -> void:
|
||||||
|
for audio_option in _get_audio_options():
|
||||||
|
audio_option.apply_current_value()
|
||||||
|
|
||||||
|
func _on_reset_to_default_button_pressed() -> void:
|
||||||
|
for audio_option in _get_audio_options():
|
||||||
|
audio_option.reset_to_default()
|
||||||
|
|
||||||
|
func _on_close_button_pressed() -> void:
|
||||||
|
visible = false
|
||||||
1
core/audio/settings/settings_menu.gd.uid
Normal file
1
core/audio/settings/settings_menu.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://cvr25q1blyxg
|
||||||
74
core/audio/settings/settings_menu.tscn
Normal file
74
core/audio/settings/settings_menu.tscn
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
[gd_scene format=3 uid="uid://caqf471x0kttc"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://cvr25q1blyxg" path="res://core/audio/settings/settings_menu.gd" id="1_4lekq"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://cescrovsjlwke" path="res://core/audio/settings/audio_option.tscn" id="1_hwcco"]
|
||||||
|
|
||||||
|
[node name="SettingsMenu" type="Control" unique_id=1639777294]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_4lekq")
|
||||||
|
|
||||||
|
[node name="PanelContainer" type="PanelContainer" parent="." unique_id=315821242]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -79.5
|
||||||
|
offset_top = -110.0
|
||||||
|
offset_right = 79.5
|
||||||
|
offset_bottom = 110.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="PanelContainer" unique_id=648635784]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 0
|
||||||
|
theme_override_constants/margin_left = 12
|
||||||
|
theme_override_constants/margin_top = 12
|
||||||
|
theme_override_constants/margin_right = 12
|
||||||
|
theme_override_constants/margin_bottom = 12
|
||||||
|
|
||||||
|
[node name="AudioOptionsContainer" type="VBoxContainer" parent="PanelContainer/MarginContainer" unique_id=824023653]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 12
|
||||||
|
|
||||||
|
[node name="MasterVolume_AudioOption" parent="PanelContainer/MarginContainer/AudioOptionsContainer" unique_id=1509773712 instance=ExtResource("1_hwcco")]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="HSeparator" type="HSeparator" parent="PanelContainer/MarginContainer/AudioOptionsContainer" unique_id=1053430754]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="MusicVolume_AudioOption" parent="PanelContainer/MarginContainer/AudioOptionsContainer" unique_id=690924616 instance=ExtResource("1_hwcco")]
|
||||||
|
layout_mode = 2
|
||||||
|
bus_name = &"Music"
|
||||||
|
label_text = "Music Volume"
|
||||||
|
|
||||||
|
[node name="HSeparator2" type="HSeparator" parent="PanelContainer/MarginContainer/AudioOptionsContainer" unique_id=453716295]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="SFXVolume_AudioOption" parent="PanelContainer/MarginContainer/AudioOptionsContainer" unique_id=2096291127 instance=ExtResource("1_hwcco")]
|
||||||
|
layout_mode = 2
|
||||||
|
bus_name = &"SFX"
|
||||||
|
label_text = "SFX Volume"
|
||||||
|
|
||||||
|
[node name="HSeparator3" type="HSeparator" parent="PanelContainer/MarginContainer/AudioOptionsContainer" unique_id=498553283]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="ResetToDefault_Button" type="Button" parent="PanelContainer/MarginContainer/AudioOptionsContainer" unique_id=720420423]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 0
|
||||||
|
text = "Reset To Default"
|
||||||
|
|
||||||
|
[node name="Close_Button" type="Button" parent="PanelContainer/MarginContainer/AudioOptionsContainer" unique_id=1137906684]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 0
|
||||||
|
text = "Close"
|
||||||
@@ -1,31 +1,66 @@
|
|||||||
extends Node3D
|
extends Node3D
|
||||||
|
|
||||||
|
const CHUNK_TYPE_BIOME: int = 0
|
||||||
|
const CHUNK_TYPE_STRAIGHT_TRACK: int = 1
|
||||||
|
const CHUNK_TYPE_CURVED_TRACK: int = 2
|
||||||
|
|
||||||
|
const CHUNK_GENERATION_STEPS_PER_FRAME: int = 2
|
||||||
|
const CHUNK_CLEANUP_STEPS_PER_FRAME: int = 4
|
||||||
|
const LAMPPOST_WIRE_STEPS_PER_FRAME: int = 1
|
||||||
|
|
||||||
|
const MAX_CHUNK_UNIQUENESS: int = 5
|
||||||
|
const RAILWAY_SCENE_DIRECTORY: String = "res://tgcc/chunk/railway/scene"
|
||||||
|
const RIVER_SIDE_ORDER: Array[String] = ["north", "est", "south", "west"]
|
||||||
|
const RIVER_DIRECTIONS: Dictionary = {
|
||||||
|
"north": Vector2(0.0, -1.0),
|
||||||
|
"est": Vector2(1.0, 0.0),
|
||||||
|
"south": Vector2(0.0, 1.0),
|
||||||
|
"west": Vector2(-1.0, 0.0),
|
||||||
|
}
|
||||||
|
const RIVER_NEIGHBOUR_OFFSETS: Dictionary = {
|
||||||
|
"north": Vector2i(0, -1),
|
||||||
|
"est": Vector2i(1, 0),
|
||||||
|
"south": Vector2i(0, 1),
|
||||||
|
"west": Vector2i(-1, 0),
|
||||||
|
}
|
||||||
|
|
||||||
@export_group("Rails")
|
@export_group("Rails")
|
||||||
@export var rail_path: Path3D
|
@export var rail_path: Path3D #rail path
|
||||||
|
|
||||||
@export_group("Biomes")
|
@export_group("Biomes")
|
||||||
@export var biome_list: Array[Biome]
|
@export var biome_list: Array[Biome] #list of scenes for the biome
|
||||||
|
|
||||||
@export_group("Grid and Area")
|
@export_group("Grid and Area")
|
||||||
@export var chunk_size: float = 20.0
|
@export var chunk_size: float = 20.0 #size of a cell; default 20 (global position is defined dividing x and z for this value)
|
||||||
@export var eye_line: int = 3
|
@export var eye_line: int = 3 #cells to be considerated around the train (e.g. 3 => a square of cells from -3 to 3 around train cell)
|
||||||
@export var district_scale: float = 0.05
|
@export var district_scale: float = 0.05 #noise value to distribuite biome; low values create large area, high values create biome with more variants
|
||||||
|
|
||||||
@export_group("Lamppost")
|
@export_group("Lamppost")
|
||||||
@export var lamppost_wire_material: ShaderMaterial
|
@export var lamppost_wire_material: ShaderMaterial
|
||||||
@export_range(0.01, 1.0) var wire_thickness: float = 0.05
|
@export_range(0.01, 1.0) var wire_thickness: float = 0.05
|
||||||
|
@export var lamppost_dist_factor: int = 10 #max distance of connections
|
||||||
|
|
||||||
var board: Dictionary = {}
|
var board: Dictionary = {}
|
||||||
var last_pos_train: Vector2i = Vector2i(999999, 999999)
|
var last_pos_train: Vector2i = Vector2i(999999, 999999)
|
||||||
var noise_generator: FastNoiseLite
|
var noise_generator: FastNoiseLite
|
||||||
var altitude_generator: FastNoiseLite
|
var altitude_generator: FastNoiseLite
|
||||||
var wire_connections: Dictionary = {}
|
var wire_connections: Dictionary = {}
|
||||||
|
var chunk_candidate_cache: Dictionary = {} #node cache (metadata)
|
||||||
|
var pending_generation_cells: Array[Vector2i] = []
|
||||||
|
var pending_cleanup_cells: Array[Vector2i] = []
|
||||||
|
var pending_wire_cells: Array[Vector2i] = []
|
||||||
|
var pending_wire_lookup: Dictionary = {}
|
||||||
|
var rail_chunk_catalogue: Dictionary = {} #rails chunk list
|
||||||
|
|
||||||
var manual_biome: Biome = null
|
var manual_biome: Biome = null
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
if biome_list.is_empty() or rail_path == null: return
|
if biome_list.is_empty() or rail_path == null: return
|
||||||
|
|
||||||
|
#connect events
|
||||||
|
UIEvents.update_rail_chunks.connect(_update_rail_chunks)
|
||||||
|
|
||||||
|
#noise generator for biome and altitute
|
||||||
noise_generator = FastNoiseLite.new()
|
noise_generator = FastNoiseLite.new()
|
||||||
noise_generator.noise_type = FastNoiseLite.TYPE_PERLIN
|
noise_generator.noise_type = FastNoiseLite.TYPE_PERLIN
|
||||||
noise_generator.seed = randi()
|
noise_generator.seed = randi()
|
||||||
@@ -36,6 +71,10 @@ func _ready() -> void:
|
|||||||
altitude_generator.seed = randi()
|
altitude_generator.seed = randi()
|
||||||
altitude_generator.frequency = district_scale * 0.5
|
altitude_generator.frequency = district_scale * 0.5
|
||||||
|
|
||||||
|
#fill cache with available chunk
|
||||||
|
_warm_chunk_candidate_cache()
|
||||||
|
_warm_rail_chunk_catalogue()
|
||||||
|
#set unique pieces
|
||||||
_update_set_pieces()
|
_update_set_pieces()
|
||||||
|
|
||||||
func _update_set_pieces() -> void:
|
func _update_set_pieces() -> void:
|
||||||
@@ -67,15 +106,18 @@ func _update_set_pieces() -> void:
|
|||||||
print(" ❌ Temple is an invisible ghost.")
|
print(" ❌ Temple is an invisible ghost.")
|
||||||
|
|
||||||
func _destroy_and_regenrate_world() -> void:
|
func _destroy_and_regenrate_world() -> void:
|
||||||
|
_warm_chunk_candidate_cache()
|
||||||
|
_clear_pending_world_work()
|
||||||
|
|
||||||
#Turn off old temples
|
#Turn off old temples
|
||||||
_update_set_pieces()
|
_update_set_pieces()
|
||||||
|
|
||||||
#Destroy all models
|
#Destroy all models
|
||||||
for pos in board.keys():
|
for pos in board.keys():
|
||||||
var cella = board[pos]
|
var cella = board[pos]
|
||||||
if cella["tipo"] == "bioma":
|
if cella["type"] != "obstacle":
|
||||||
if cella.has("nodo") and is_instance_valid(cella["nodo"]):
|
if cella.has("node") and is_instance_valid(cella["node"]):
|
||||||
cella["nodo"].queue_free()
|
cella["node"].queue_free()
|
||||||
|
|
||||||
#Clean board and wire connections
|
#Clean board and wire connections
|
||||||
board.clear()
|
board.clear()
|
||||||
@@ -83,9 +125,16 @@ func _destroy_and_regenrate_world() -> void:
|
|||||||
|
|
||||||
#Create train
|
#Create train
|
||||||
last_pos_train = Vector2i(999999, 999999)
|
last_pos_train = Vector2i(999999, 999999)
|
||||||
_train_radar()
|
if rail_path != null and rail_path.train_instance != null:
|
||||||
last_pos_train = Vector2i(999999, 999999)
|
var train_pos = rail_path.train_instance.global_position
|
||||||
_train_radar()
|
var current_pos = Vector2i(roundi(train_pos.x / chunk_size), roundi(train_pos.z / chunk_size))
|
||||||
|
_refresh_world(current_pos)
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
#based on constant values the queue are evalutated by frame and not all together
|
||||||
|
_drain_cleanup_queue()
|
||||||
|
_drain_generation_queue()
|
||||||
|
_drain_wire_queue()
|
||||||
|
|
||||||
func _physics_process(_delta: float) -> void:
|
func _physics_process(_delta: float) -> void:
|
||||||
if rail_path == null or rail_path.train_instance == null: return
|
if rail_path == null or rail_path.train_instance == null: return
|
||||||
@@ -97,9 +146,7 @@ func _physics_process(_delta: float) -> void:
|
|||||||
|
|
||||||
if current_pos != last_pos_train:
|
if current_pos != last_pos_train:
|
||||||
last_pos_train = current_pos
|
last_pos_train = current_pos
|
||||||
_generate_pieces_around_train(current_pos)
|
_refresh_world(current_pos)
|
||||||
_clean_far_chunks(current_pos)
|
|
||||||
_train_radar()
|
|
||||||
|
|
||||||
func collect_all_chunkinfo(root: Node, list: Array[Node]) -> void:
|
func collect_all_chunkinfo(root: Node, list: Array[Node]) -> void:
|
||||||
if root == null: return
|
if root == null: return
|
||||||
@@ -110,6 +157,301 @@ func collect_all_chunkinfo(root: Node, list: Array[Node]) -> void:
|
|||||||
for child in root.get_children():
|
for child in root.get_children():
|
||||||
collect_all_chunkinfo(child, list)
|
collect_all_chunkinfo(child, list)
|
||||||
|
|
||||||
|
func collect_all_propinfo(root: Node, list: Array[Node]) -> void:
|
||||||
|
if root == null: return
|
||||||
|
|
||||||
|
if "available_props" in root:
|
||||||
|
list.append(root)
|
||||||
|
|
||||||
|
for child in root.get_children():
|
||||||
|
collect_all_propinfo(child, list)
|
||||||
|
|
||||||
|
func _warm_chunk_candidate_cache() -> void:
|
||||||
|
var unique_scenes: Dictionary = {}
|
||||||
|
|
||||||
|
for biome in biome_list:
|
||||||
|
if biome == null:
|
||||||
|
continue
|
||||||
|
for scene in biome.available_chunks:
|
||||||
|
if scene == null:
|
||||||
|
continue
|
||||||
|
unique_scenes[_get_chunk_scene_cache_key(scene)] = scene
|
||||||
|
|
||||||
|
if manual_biome != null:
|
||||||
|
for scene in manual_biome.available_chunks:
|
||||||
|
if scene == null:
|
||||||
|
continue
|
||||||
|
unique_scenes[_get_chunk_scene_cache_key(scene)] = scene
|
||||||
|
|
||||||
|
for scene in unique_scenes.values():
|
||||||
|
_get_chunk_scene_metadata(scene)
|
||||||
|
|
||||||
|
func _warm_rail_chunk_catalogue() -> void:
|
||||||
|
rail_chunk_catalogue.clear()
|
||||||
|
|
||||||
|
var directory := DirAccess.open(RAILWAY_SCENE_DIRECTORY)
|
||||||
|
if directory == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
directory.list_dir_begin()
|
||||||
|
var file_name := directory.get_next()
|
||||||
|
while file_name != "":
|
||||||
|
if not directory.current_is_dir() and file_name.ends_with(".tscn"):
|
||||||
|
var scene_path := "%s/%s" % [RAILWAY_SCENE_DIRECTORY, file_name]
|
||||||
|
var scene := load(scene_path) as PackedScene
|
||||||
|
if scene != null:
|
||||||
|
var chunk_type = _get_chunk_type_from_scene(scene)
|
||||||
|
if chunk_type == CHUNK_TYPE_STRAIGHT_TRACK or chunk_type == CHUNK_TYPE_CURVED_TRACK:
|
||||||
|
if not rail_chunk_catalogue.has(chunk_type):
|
||||||
|
rail_chunk_catalogue[chunk_type] = []
|
||||||
|
rail_chunk_catalogue[chunk_type].append(scene)
|
||||||
|
file_name = directory.get_next()
|
||||||
|
directory.list_dir_end()
|
||||||
|
|
||||||
|
func _get_chunk_scene_cache_key(scene: PackedScene) -> String:
|
||||||
|
if scene == null:
|
||||||
|
return ""
|
||||||
|
if scene.resource_path != "":
|
||||||
|
return scene.resource_path
|
||||||
|
return "scene_%s" % scene.get_instance_id()
|
||||||
|
|
||||||
|
func _get_chunk_scene_metadata(scene: PackedScene) -> Dictionary:
|
||||||
|
if scene == null:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
var key = _get_chunk_scene_cache_key(scene)
|
||||||
|
if chunk_candidate_cache.has(key):
|
||||||
|
return chunk_candidate_cache[key]
|
||||||
|
|
||||||
|
var preview_chunk = scene.instantiate()
|
||||||
|
var info_list: Array[Node] = []
|
||||||
|
collect_all_chunkinfo(preview_chunk, info_list)
|
||||||
|
var info_node = info_list[0] if info_list.size() > 0 else null
|
||||||
|
|
||||||
|
if info_node == null or not info_node.has_method("get_rotated_data"):
|
||||||
|
preview_chunk.queue_free()
|
||||||
|
chunk_candidate_cache[key] = {}
|
||||||
|
return {}
|
||||||
|
|
||||||
|
var info_path: NodePath = NodePath(".")
|
||||||
|
if info_node != preview_chunk:
|
||||||
|
info_path = preview_chunk.get_path_to(info_node)
|
||||||
|
|
||||||
|
var rotations = []
|
||||||
|
for rot in range(4):
|
||||||
|
rotations.append({
|
||||||
|
"rotation": rot,
|
||||||
|
"data": info_node.get_rotated_data(rot)
|
||||||
|
})
|
||||||
|
|
||||||
|
var metadata = {
|
||||||
|
"info_path": info_path,
|
||||||
|
"rotations": rotations,
|
||||||
|
"has_lamppost": "have_lamppost" in info_node and info_node.have_lamppost,
|
||||||
|
"uniqueness": _get_chunk_uniqueness_from_info(info_node),
|
||||||
|
}
|
||||||
|
preview_chunk.queue_free()
|
||||||
|
chunk_candidate_cache[key] = metadata
|
||||||
|
return metadata
|
||||||
|
|
||||||
|
func _get_cached_chunk_info(instance: Node, scene: PackedScene) -> Node:
|
||||||
|
var metadata = _get_chunk_scene_metadata(scene)
|
||||||
|
if metadata.is_empty():
|
||||||
|
return null
|
||||||
|
|
||||||
|
var info_path: NodePath = metadata["info_path"]
|
||||||
|
if String(info_path) == ".":
|
||||||
|
return instance
|
||||||
|
return instance.get_node_or_null(info_path)
|
||||||
|
|
||||||
|
func _get_chunk_type_from_scene(scene: PackedScene) -> int:
|
||||||
|
if scene == null:
|
||||||
|
return CHUNK_TYPE_BIOME
|
||||||
|
|
||||||
|
var preview_chunk = scene.instantiate()
|
||||||
|
var info_list: Array[Node] = []
|
||||||
|
collect_all_chunkinfo(preview_chunk, info_list)
|
||||||
|
var info_node = info_list[0] if info_list.size() > 0 else null
|
||||||
|
var chunk_type = CHUNK_TYPE_BIOME
|
||||||
|
if info_node != null and "chunk_type" in info_node:
|
||||||
|
chunk_type = info_node.chunk_type
|
||||||
|
preview_chunk.queue_free()
|
||||||
|
return chunk_type
|
||||||
|
|
||||||
|
func _clear_pending_world_work() -> void:
|
||||||
|
pending_generation_cells.clear()
|
||||||
|
pending_cleanup_cells.clear()
|
||||||
|
pending_wire_cells.clear()
|
||||||
|
pending_wire_lookup.clear()
|
||||||
|
|
||||||
|
func _collect_replaceable_rail_chunks(root: Node, result: Array[Node3D]) -> void:
|
||||||
|
if root == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
if root is Node3D:
|
||||||
|
var node_3d := root as Node3D
|
||||||
|
if node_3d.scene_file_path.begins_with(RAILWAY_SCENE_DIRECTORY):
|
||||||
|
var info_list: Array[Node] = []
|
||||||
|
collect_all_chunkinfo(node_3d, info_list)
|
||||||
|
var info_node = info_list[0] if info_list.size() > 0 else null
|
||||||
|
if info_node != null and "chunk_type" in info_node:
|
||||||
|
var chunk_type = info_node.chunk_type
|
||||||
|
if chunk_type == CHUNK_TYPE_STRAIGHT_TRACK or chunk_type == CHUNK_TYPE_CURVED_TRACK:
|
||||||
|
result.append(node_3d)
|
||||||
|
return
|
||||||
|
|
||||||
|
for child in root.get_children():
|
||||||
|
_collect_replaceable_rail_chunks(child, result)
|
||||||
|
|
||||||
|
func _pick_replacement_rail_scene(chunk_type: int, current_scene_path: String) -> PackedScene:
|
||||||
|
var candidates: Array = rail_chunk_catalogue.get(chunk_type, [])
|
||||||
|
if candidates.is_empty():
|
||||||
|
return null
|
||||||
|
|
||||||
|
var alternatives: Array[PackedScene] = []
|
||||||
|
for candidate in candidates:
|
||||||
|
var scene := candidate as PackedScene
|
||||||
|
if scene != null and scene.resource_path != current_scene_path:
|
||||||
|
alternatives.append(scene)
|
||||||
|
|
||||||
|
if not alternatives.is_empty():
|
||||||
|
return alternatives.pick_random()
|
||||||
|
return candidates.pick_random() as PackedScene
|
||||||
|
|
||||||
|
func _replace_rail_chunk_instance(chunk_root: Node3D) -> bool:
|
||||||
|
if chunk_root == null or not is_instance_valid(chunk_root):
|
||||||
|
return false
|
||||||
|
|
||||||
|
var info_list: Array[Node] = []
|
||||||
|
collect_all_chunkinfo(chunk_root, info_list)
|
||||||
|
var info_node = info_list[0] if info_list.size() > 0 else null
|
||||||
|
if info_node == null or not "chunk_type" in info_node:
|
||||||
|
return false
|
||||||
|
|
||||||
|
var replacement_scene = _pick_replacement_rail_scene(info_node.chunk_type, chunk_root.scene_file_path)
|
||||||
|
if replacement_scene == null:
|
||||||
|
return false
|
||||||
|
|
||||||
|
var chunk_parent = chunk_root.get_parent()
|
||||||
|
var replacement = replacement_scene.instantiate() as Node3D
|
||||||
|
if chunk_parent == null or replacement == null:
|
||||||
|
return false
|
||||||
|
|
||||||
|
var chunk_index = chunk_root.get_index()
|
||||||
|
var chunk_name = chunk_root.name
|
||||||
|
chunk_root.name = "%s_old" % chunk_name
|
||||||
|
|
||||||
|
replacement.transform = chunk_root.transform
|
||||||
|
chunk_parent.add_child(replacement)
|
||||||
|
chunk_parent.move_child(replacement, chunk_index)
|
||||||
|
replacement.name = chunk_name
|
||||||
|
replacement.owner = chunk_root.owner
|
||||||
|
chunk_root.queue_free()
|
||||||
|
return true
|
||||||
|
|
||||||
|
func _refresh_rail_chunks() -> void:
|
||||||
|
print("update rail chunks")
|
||||||
|
_warm_rail_chunk_catalogue()
|
||||||
|
|
||||||
|
var current_scene: Node = get_tree().current_scene
|
||||||
|
if current_scene == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
var replaceable_chunks: Array[Node3D] = []
|
||||||
|
_collect_replaceable_rail_chunks(current_scene, replaceable_chunks)
|
||||||
|
|
||||||
|
var replaced_count = 0
|
||||||
|
for chunk_root in replaceable_chunks:
|
||||||
|
if _replace_rail_chunk_instance(chunk_root):
|
||||||
|
replaced_count += 1
|
||||||
|
|
||||||
|
if replaced_count > 0:
|
||||||
|
await get_tree().process_frame
|
||||||
|
_destroy_and_regenrate_world()
|
||||||
|
|
||||||
|
func _update_rail_chunks() -> void:
|
||||||
|
call_deferred("_refresh_rail_chunks")
|
||||||
|
|
||||||
|
func _refresh_world(center: Vector2i) -> void:
|
||||||
|
_rebuild_generation_queue(center)
|
||||||
|
_rebuild_cleanup_queue(center)
|
||||||
|
|
||||||
|
func _rebuild_generation_queue(center: Vector2i) -> void:
|
||||||
|
pending_generation_cells.clear()
|
||||||
|
|
||||||
|
for radius in range(eye_line + 1):
|
||||||
|
for x in range(-radius, radius + 1):
|
||||||
|
for z in range(-radius, radius + 1):
|
||||||
|
if maxi(abs(x), abs(z)) != radius:
|
||||||
|
continue
|
||||||
|
|
||||||
|
var grid_pos = center + Vector2i(x, z)
|
||||||
|
if board.has(grid_pos):
|
||||||
|
continue
|
||||||
|
pending_generation_cells.append(grid_pos)
|
||||||
|
|
||||||
|
func _rebuild_cleanup_queue(center: Vector2i) -> void:
|
||||||
|
pending_cleanup_cells.clear()
|
||||||
|
var safe_margin = 2
|
||||||
|
|
||||||
|
for grid_pos in board.keys():
|
||||||
|
var cell = board[grid_pos]
|
||||||
|
if cell["type"] == "obstacle":
|
||||||
|
continue
|
||||||
|
|
||||||
|
var dist_x = abs(grid_pos.x - center.x)
|
||||||
|
var dist_z = abs(grid_pos.y - center.y)
|
||||||
|
if dist_x > eye_line + safe_margin or dist_z > eye_line + safe_margin:
|
||||||
|
pending_cleanup_cells.append(grid_pos)
|
||||||
|
|
||||||
|
func _drain_generation_queue() -> void:
|
||||||
|
var processed = 0
|
||||||
|
while processed < CHUNK_GENERATION_STEPS_PER_FRAME and not pending_generation_cells.is_empty():
|
||||||
|
var grid_pos = pending_generation_cells.pop_front()
|
||||||
|
if board.has(grid_pos):
|
||||||
|
continue
|
||||||
|
|
||||||
|
var is_obstacle = _register_cell_with_ray(grid_pos)
|
||||||
|
if not is_obstacle:
|
||||||
|
_add_compatible_biome(grid_pos)
|
||||||
|
processed += 1
|
||||||
|
|
||||||
|
func _drain_cleanup_queue() -> void:
|
||||||
|
var processed = 0
|
||||||
|
while processed < CHUNK_CLEANUP_STEPS_PER_FRAME and not pending_cleanup_cells.is_empty():
|
||||||
|
var grid_pos = pending_cleanup_cells.pop_front()
|
||||||
|
if not board.has(grid_pos):
|
||||||
|
continue
|
||||||
|
|
||||||
|
var cell = board[grid_pos]
|
||||||
|
if cell["type"] == "obstacle":
|
||||||
|
continue
|
||||||
|
|
||||||
|
if cell.has("node") and is_instance_valid(cell["node"]):
|
||||||
|
cell["node"].queue_free()
|
||||||
|
board.erase(grid_pos)
|
||||||
|
processed += 1
|
||||||
|
|
||||||
|
func _queue_lamppost_wire_connection(grid_pos: Vector2i) -> void:
|
||||||
|
if pending_wire_lookup.has(grid_pos):
|
||||||
|
return
|
||||||
|
pending_wire_lookup[grid_pos] = true
|
||||||
|
pending_wire_cells.append(grid_pos)
|
||||||
|
|
||||||
|
func _drain_wire_queue() -> void:
|
||||||
|
var processed = 0
|
||||||
|
while processed < LAMPPOST_WIRE_STEPS_PER_FRAME and not pending_wire_cells.is_empty():
|
||||||
|
var grid_pos = pending_wire_cells.pop_front()
|
||||||
|
pending_wire_lookup.erase(grid_pos)
|
||||||
|
|
||||||
|
if not board.has(grid_pos):
|
||||||
|
continue
|
||||||
|
if not board[grid_pos].get("have_lamppost", false):
|
||||||
|
continue
|
||||||
|
|
||||||
|
_connect_lamppost_wires(grid_pos)
|
||||||
|
processed += 1
|
||||||
|
|
||||||
func _generate_pieces_around_train(center: Vector2i) -> void:
|
func _generate_pieces_around_train(center: Vector2i) -> void:
|
||||||
for x in range(-eye_line, eye_line + 1):
|
for x in range(-eye_line, eye_line + 1):
|
||||||
for z in range(-eye_line, eye_line + 1):
|
for z in range(-eye_line, eye_line + 1):
|
||||||
@@ -137,6 +479,78 @@ func _get_procedural_biome_name(value: float) -> String:
|
|||||||
var index = clamp(int(normalized_value * biome_list.size()), 0, biome_list.size() - 1)
|
var index = clamp(int(normalized_value * biome_list.size()), 0, biome_list.size() - 1)
|
||||||
return biome_list[index].name
|
return biome_list[index].name
|
||||||
|
|
||||||
|
func _get_chunk_uniqueness_from_info(info_node: Node) -> int:
|
||||||
|
if info_node != null and "uniqueness" in info_node:
|
||||||
|
return clampi(info_node.uniqueness, 0, MAX_CHUNK_UNIQUENESS)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
func _has_nearby_unique_chunk(grid_pos: Vector2i, uniqueness: int) -> bool:
|
||||||
|
if uniqueness <= 0:
|
||||||
|
return false
|
||||||
|
|
||||||
|
for nearby_pos in board.keys():
|
||||||
|
var nearby_uniqueness = int(board[nearby_pos].get("uniqueness", 0))
|
||||||
|
if nearby_uniqueness <= 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
var min_distance = maxi(uniqueness, nearby_uniqueness)
|
||||||
|
var dist_x = abs(nearby_pos.x - grid_pos.x)
|
||||||
|
var dist_z = abs(nearby_pos.y - grid_pos.y)
|
||||||
|
if dist_x <= min_distance and dist_z <= min_distance:
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
func _get_uniqueness_pick_weight(uniqueness: int) -> float:
|
||||||
|
return 1.0 / pow(float(uniqueness + 1), 2.0)
|
||||||
|
|
||||||
|
func _pick_weighted_candidate(candidates: Array) -> Dictionary:
|
||||||
|
var total_weight = 0.0
|
||||||
|
for candidate in candidates:
|
||||||
|
total_weight += candidate.weight
|
||||||
|
|
||||||
|
if total_weight <= 0.0:
|
||||||
|
return candidates.pick_random()
|
||||||
|
|
||||||
|
var target_weight = randf() * total_weight
|
||||||
|
var current_weight = 0.0
|
||||||
|
for candidate in candidates:
|
||||||
|
current_weight += candidate.weight
|
||||||
|
if current_weight >= target_weight:
|
||||||
|
return candidate
|
||||||
|
return candidates.back()
|
||||||
|
|
||||||
|
func _pick_backup_scene(zone_catalogue: Array[PackedScene], grid_pos: Vector2i) -> PackedScene:
|
||||||
|
for scene in zone_catalogue:
|
||||||
|
var metadata = _get_chunk_scene_metadata(scene)
|
||||||
|
var uniqueness = int(metadata.get("uniqueness", 0))
|
||||||
|
if not _has_nearby_unique_chunk(grid_pos, uniqueness):
|
||||||
|
return scene
|
||||||
|
return zone_catalogue[0]
|
||||||
|
|
||||||
|
func _spawn_props_for_chunk(root: Node) -> void:
|
||||||
|
var prop_markers: Array[Node] = []
|
||||||
|
collect_all_propinfo(root, prop_markers)
|
||||||
|
|
||||||
|
for marker in prop_markers:
|
||||||
|
_spawn_prop_for_marker(marker)
|
||||||
|
|
||||||
|
func _spawn_prop_for_marker(marker: Node) -> void:
|
||||||
|
if marker.available_props.is_empty():
|
||||||
|
return
|
||||||
|
|
||||||
|
var prop_scene = marker.available_props.pick_random()
|
||||||
|
if prop_scene == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
var prop_instance = prop_scene.instantiate()
|
||||||
|
var prop_node = prop_instance as Node3D
|
||||||
|
if prop_node == null:
|
||||||
|
prop_instance.queue_free()
|
||||||
|
return
|
||||||
|
|
||||||
|
marker.add_child(prop_node)
|
||||||
|
prop_node.transform = Transform3D.IDENTITY
|
||||||
|
|
||||||
func _register_cell_with_ray(grid_pos: Vector2i) -> bool:
|
func _register_cell_with_ray(grid_pos: Vector2i) -> bool:
|
||||||
if board.has(grid_pos): return true
|
if board.has(grid_pos): return true
|
||||||
|
|
||||||
@@ -181,8 +595,10 @@ func _register_cell_with_ray(grid_pos: Vector2i) -> bool:
|
|||||||
right_info_node = info_list[0]
|
right_info_node = info_list[0]
|
||||||
|
|
||||||
var exit_found = {"north": false, "est": false, "south": false, "west": false}
|
var exit_found = {"north": false, "est": false, "south": false, "west": false}
|
||||||
|
var river_exit_found = {"north": false, "est": false, "south": false, "west": false}
|
||||||
var height_found = {"north": 0, "est": 0, "south": 0, "west": 0}
|
var height_found = {"north": 0, "est": 0, "south": 0, "west": 0}
|
||||||
var have_lamppost = false
|
var have_lamppost = false
|
||||||
|
var uniqueness = 0
|
||||||
|
|
||||||
#Get node info
|
#Get node info
|
||||||
if right_info_node != null:
|
if right_info_node != null:
|
||||||
@@ -190,23 +606,28 @@ func _register_cell_with_ray(grid_pos: Vector2i) -> bool:
|
|||||||
var rotation_steps = roundi(rad_to_deg(right_info_node.global_rotation.y) / -90.0)
|
var rotation_steps = roundi(rad_to_deg(right_info_node.global_rotation.y) / -90.0)
|
||||||
var data = right_info_node.get_rotated_data(rotation_steps)
|
var data = right_info_node.get_rotated_data(rotation_steps)
|
||||||
exit_found = data["connections"]
|
exit_found = data["connections"]
|
||||||
|
river_exit_found = data["river_connections"]
|
||||||
height_found = data["heights"]
|
height_found = data["heights"]
|
||||||
|
|
||||||
if "have_lamppost" in right_info_node:
|
if "have_lamppost" in right_info_node:
|
||||||
have_lamppost = right_info_node.have_lamppost
|
have_lamppost = right_info_node.have_lamppost
|
||||||
|
|
||||||
|
uniqueness = _get_chunk_uniqueness_from_info(right_info_node)
|
||||||
|
|
||||||
#Add piece to the grid
|
#Add piece to the grid
|
||||||
board[grid_pos] = {
|
board[grid_pos] = {
|
||||||
"type": "obstacle",
|
"type": "obstacle",
|
||||||
"exit": exit_found,
|
"exit": exit_found,
|
||||||
|
"river_exit": river_exit_found,
|
||||||
"heights": height_found,
|
"heights": height_found,
|
||||||
"node": root_chunk,
|
"node": root_chunk,
|
||||||
"info": right_info_node,
|
"info": right_info_node,
|
||||||
"have_lamppost": have_lamppost
|
"have_lamppost": have_lamppost,
|
||||||
|
"uniqueness": uniqueness
|
||||||
}
|
}
|
||||||
|
|
||||||
if have_lamppost:
|
if have_lamppost:
|
||||||
_connect_lamppost_wires(grid_pos)
|
_queue_lamppost_wire_connection(grid_pos)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
return false
|
return false
|
||||||
@@ -216,6 +637,10 @@ func _add_compatible_biome(grid_pos: Vector2i) -> void:
|
|||||||
var req_conn_est = _needed_connection(grid_pos + Vector2i(1, 0), "west")
|
var req_conn_est = _needed_connection(grid_pos + Vector2i(1, 0), "west")
|
||||||
var req_conn_south = _needed_connection(grid_pos + Vector2i(0, 1), "north")
|
var req_conn_south = _needed_connection(grid_pos + Vector2i(0, 1), "north")
|
||||||
var req_conn_west = _needed_connection(grid_pos + Vector2i(-1, 0), "est")
|
var req_conn_west = _needed_connection(grid_pos + Vector2i(-1, 0), "est")
|
||||||
|
var req_river_north = _needed_river_connection(grid_pos + Vector2i(0, -1), "south")
|
||||||
|
var req_river_est = _needed_river_connection(grid_pos + Vector2i(1, 0), "west")
|
||||||
|
var req_river_south = _needed_river_connection(grid_pos + Vector2i(0, 1), "north")
|
||||||
|
var req_river_west = _needed_river_connection(grid_pos + Vector2i(-1, 0), "est")
|
||||||
|
|
||||||
var req_height_north = _needed_heights(grid_pos + Vector2i(0, -1), "south")
|
var req_height_north = _needed_heights(grid_pos + Vector2i(0, -1), "south")
|
||||||
var req_height_est = _needed_heights(grid_pos + Vector2i(1, 0), "west")
|
var req_height_est = _needed_heights(grid_pos + Vector2i(1, 0), "west")
|
||||||
@@ -229,21 +654,28 @@ func _add_compatible_biome(grid_pos: Vector2i) -> void:
|
|||||||
var valid_candidates = []
|
var valid_candidates = []
|
||||||
|
|
||||||
for scene in zone_catalogue:
|
for scene in zone_catalogue:
|
||||||
var test_chunk = scene.instantiate()
|
var metadata = _get_chunk_scene_metadata(scene)
|
||||||
var test_list: Array[Node] = []
|
if metadata.is_empty():
|
||||||
collect_all_chunkinfo(test_chunk, test_list)
|
continue
|
||||||
var info_test = test_list[0] if test_list.size() > 0 else null
|
|
||||||
|
|
||||||
if info_test != null and info_test.has_method("get_rotated_data"):
|
for candidate in metadata["rotations"]:
|
||||||
for rot in range(4):
|
var rot = candidate["rotation"]
|
||||||
var data = test_chunk.get_rotated_data(rot)
|
var data = candidate["data"]
|
||||||
var u_conn = data["connections"]
|
var u_conn = data["connections"]
|
||||||
|
var u_river_conn = data["river_connections"]
|
||||||
var u_height = data["heights"]
|
var u_height = data["heights"]
|
||||||
|
var uniqueness = int(metadata.get("uniqueness", 0))
|
||||||
|
if _has_nearby_unique_chunk(grid_pos, uniqueness):
|
||||||
|
continue
|
||||||
|
|
||||||
var match_conn_n = (req_conn_north == -1) or ((req_conn_north == 1) == u_conn["north"])
|
var match_conn_n = (req_conn_north == -1) or ((req_conn_north == 1) == u_conn["north"])
|
||||||
var match_conn_e = (req_conn_est == -1) or ((req_conn_est == 1) == u_conn["est"])
|
var match_conn_e = (req_conn_est == -1) or ((req_conn_est == 1) == u_conn["est"])
|
||||||
var match_conn_s = (req_conn_south == -1) or ((req_conn_south == 1) == u_conn["south"])
|
var match_conn_s = (req_conn_south == -1) or ((req_conn_south == 1) == u_conn["south"])
|
||||||
var match_conn_o = (req_conn_west == -1) or ((req_conn_west == 1) == u_conn["west"])
|
var match_conn_o = (req_conn_west == -1) or ((req_conn_west == 1) == u_conn["west"])
|
||||||
|
var match_river_n = (req_river_north == -1) or ((req_river_north == 1) == u_river_conn["north"])
|
||||||
|
var match_river_e = (req_river_est == -1) or ((req_river_est == 1) == u_river_conn["est"])
|
||||||
|
var match_river_s = (req_river_south == -1) or ((req_river_south == 1) == u_river_conn["south"])
|
||||||
|
var match_river_o = (req_river_west == -1) or ((req_river_west == 1) == u_river_conn["west"])
|
||||||
|
|
||||||
var match_alt_n = (req_height_north == -1) or (req_height_north == u_height["north"])
|
var match_alt_n = (req_height_north == -1) or (req_height_north == u_height["north"])
|
||||||
var match_alt_e = (req_height_est == -1) or (req_height_est == u_height["est"])
|
var match_alt_e = (req_height_est == -1) or (req_height_est == u_height["est"])
|
||||||
@@ -256,16 +688,21 @@ func _add_compatible_biome(grid_pos: Vector2i) -> void:
|
|||||||
var diff_o = abs(u_height["west"] - height_target) if req_height_west == -1 else 0
|
var diff_o = abs(u_height["west"] - height_target) if req_height_west == -1 else 0
|
||||||
var excessive_jumps = diff_n > 1 or diff_e > 1 or diff_s > 1 or diff_o > 1
|
var excessive_jumps = diff_n > 1 or diff_e > 1 or diff_s > 1 or diff_o > 1
|
||||||
|
|
||||||
if match_conn_n and match_conn_e and match_conn_s and match_conn_o and match_alt_n and match_alt_e and match_alt_s and match_alt_o and not excessive_jumps:
|
if match_conn_n and match_conn_e and match_conn_s and match_conn_o and match_river_n and match_river_e and match_river_s and match_river_o and match_alt_n and match_alt_e and match_alt_s and match_alt_o and not excessive_jumps:
|
||||||
var score = 0
|
var score = 0
|
||||||
if req_height_north == -1 and u_height["north"] == height_target: score += 1
|
if req_height_north == -1 and u_height["north"] == height_target: score += 1
|
||||||
if req_height_est == -1 and u_height["est"] == height_target: score += 1
|
if req_height_est == -1 and u_height["est"] == height_target: score += 1
|
||||||
if req_height_south == -1 and u_height["south"] == height_target: score += 1
|
if req_height_south == -1 and u_height["south"] == height_target: score += 1
|
||||||
if req_height_west == -1 and u_height["west"] == height_target: score += 1
|
if req_height_west == -1 and u_height["west"] == height_target: score += 1
|
||||||
|
|
||||||
valid_candidates.append({"scene": scene, "rotation": rot, "data": data, "score": score})
|
valid_candidates.append({
|
||||||
|
"scene": scene,
|
||||||
test_chunk.queue_free()
|
"rotation": rot,
|
||||||
|
"data": data,
|
||||||
|
"score": score,
|
||||||
|
"weight": _get_uniqueness_pick_weight(uniqueness),
|
||||||
|
"uniqueness": uniqueness
|
||||||
|
})
|
||||||
|
|
||||||
if valid_candidates.size() > 0:
|
if valid_candidates.size() > 0:
|
||||||
var max_score = -1
|
var max_score = -1
|
||||||
@@ -276,40 +713,46 @@ func _add_compatible_biome(grid_pos: Vector2i) -> void:
|
|||||||
for c in valid_candidates:
|
for c in valid_candidates:
|
||||||
if c.score == max_score: best_candidate.append(c)
|
if c.score == max_score: best_candidate.append(c)
|
||||||
|
|
||||||
var choise = best_candidate.pick_random()
|
var choise = _pick_weighted_candidate(best_candidate)
|
||||||
var new_chunk = choise.scene.instantiate()
|
var new_chunk = choise.scene.instantiate()
|
||||||
add_child(new_chunk)
|
|
||||||
new_chunk.position = Vector3(grid_pos.x * chunk_size, 0, grid_pos.y * chunk_size)
|
new_chunk.position = Vector3(grid_pos.x * chunk_size, 0, grid_pos.y * chunk_size)
|
||||||
new_chunk.rotation.y = choise.rotation * (-PI / 2.0)
|
new_chunk.rotation.y = choise.rotation * (-PI / 2.0)
|
||||||
|
add_child(new_chunk)
|
||||||
|
_spawn_props_for_chunk(new_chunk)
|
||||||
|
|
||||||
var new_list: Array[Node] = []
|
var info_new = _get_cached_chunk_info(new_chunk, choise.scene)
|
||||||
collect_all_chunkinfo(new_chunk, new_list)
|
|
||||||
var info_new = new_list[0] if new_list.size() > 0 else null
|
|
||||||
|
|
||||||
var have_lamppost = false
|
var have_lamppost = false
|
||||||
if info_new != null and "have_lamppost" in new_chunk:
|
if info_new != null and "have_lamppost" in info_new:
|
||||||
have_lamppost = info_new.have_lamppost
|
have_lamppost = info_new.have_lamppost
|
||||||
|
|
||||||
|
var river_flow_direction = _calculate_river_flow_direction(grid_pos, choise.data["river_connections"])
|
||||||
|
_apply_river_flow_direction(new_chunk, river_flow_direction)
|
||||||
|
|
||||||
board[grid_pos] = {
|
board[grid_pos] = {
|
||||||
"type": "bioma",
|
"type": "bioma",
|
||||||
"exit": choise.data["connections"],
|
"exit": choise.data["connections"],
|
||||||
|
"river_exit": choise.data["river_connections"],
|
||||||
|
"river_flow_direction": river_flow_direction,
|
||||||
"heights": choise.data["heights"],
|
"heights": choise.data["heights"],
|
||||||
"node": new_chunk,
|
"node": new_chunk,
|
||||||
"info": info_new,
|
"info": info_new,
|
||||||
"have_lamppost": have_lamppost
|
"have_lamppost": have_lamppost,
|
||||||
|
"uniqueness": choise.uniqueness
|
||||||
}
|
}
|
||||||
|
|
||||||
if have_lamppost:
|
if have_lamppost:
|
||||||
_connect_lamppost_wires(grid_pos)
|
_queue_lamppost_wire_connection(grid_pos)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
var backup = zone_catalogue[0].instantiate()
|
var backup_scene = _pick_backup_scene(zone_catalogue, grid_pos)
|
||||||
add_child(backup)
|
var backup = backup_scene.instantiate()
|
||||||
backup.position = Vector3(grid_pos.x * chunk_size, 0, grid_pos.y * chunk_size)
|
backup.position = Vector3(grid_pos.x * chunk_size, 0, grid_pos.y * chunk_size)
|
||||||
|
add_child(backup)
|
||||||
|
_spawn_props_for_chunk(backup)
|
||||||
|
|
||||||
var backup_list: Array[Node] = []
|
var info_backup = _get_cached_chunk_info(backup, backup_scene)
|
||||||
collect_all_chunkinfo(backup, backup_list)
|
var backup_uniqueness = _get_chunk_uniqueness_from_info(info_backup)
|
||||||
var info_backup = backup_list[0] if backup_list.size() > 0 else null
|
|
||||||
|
|
||||||
var safe_heights = {
|
var safe_heights = {
|
||||||
"north": req_height_north if req_height_north != -1 else height_target,
|
"north": req_height_north if req_height_north != -1 else height_target,
|
||||||
@@ -320,12 +763,111 @@ func _add_compatible_biome(grid_pos: Vector2i) -> void:
|
|||||||
board[grid_pos] = {
|
board[grid_pos] = {
|
||||||
"type": "biome",
|
"type": "biome",
|
||||||
"exit": {"north":false, "est":false, "south":false, "west":false},
|
"exit": {"north":false, "est":false, "south":false, "west":false},
|
||||||
|
"river_exit": {"north":false, "est":false, "south":false, "west":false},
|
||||||
|
"river_flow_direction": Vector2.ZERO,
|
||||||
"heights": safe_heights,
|
"heights": safe_heights,
|
||||||
"node": backup,
|
"node": backup,
|
||||||
"info": info_backup,
|
"info": info_backup,
|
||||||
"have_lamppost": false
|
"have_lamppost": false,
|
||||||
|
"uniqueness": backup_uniqueness
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _calculate_river_flow_direction(grid_pos: Vector2i, river_connections: Dictionary) -> Vector2:
|
||||||
|
var connected_sides: Array[String] = []
|
||||||
|
for side in RIVER_SIDE_ORDER:
|
||||||
|
if river_connections.has(side) and river_connections[side]:
|
||||||
|
connected_sides.append(side)
|
||||||
|
|
||||||
|
if connected_sides.is_empty():
|
||||||
|
return Vector2.ZERO
|
||||||
|
|
||||||
|
var neighbour_flow = _get_connected_neighbour_river_flow(grid_pos, connected_sides)
|
||||||
|
if not neighbour_flow.is_zero_approx():
|
||||||
|
var continued_flow = _continue_river_flow_from_neighbour(grid_pos, connected_sides, neighbour_flow)
|
||||||
|
if not continued_flow.is_zero_approx():
|
||||||
|
return continued_flow.normalized()
|
||||||
|
|
||||||
|
var default_flow = _get_default_river_flow(connected_sides)
|
||||||
|
if default_flow.is_zero_approx():
|
||||||
|
return Vector2.ZERO
|
||||||
|
return default_flow.normalized()
|
||||||
|
|
||||||
|
func _get_connected_neighbour_river_flow(grid_pos: Vector2i, connected_sides: Array[String]) -> Vector2:
|
||||||
|
for side in connected_sides:
|
||||||
|
var neighbour_pos: Vector2i = grid_pos + RIVER_NEIGHBOUR_OFFSETS[side]
|
||||||
|
if not board.has(neighbour_pos):
|
||||||
|
continue
|
||||||
|
var neighbour = board[neighbour_pos]
|
||||||
|
if not neighbour.has("river_flow_direction"):
|
||||||
|
continue
|
||||||
|
var neighbour_flow: Vector2 = neighbour["river_flow_direction"]
|
||||||
|
if not neighbour_flow.is_zero_approx():
|
||||||
|
return neighbour_flow.normalized()
|
||||||
|
return Vector2.ZERO
|
||||||
|
|
||||||
|
func _continue_river_flow_from_neighbour(grid_pos: Vector2i, connected_sides: Array[String], neighbour_flow: Vector2) -> Vector2:
|
||||||
|
for side in connected_sides:
|
||||||
|
var neighbour_pos: Vector2i = grid_pos + RIVER_NEIGHBOUR_OFFSETS[side]
|
||||||
|
if not board.has(neighbour_pos):
|
||||||
|
continue
|
||||||
|
var neighbour = board[neighbour_pos]
|
||||||
|
if not neighbour.has("river_flow_direction"):
|
||||||
|
continue
|
||||||
|
var side_direction: Vector2 = RIVER_DIRECTIONS[side]
|
||||||
|
var neighbour_direction: Vector2 = neighbour["river_flow_direction"]
|
||||||
|
if neighbour_direction.is_zero_approx():
|
||||||
|
continue
|
||||||
|
neighbour_direction = neighbour_direction.normalized()
|
||||||
|
var other_sides = connected_sides.duplicate()
|
||||||
|
other_sides.erase(side)
|
||||||
|
if other_sides.is_empty():
|
||||||
|
return neighbour_direction
|
||||||
|
|
||||||
|
var other_direction = _get_average_river_side_direction(other_sides)
|
||||||
|
if neighbour_direction.dot(-side_direction) > 0.25:
|
||||||
|
return other_direction - side_direction
|
||||||
|
if neighbour_direction.dot(side_direction) > 0.25:
|
||||||
|
return side_direction - other_direction
|
||||||
|
|
||||||
|
var default_flow = _get_default_river_flow(connected_sides)
|
||||||
|
if default_flow.dot(neighbour_flow) < 0.0:
|
||||||
|
return -default_flow
|
||||||
|
return default_flow
|
||||||
|
|
||||||
|
func _get_default_river_flow(connected_sides: Array[String]) -> Vector2:
|
||||||
|
if connected_sides.size() == 1:
|
||||||
|
return RIVER_DIRECTIONS[connected_sides[0]]
|
||||||
|
|
||||||
|
if connected_sides.has("north") and connected_sides.has("south"):
|
||||||
|
return Vector2(0.0, 1.0)
|
||||||
|
if connected_sides.has("est") and connected_sides.has("west"):
|
||||||
|
return Vector2(1.0, 0.0)
|
||||||
|
|
||||||
|
var start_direction: Vector2 = RIVER_DIRECTIONS[connected_sides[0]]
|
||||||
|
var end_direction = _get_average_river_side_direction(connected_sides.slice(1))
|
||||||
|
return end_direction - start_direction
|
||||||
|
|
||||||
|
func _get_average_river_side_direction(sides: Array[String]) -> Vector2:
|
||||||
|
var direction := Vector2.ZERO
|
||||||
|
for side in sides:
|
||||||
|
direction += RIVER_DIRECTIONS[side]
|
||||||
|
if direction.is_zero_approx():
|
||||||
|
return Vector2.ZERO
|
||||||
|
return direction / float(sides.size())
|
||||||
|
|
||||||
|
func _apply_river_flow_direction(root: Node, flow_direction: Vector2) -> void:
|
||||||
|
if flow_direction.is_zero_approx():
|
||||||
|
return
|
||||||
|
_set_river_flow_direction_recursive(root, flow_direction.normalized())
|
||||||
|
|
||||||
|
func _set_river_flow_direction_recursive(node: Node, flow_direction: Vector2) -> void:
|
||||||
|
if node is MeshInstance3D and node.name.begins_with("Water_F"):
|
||||||
|
var mesh_instance := node as MeshInstance3D
|
||||||
|
mesh_instance.set_instance_shader_parameter("river_flow_direction", flow_direction)
|
||||||
|
|
||||||
|
for child in node.get_children():
|
||||||
|
_set_river_flow_direction_recursive(child, flow_direction)
|
||||||
|
|
||||||
func _needed_connection(near_pos: Vector2i, side_needed: String) -> int:
|
func _needed_connection(near_pos: Vector2i, side_needed: String) -> int:
|
||||||
if not board.has(near_pos):
|
if not board.has(near_pos):
|
||||||
_register_cell_with_ray(near_pos)
|
_register_cell_with_ray(near_pos)
|
||||||
@@ -333,75 +875,28 @@ func _needed_connection(near_pos: Vector2i, side_needed: String) -> int:
|
|||||||
return 1 if board[near_pos]["exit"][side_needed] else 0
|
return 1 if board[near_pos]["exit"][side_needed] else 0
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
|
func _needed_river_connection(near_pos: Vector2i, side_needed: String) -> int:
|
||||||
|
if not board.has(near_pos):
|
||||||
|
_register_cell_with_ray(near_pos)
|
||||||
|
if board.has(near_pos) and board[near_pos].has("river_exit"):
|
||||||
|
return 1 if board[near_pos]["river_exit"][side_needed] else 0
|
||||||
|
return -1
|
||||||
|
|
||||||
func _needed_heights(near_pos: Vector2i, side_needed: String) -> int:
|
func _needed_heights(near_pos: Vector2i, side_needed: String) -> int:
|
||||||
if board.has(near_pos) and board[near_pos].has("heights"):
|
if board.has(near_pos) and board[near_pos].has("heights"):
|
||||||
return board[near_pos]["heights"][side_needed]
|
return board[near_pos]["heights"][side_needed]
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
func _train_radar() -> void:
|
|
||||||
if rail_path == null or rail_path.curve == null or rail_path.train_instance == null: return
|
|
||||||
|
|
||||||
if manual_biome != null:
|
|
||||||
return
|
|
||||||
|
|
||||||
var train_pos = rail_path.train_instance.global_position
|
|
||||||
var grid_x = roundi(train_pos.x / chunk_size)
|
|
||||||
var grid_z = roundi(train_pos.z / chunk_size)
|
|
||||||
var current_biome = _get_procedural_biome_name(noise_generator.get_noise_2d(grid_x, grid_z))
|
|
||||||
|
|
||||||
var current_progress = rail_path.train_progress
|
|
||||||
var total_length = rail_path.curve.get_baked_length()
|
|
||||||
#var exchange_distance = 0.0
|
|
||||||
#var next_biome = ""
|
|
||||||
|
|
||||||
for step in range(1, 31):
|
|
||||||
var next_progress = wrapf(current_progress + (step * chunk_size), 0.0, total_length)
|
|
||||||
var next_local_pos = rail_path.curve.sample_baked(next_progress, true)
|
|
||||||
var next_global_pos = rail_path.to_global(next_local_pos)
|
|
||||||
|
|
||||||
var f_x = roundi(next_global_pos.x / chunk_size)
|
|
||||||
var f_z = roundi(next_global_pos.z / chunk_size)
|
|
||||||
var future_biome = _get_procedural_biome_name(noise_generator.get_noise_2d(f_x, f_z))
|
|
||||||
|
|
||||||
if future_biome != current_biome:
|
|
||||||
#exchange_distance = step * chunk_size
|
|
||||||
#next_biome = future_biome
|
|
||||||
break
|
|
||||||
|
|
||||||
func _clean_far_chunks(centro_attuale: Vector2i) -> void:
|
|
||||||
var cells_to_remove = []
|
|
||||||
var safe_margin = 2
|
|
||||||
|
|
||||||
for grid_pos in board.keys():
|
|
||||||
var cell = board[grid_pos]
|
|
||||||
if cell["type"] == "obstacle": continue
|
|
||||||
|
|
||||||
var dist_x = abs(grid_pos.x - centro_attuale.x)
|
|
||||||
var dist_z = abs(grid_pos.y - centro_attuale.y)
|
|
||||||
|
|
||||||
if dist_x > eye_line + safe_margin or dist_z > eye_line + safe_margin:
|
|
||||||
if cell.has("node") and is_instance_valid(cell["node"]):
|
|
||||||
cell["node"].queue_free()
|
|
||||||
cells_to_remove.append(grid_pos)
|
|
||||||
|
|
||||||
for pos in cells_to_remove:
|
|
||||||
board.erase(pos)
|
|
||||||
|
|
||||||
|
|
||||||
func _get_lampposts(info_node: Node, side: String) -> Array[Node3D]:
|
func _get_lampposts(info_node: Node, side: String) -> Array[Node3D]:
|
||||||
var lampposts: Array[Node3D] = []
|
var lampposts: Array[Node3D] = []
|
||||||
if side == "sx":
|
if side == "sx":
|
||||||
if "connection_left" in info_node and info_node.connection_left != null:
|
if "connection_left" in info_node and info_node.connection_left != null:
|
||||||
for p in info_node.connection_left:
|
for p in info_node.connection_left:
|
||||||
if is_instance_valid(p): lampposts.append(p)
|
if is_instance_valid(p): lampposts.append(p)
|
||||||
#if lampposts.is_empty() and "nodo_attacco_sx" in nodo_info and is_instance_valid(nodo_info.get("nodo_attacco_sx")):
|
|
||||||
# lampposts.append(nodo_info.get("nodo_attacco_sx"))
|
|
||||||
else:
|
else:
|
||||||
if "connection_right" in info_node and info_node.connection_right != null:
|
if "connection_right" in info_node and info_node.connection_right != null:
|
||||||
for p in info_node.connection_right:
|
for p in info_node.connection_right:
|
||||||
if is_instance_valid(p): lampposts.append(p)
|
if is_instance_valid(p): lampposts.append(p)
|
||||||
#if lampposts.is_empty() and "nodo_attacco_dx" in nodo_info and is_instance_valid(nodo_info.get("nodo_attacco_dx")):
|
|
||||||
# lampposts.append(nodo_info.get("nodo_attacco_dx"))
|
|
||||||
return lampposts
|
return lampposts
|
||||||
|
|
||||||
func _connect_lamppost_wires(new_board_pos: Vector2i) -> void:
|
func _connect_lamppost_wires(new_board_pos: Vector2i) -> void:
|
||||||
@@ -425,7 +920,7 @@ func _connect_lamppost_wires(new_board_pos: Vector2i) -> void:
|
|||||||
var p_sx_your_best = null; var p_dx_your_best = null
|
var p_sx_your_best = null; var p_dx_your_best = null
|
||||||
var best_closest_to_root = null
|
var best_closest_to_root = null
|
||||||
var best_distance = 999999.0
|
var best_distance = 999999.0
|
||||||
var ray_research = 3
|
var ray_research = 6
|
||||||
|
|
||||||
for x in range(-ray_research, ray_research + 1):
|
for x in range(-ray_research, ray_research + 1):
|
||||||
for z in range(-ray_research, ray_research + 1):
|
for z in range(-ray_research, ray_research + 1):
|
||||||
@@ -493,7 +988,7 @@ func _connect_lamppost_wires(new_board_pos: Vector2i) -> void:
|
|||||||
p_sx_your_best = closest_sx[i_t]
|
p_sx_your_best = closest_sx[i_t]
|
||||||
p_dx_your_best = closest_dx[i_t]
|
p_dx_your_best = closest_dx[i_t]
|
||||||
|
|
||||||
var max_dist = chunk_size * 8.0
|
var max_dist = chunk_size * lamppost_dist_factor
|
||||||
|
|
||||||
if best_closest_to_root != null and best_distance < max_dist:
|
if best_closest_to_root != null and best_distance < max_dist:
|
||||||
var dist_streight = p_sx_my_best.global_position.distance_to(p_sx_your_best.global_position) + p_dx_my_best.global_position.distance_to(p_dx_your_best.global_position)
|
var dist_streight = p_sx_my_best.global_position.distance_to(p_sx_your_best.global_position) + p_dx_my_best.global_position.distance_to(p_dx_your_best.global_position)
|
||||||
@@ -511,6 +1006,7 @@ func _connect_lamppost_wires(new_board_pos: Vector2i) -> void:
|
|||||||
if not wire_connections.has(closest_id): wire_connections[closest_id] = 0
|
if not wire_connections.has(closest_id): wire_connections[closest_id] = 0
|
||||||
wire_connections[closest_id] += 1
|
wire_connections[closest_id] += 1
|
||||||
|
|
||||||
|
#draw lamppost
|
||||||
func _draw_parable(p1: Vector3, p2: Vector3, parent: Node3D) -> void:
|
func _draw_parable(p1: Vector3, p2: Vector3, parent: Node3D) -> void:
|
||||||
var segments = 15
|
var segments = 15
|
||||||
var lowering = 1.5
|
var lowering = 1.5
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ class_name ChunkInfo
|
|||||||
|
|
||||||
@export_group("Set Piece Rules (Unique pieces)")
|
@export_group("Set Piece Rules (Unique pieces)")
|
||||||
@export var exclusive_biome: String = "" # Es: "Forest"
|
@export var exclusive_biome: String = "" # Es: "Forest"
|
||||||
|
@export_range(0, 5, 1) var uniqueness: int = 0 #0=common; 5=unique
|
||||||
|
|
||||||
@export_group("Base exit")
|
@export_group("Base exit")
|
||||||
@export var north: bool = false
|
@export var north: bool = false
|
||||||
@@ -12,6 +13,12 @@ class_name ChunkInfo
|
|||||||
@export var south: bool = false
|
@export var south: bool = false
|
||||||
@export var west: bool = false
|
@export var west: bool = false
|
||||||
|
|
||||||
|
@export_group("River exit")
|
||||||
|
@export var river_north: bool = false
|
||||||
|
@export var river_est: bool = false
|
||||||
|
@export var river_south: bool = false
|
||||||
|
@export var river_west: bool = false
|
||||||
|
|
||||||
@export_group("Margin heights (level 0, 1, 2)")
|
@export_group("Margin heights (level 0, 1, 2)")
|
||||||
@export_range(0, 2, 1) var height_north: int = 0
|
@export_range(0, 2, 1) var height_north: int = 0
|
||||||
@export_range(0, 2, 1) var height_est: int = 0
|
@export_range(0, 2, 1) var height_est: int = 0
|
||||||
@@ -29,14 +36,17 @@ func _ready() -> void:
|
|||||||
|
|
||||||
func get_rotated_data(steps_90: int) -> Dictionary:
|
func get_rotated_data(steps_90: int) -> Dictionary:
|
||||||
var original_exit = [north, est, south, west]
|
var original_exit = [north, est, south, west]
|
||||||
|
var original_river_exit = [river_north, river_est, river_south, river_west]
|
||||||
var original_height = [height_north, height_est, height_south, height_west]
|
var original_height = [height_north, height_est, height_south, height_west]
|
||||||
|
|
||||||
var calculated_exit = []
|
var calculated_exit = []
|
||||||
|
var calculated_river_exit = []
|
||||||
var calculated_height = []
|
var calculated_height = []
|
||||||
|
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
var index = (i - steps_90 + 4) % 4
|
var index = (i - steps_90 + 4) % 4
|
||||||
calculated_exit.append(original_exit[index])
|
calculated_exit.append(original_exit[index])
|
||||||
|
calculated_river_exit.append(original_river_exit[index])
|
||||||
calculated_height.append(original_height[index])
|
calculated_height.append(original_height[index])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -44,6 +54,10 @@ func get_rotated_data(steps_90: int) -> Dictionary:
|
|||||||
"north": calculated_exit[0], "est": calculated_exit[1],
|
"north": calculated_exit[0], "est": calculated_exit[1],
|
||||||
"south": calculated_exit[2], "west": calculated_exit[3]
|
"south": calculated_exit[2], "west": calculated_exit[3]
|
||||||
},
|
},
|
||||||
|
"river_connections": {
|
||||||
|
"north": calculated_river_exit[0], "est": calculated_river_exit[1],
|
||||||
|
"south": calculated_river_exit[2], "west": calculated_river_exit[3]
|
||||||
|
},
|
||||||
"heights": {
|
"heights": {
|
||||||
"north": calculated_height[0], "est": calculated_height[1],
|
"north": calculated_height[0], "est": calculated_height[1],
|
||||||
"south": calculated_height[2], "west": calculated_height[3]
|
"south": calculated_height[2], "west": calculated_height[3]
|
||||||
|
|||||||
4
core/biome_generator/prop_info.gd
Normal file
4
core/biome_generator/prop_info.gd
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
extends Marker3D
|
||||||
|
class_name PropInfo
|
||||||
|
|
||||||
|
@export var available_props: Array[PackedScene]
|
||||||
1
core/biome_generator/prop_info.gd.uid
Normal file
1
core/biome_generator/prop_info.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dg6ngy4pmtsyc
|
||||||
@@ -47,15 +47,112 @@ var next_stop_index: int = 0
|
|||||||
var stop_multiply: float = 1.0
|
var stop_multiply: float = 1.0
|
||||||
var is_restarting: bool = false
|
var is_restarting: bool = false
|
||||||
var tween_restart: Tween
|
var tween_restart: Tween
|
||||||
|
var environment_config: EnvironmentConfig
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
_cache_environment_config()
|
||||||
if curve != null and curve.get_baked_length() > 0:
|
if curve != null and curve.get_baked_length() > 0:
|
||||||
build_rails()
|
build_rails()
|
||||||
build_train()
|
build_train()
|
||||||
_plan_stops()
|
_plan_stops()
|
||||||
|
_apply_initial_train_start()
|
||||||
else:
|
else:
|
||||||
print("WARNING: Draw Path3D for rails!")
|
print("WARNING: Draw Path3D for rails!")
|
||||||
|
|
||||||
|
func _cache_environment_config() -> void:
|
||||||
|
var parent_node: Node = get_parent()
|
||||||
|
if parent_node != null:
|
||||||
|
var day_night_node := parent_node.get_node_or_null("DayNight") as EnvironmentManagerRoot
|
||||||
|
if day_night_node != null:
|
||||||
|
environment_config = day_night_node.environment_config
|
||||||
|
return
|
||||||
|
|
||||||
|
var current_scene: Node = get_tree().current_scene
|
||||||
|
if current_scene == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
for child in current_scene.get_children():
|
||||||
|
var environment_manager := child as EnvironmentManagerRoot
|
||||||
|
if environment_manager != null:
|
||||||
|
environment_config = environment_manager.environment_config
|
||||||
|
return
|
||||||
|
|
||||||
|
func _apply_initial_train_start() -> void:
|
||||||
|
if train_instance == null or curve == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
var total_length: float = curve.get_baked_length()
|
||||||
|
if total_length <= 0.0:
|
||||||
|
return
|
||||||
|
|
||||||
|
#start from a random position
|
||||||
|
if environment_config != null and environment_config.train_start_from_random_position:
|
||||||
|
train_progress = randf() * total_length
|
||||||
|
_update_next_stop_index_from_progress()
|
||||||
|
elif environment_config != null and not stop_offset.is_empty():
|
||||||
|
#start from a specific stop
|
||||||
|
var stop_index: int = clampi(environment_config.train_start_stop_index, 0, stop_offset.size() - 1)
|
||||||
|
train_progress = stop_offset[stop_index]
|
||||||
|
_set_next_stop_index_from_current(stop_index)
|
||||||
|
else:
|
||||||
|
train_progress = wrapf(train_progress, 0.0, total_length)
|
||||||
|
_update_next_stop_index_from_progress()
|
||||||
|
|
||||||
|
_snap_train_to_progress()
|
||||||
|
|
||||||
|
func _set_next_stop_index_from_current(current_stop_index: int) -> void:
|
||||||
|
if stop_offset.is_empty():
|
||||||
|
next_stop_index = 0
|
||||||
|
return
|
||||||
|
|
||||||
|
if train_speed >= 0.0:
|
||||||
|
next_stop_index = (current_stop_index + 1) % stop_offset.size()
|
||||||
|
else:
|
||||||
|
next_stop_index = current_stop_index - 1
|
||||||
|
if next_stop_index < 0:
|
||||||
|
next_stop_index = stop_offset.size() - 1
|
||||||
|
|
||||||
|
func _update_next_stop_index_from_progress() -> void:
|
||||||
|
if stop_offset.is_empty():
|
||||||
|
next_stop_index = 0
|
||||||
|
return
|
||||||
|
|
||||||
|
if train_speed >= 0.0:
|
||||||
|
next_stop_index = 0
|
||||||
|
for i in range(stop_offset.size()):
|
||||||
|
if stop_offset[i] > train_progress + 0.001:
|
||||||
|
next_stop_index = i
|
||||||
|
return
|
||||||
|
return
|
||||||
|
|
||||||
|
next_stop_index = stop_offset.size() - 1
|
||||||
|
for i in range(stop_offset.size() - 1, -1, -1):
|
||||||
|
if stop_offset[i] < train_progress - 0.001:
|
||||||
|
next_stop_index = i
|
||||||
|
return
|
||||||
|
|
||||||
|
func _snap_train_to_progress() -> void:
|
||||||
|
if train_instance == null or curve == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
var total_length: float = curve.get_baked_length()
|
||||||
|
if total_length <= 0.0:
|
||||||
|
return
|
||||||
|
|
||||||
|
train_progress = wrapf(train_progress, 0.0, total_length)
|
||||||
|
var center_position: Vector3 = to_global(curve.sample_baked(train_progress, true))
|
||||||
|
var prog_forward: float = wrapf(train_progress + 2.0, 0.0, total_length)
|
||||||
|
var forward_position: Vector3 = to_global(curve.sample_baked(prog_forward, true))
|
||||||
|
|
||||||
|
train_instance.global_position = center_position
|
||||||
|
if center_position.distance_to(forward_position) > 0.01:
|
||||||
|
train_instance.look_at(forward_position, Vector3.UP)
|
||||||
|
train_instance.rotate_y(PI)
|
||||||
|
|
||||||
|
if cameras:
|
||||||
|
cameras.global_position = center_position
|
||||||
|
cameras.global_basis = train_instance.global_basis
|
||||||
|
|
||||||
func build_rails() -> void:
|
func build_rails() -> void:
|
||||||
var mat_wood = StandardMaterial3D.new()
|
var mat_wood = StandardMaterial3D.new()
|
||||||
mat_wood.albedo_color = Color(0.35, 0.2, 0.1)
|
mat_wood.albedo_color = Color(0.35, 0.2, 0.1)
|
||||||
7
core/daynight/FogNoise.tres
Normal file
7
core/daynight/FogNoise.tres
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[gd_resource type="NoiseTexture2D" format=3 uid="uid://b2xcpt2y8v32x"]
|
||||||
|
|
||||||
|
[sub_resource type="FastNoiseLite" id="FastNoiseLite_oqwsk"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
noise = SubResource("FastNoiseLite_oqwsk")
|
||||||
|
seamless = true
|
||||||
@@ -1,9 +1,17 @@
|
|||||||
shader_type canvas_item;
|
shader_type canvas_item;
|
||||||
|
|
||||||
|
// Cattura tutto quello che c'è sotto questo nodo
|
||||||
uniform sampler2D screen_texture : hint_screen_texture, filter_linear_mipmap;
|
uniform sampler2D screen_texture : hint_screen_texture, filter_linear_mipmap;
|
||||||
|
|
||||||
uniform float blur_amount : hint_range(0.0, 5.0) = 2.5;
|
uniform float blur_amount : hint_range(0.0, 5.0) = 2.5;
|
||||||
|
uniform float focus_size : hint_range(0.0, 1.0) = 0.4;
|
||||||
|
uniform float transition_softness : hint_range(0.01, 1.0) = 0.3;
|
||||||
|
|
||||||
void fragment() {
|
void fragment() {
|
||||||
COLOR = textureLod(screen_texture, SCREEN_UV, blur_amount);
|
float dist_from_center = abs(SCREEN_UV.y - 0.5);
|
||||||
|
float mask = smoothstep(focus_size / 2.0, (focus_size / 2.0) + transition_softness, dist_from_center);
|
||||||
|
|
||||||
|
// Applica il blur
|
||||||
|
vec4 blurred_screen = textureLod(screen_texture, SCREEN_UV, blur_amount * mask);
|
||||||
|
COLOR = blurred_screen;
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,21 @@
|
|||||||
class_name DayNightController
|
class_name DayNightController
|
||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
|
const TIME_OPTION_SUNRISE: int = 0
|
||||||
|
const TIME_OPTION_DAY: int = 1
|
||||||
|
const TIME_OPTION_SUNSET: int = 2
|
||||||
|
const TIME_OPTION_NIGHT: int = 3
|
||||||
|
|
||||||
var environment_config: EnvironmentConfig
|
var environment_config: EnvironmentConfig
|
||||||
|
|
||||||
#Multiply for debug
|
#Multiply for debug
|
||||||
@export var time_scale: float = 1.0
|
@export var time_scale: float = 1.0
|
||||||
|
|
||||||
@export var paused: bool = false
|
@export var paused: bool = false
|
||||||
|
|
||||||
signal time_changed(time: float)
|
signal time_changed(time: float)
|
||||||
|
|
||||||
var current_time: float = 0.0
|
var current_time: float = 0.0
|
||||||
|
var _current_time_option_index: int = -1
|
||||||
|
|
||||||
func _init(environmentconfig: EnvironmentConfig) -> void:
|
func _init(environmentconfig: EnvironmentConfig) -> void:
|
||||||
environment_config = environmentconfig
|
environment_config = environmentconfig
|
||||||
@@ -19,6 +24,7 @@ func _ready() -> void:
|
|||||||
#connect events
|
#connect events
|
||||||
UIEvents.set_day_time.connect(_on_set_day_time)
|
UIEvents.set_day_time.connect(_on_set_day_time)
|
||||||
UIEvents.toggle_pause_daytime.connect(_on_toggle_pause_daytime)
|
UIEvents.toggle_pause_daytime.connect(_on_toggle_pause_daytime)
|
||||||
|
UIEvents.time_option_item_changed.connect(_time_option_changed)
|
||||||
|
|
||||||
current_time = environment_config.start_time
|
current_time = environment_config.start_time
|
||||||
update_time(current_time)
|
update_time(current_time)
|
||||||
@@ -44,9 +50,34 @@ func set_time(t: float) -> void:
|
|||||||
update_time(current_time)
|
update_time(current_time)
|
||||||
|
|
||||||
func update_time(currtime: float) -> void:
|
func update_time(currtime: float) -> void:
|
||||||
|
var time_option_index: int = get_time_option_index(currtime)
|
||||||
|
if time_option_index != _current_time_option_index:
|
||||||
|
_current_time_option_index = time_option_index
|
||||||
|
UIEvents.day_time_option_changed.emit(time_option_index)
|
||||||
|
|
||||||
emit_signal("time_changed", currtime)
|
emit_signal("time_changed", currtime)
|
||||||
UIEvents.day_time_changed.emit(currtime, get_time_string())
|
UIEvents.day_time_changed.emit(currtime, get_time_string())
|
||||||
|
|
||||||
|
func get_time_option_index(currtime: float) -> int:
|
||||||
|
if currtime >= environment_config.night or currtime < environment_config.sunrise:
|
||||||
|
return TIME_OPTION_NIGHT
|
||||||
|
if currtime < environment_config.day:
|
||||||
|
return TIME_OPTION_SUNRISE
|
||||||
|
if currtime < environment_config.sunset:
|
||||||
|
return TIME_OPTION_DAY
|
||||||
|
return TIME_OPTION_SUNSET
|
||||||
|
|
||||||
|
func _time_option_changed(index: int) -> void:
|
||||||
|
match index:
|
||||||
|
TIME_OPTION_SUNRISE:
|
||||||
|
set_time(environment_config.sunrise)
|
||||||
|
TIME_OPTION_DAY:
|
||||||
|
set_time(environment_config.day)
|
||||||
|
TIME_OPTION_SUNSET:
|
||||||
|
set_time(environment_config.sunset)
|
||||||
|
TIME_OPTION_NIGHT:
|
||||||
|
set_time(environment_config.night)
|
||||||
|
|
||||||
func _on_set_day_time(value: float) -> void:
|
func _on_set_day_time(value: float) -> void:
|
||||||
set_time(value)
|
set_time(value)
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
[ext_resource type="Material" uid="uid://codq5gx71rj4o" path="res://core/daynight/environment_dust_material.tres" id="8_amaf0"]
|
[ext_resource type="Material" uid="uid://codq5gx71rj4o" path="res://core/daynight/environment_dust_material.tres" id="8_amaf0"]
|
||||||
[ext_resource type="Shader" uid="uid://bkn6eqgbn37jx" path="res://core/daynight/blur.gdshader" id="9_amaf0"]
|
[ext_resource type="Shader" uid="uid://bkn6eqgbn37jx" path="res://core/daynight/blur.gdshader" id="9_amaf0"]
|
||||||
[ext_resource type="Shader" uid="uid://b5wa82soyhsqm" path="res://core/daynight/environment_shadows.gdshader" id="10_tuauy"]
|
[ext_resource type="Shader" uid="uid://b5wa82soyhsqm" path="res://core/daynight/environment_shadows.gdshader" id="10_tuauy"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://b2xcpt2y8v32x" path="res://core/daynight/FogNoise.tres" id="11_tuauy"]
|
||||||
[ext_resource type="FastNoiseLite" uid="uid://c0mtwrkptjcuw" path="res://core/daynight/environment_shadows_noise_clouds.tres" id="11_yn8v8"]
|
[ext_resource type="FastNoiseLite" uid="uid://c0mtwrkptjcuw" path="res://core/daynight/environment_shadows_noise_clouds.tres" id="11_yn8v8"]
|
||||||
|
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_ruhh7"]
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_ruhh7"]
|
||||||
@@ -31,6 +32,7 @@ render_priority = 0
|
|||||||
shader = ExtResource("2_r4tfj")
|
shader = ExtResource("2_r4tfj")
|
||||||
shader_parameter/use_red_as_alpha = true
|
shader_parameter/use_red_as_alpha = true
|
||||||
shader_parameter/fog_color = Color(0.8, 0.85, 0.9, 0.5)
|
shader_parameter/fog_color = Color(0.8, 0.85, 0.9, 0.5)
|
||||||
|
shader_parameter/fog_density = 0.25
|
||||||
shader_parameter/scroll_speed = Vector2(0.05, 0.01)
|
shader_parameter/scroll_speed = Vector2(0.05, 0.01)
|
||||||
shader_parameter/texture_scale = Vector2(1, 1)
|
shader_parameter/texture_scale = Vector2(1, 1)
|
||||||
shader_parameter/edge_softness_y = 0.2
|
shader_parameter/edge_softness_y = 0.2
|
||||||
@@ -40,9 +42,58 @@ shader_parameter/sun_color = Color(0.2841828, 0.2023238, 0.27953526, 1)
|
|||||||
|
|
||||||
[sub_resource type="Resource" id="Resource_r4tfj"]
|
[sub_resource type="Resource" id="Resource_r4tfj"]
|
||||||
script = ExtResource("2_h6hjk")
|
script = ExtResource("2_h6hjk")
|
||||||
|
morning_color = Color(0.93333334, 0.78039217, 0.6039216, 1)
|
||||||
|
afternoon_color = Color(0.9490196, 0.62352943, 0.38039216, 1)
|
||||||
|
night_color = Color(0.18431373, 0.18431373, 0.4862745, 1)
|
||||||
|
sun_rotation_morning = Vector3(-50, -90, 0)
|
||||||
|
sun_rotation_afternoon = Vector3(-120, -90, 0)
|
||||||
|
sun_rotation_night = Vector3(-130, -90, 0)
|
||||||
|
night_light_energy = 1.0
|
||||||
|
exposure_morning = 0.8
|
||||||
|
exposure_afternoon = 0.7
|
||||||
|
exposure_night = 0.7
|
||||||
|
sky_top_morning = Color(0.11764706, 0.35686275, 0.5411765, 1)
|
||||||
|
sky_top_afternoon = Color(0.7019608, 0.4509804, 0.2, 1)
|
||||||
|
sky_top_night = Color(0.050980393, 0.050980393, 0.14901961, 1)
|
||||||
|
sky_horizon_morning = Color(0.4627451, 0.6745098, 0.8627451, 1)
|
||||||
|
sky_horizon_afternoon = Color(0.93333334, 0.6, 0.8039216, 1)
|
||||||
|
sky_horizon_night = Color(0.14901961, 0.101960786, 0.2509804, 1)
|
||||||
|
grad_top_morning = Color(0.7921569, 0.8784314, 0.95686275, 1)
|
||||||
|
grad_top_afternoon = Color(0.8627451, 0.24313726, 0.5411765, 1)
|
||||||
|
grad_top_night = Color(0.16470589, 0.16470589, 0.26666668, 1)
|
||||||
|
grad_bot_morning = Color(0.05882353, 0.078431375, 0.21568628, 1)
|
||||||
|
grad_bot_afternoon = Color(0.2509804, 0.019607844, 0.043137256, 1)
|
||||||
|
grad_intensity_morning = 0.05
|
||||||
|
grad_intensity_afternoon = 0.1
|
||||||
|
grad_intensity_night = 0.5
|
||||||
|
fog_color_morning = Color(0.7490196, 0.8509804, 0.9490196, 1)
|
||||||
|
fog_color_afternoon = Color(0.9823975, 0.8034449, 0.8778439, 1)
|
||||||
|
fog_color_night = Color(0.38409987, 0.28720453, 0.5907528, 1)
|
||||||
|
fog_density_morning = 0.01
|
||||||
|
fog_density_afternoon = 0.02
|
||||||
|
glow_morning = 0.4
|
||||||
|
glow_night = 0.8
|
||||||
material_fog = SubResource("ShaderMaterial_b5atu")
|
material_fog = SubResource("ShaderMaterial_b5atu")
|
||||||
material_drops = SubResource("StandardMaterial3D_r4tfj")
|
material_drops = SubResource("StandardMaterial3D_r4tfj")
|
||||||
material_clouds = SubResource("ShaderMaterial_ruhh7")
|
material_clouds = SubResource("ShaderMaterial_ruhh7")
|
||||||
|
lightning_color = Color(1, 0.9843137, 0.4627451, 1)
|
||||||
|
lightning_min = 2
|
||||||
|
lightning_max = 4
|
||||||
|
lightning_scale_min = 2.0
|
||||||
|
lightning_scale_max = 5.0
|
||||||
|
godray_max_rain = 30
|
||||||
|
godray_spawn_radius = 100.0
|
||||||
|
godray_spawn_offset = Vector3(20, 80, 20)
|
||||||
|
godray_rotation_degrees = Vector3(50, 30, 0)
|
||||||
|
godray_scale = Vector3(2, 25, 50)
|
||||||
|
snow_amount = 2000.0
|
||||||
|
wind_amount = 50
|
||||||
|
cloud_speed = 0.01
|
||||||
|
fireflies_amount = 550
|
||||||
|
fireflies_spawn_ray = 60.0
|
||||||
|
water_color_morning = Color(0.33333334, 0.654902, 0.5294118, 1)
|
||||||
|
water_color_afternoon = Color(0.5803922, 0.5137255, 0.2901961, 1)
|
||||||
|
water_color_night = Color(0.48235294, 0.45490196, 0.69411767, 1)
|
||||||
metadata/_custom_type_script = "uid://butda6k2tli3o"
|
metadata/_custom_type_script = "uid://butda6k2tli3o"
|
||||||
|
|
||||||
[sub_resource type="Gradient" id="Gradient_i3hjl"]
|
[sub_resource type="Gradient" id="Gradient_i3hjl"]
|
||||||
@@ -85,7 +136,7 @@ gradient = SubResource("Gradient_djqkg")
|
|||||||
lifetime_randomness = 0.5
|
lifetime_randomness = 0.5
|
||||||
emission_shape_scale = Vector3(5, 5, 5)
|
emission_shape_scale = Vector3(5, 5, 5)
|
||||||
emission_shape = 3
|
emission_shape = 3
|
||||||
emission_box_extents = Vector3(25, 5, 25)
|
emission_box_extents = Vector3(1, 1, 1)
|
||||||
direction = Vector3(0, 1, 0)
|
direction = Vector3(0, 1, 0)
|
||||||
initial_velocity_min = 6.0
|
initial_velocity_min = 6.0
|
||||||
initial_velocity_max = 6.0
|
initial_velocity_max = 6.0
|
||||||
@@ -99,10 +150,9 @@ point_count = 3
|
|||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_cer0u"]
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_cer0u"]
|
||||||
render_priority = 0
|
render_priority = 0
|
||||||
shader = ExtResource("5_djqkg")
|
shader = ExtResource("5_djqkg")
|
||||||
shader_parameter/wave_frequency = 1.0
|
shader_parameter/time_scale = 3.065
|
||||||
shader_parameter/base_amplitude = 0.5
|
shader_parameter/wave_amplitude = 0.3
|
||||||
shader_parameter/secondary_ratio = 0.6
|
shader_parameter/wave_frequency = 0.25
|
||||||
shader_parameter/time_scale_base = 3.0
|
|
||||||
|
|
||||||
[sub_resource type="TubeTrailMesh" id="TubeTrailMesh_vo82p"]
|
[sub_resource type="TubeTrailMesh" id="TubeTrailMesh_vo82p"]
|
||||||
material = SubResource("ShaderMaterial_cer0u")
|
material = SubResource("ShaderMaterial_cer0u")
|
||||||
@@ -174,7 +224,9 @@ size = Vector2(0.05, 0.8)
|
|||||||
|
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_kavln"]
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_kavln"]
|
||||||
shader = ExtResource("9_amaf0")
|
shader = ExtResource("9_amaf0")
|
||||||
shader_parameter/blur_amount = 0.6000000285
|
shader_parameter/blur_amount = 0.50000002375
|
||||||
|
shader_parameter/focus_size = 0.54400002584
|
||||||
|
shader_parameter/transition_softness = 0.00999999977648
|
||||||
|
|
||||||
[sub_resource type="QuadMesh" id="QuadMesh_sxgg7"]
|
[sub_resource type="QuadMesh" id="QuadMesh_sxgg7"]
|
||||||
size = Vector2(2, 2)
|
size = Vector2(2, 2)
|
||||||
@@ -184,12 +236,12 @@ noise = ExtResource("11_yn8v8")
|
|||||||
seamless = true
|
seamless = true
|
||||||
|
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_oqt1s"]
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_oqt1s"]
|
||||||
render_priority = 0
|
render_priority = -1
|
||||||
shader = ExtResource("10_tuauy")
|
shader = ExtResource("10_tuauy")
|
||||||
shader_parameter/noise_texture = SubResource("NoiseTexture2D_0fcg4")
|
shader_parameter/noise_texture = SubResource("NoiseTexture2D_0fcg4")
|
||||||
shader_parameter/cloud_scale = 0.0070000003325
|
shader_parameter/cloud_scale = 0.0070000003325
|
||||||
shader_parameter/cloud_speed = 0.0030000001425
|
shader_parameter/cloud_speed = 0.0030000001425
|
||||||
shader_parameter/direction = Vector2(0.5, 0.2)
|
shader_parameter/direction = Vector2(0.1, 0.025)
|
||||||
shader_parameter/sun_angle = Vector2(0.5, 0.5)
|
shader_parameter/sun_angle = Vector2(0.5, 0.5)
|
||||||
shader_parameter/cloud_density = 0.400000019
|
shader_parameter/cloud_density = 0.400000019
|
||||||
shader_parameter/center_sharpness = 0.138000006555
|
shader_parameter/center_sharpness = 0.138000006555
|
||||||
@@ -201,7 +253,24 @@ shader_parameter/fade_end = 800.000035625
|
|||||||
shader_parameter/height_fade_start = 10.0
|
shader_parameter/height_fade_start = 10.0
|
||||||
shader_parameter/height_fade_end = 50.0
|
shader_parameter/height_fade_end = 50.0
|
||||||
|
|
||||||
[node name="EnvironmentManager" type="Node3D" unique_id=1611939731 node_paths=PackedStringArray("particles_wind", "particles_snow", "particles_fireflies", "particles_rain", "environment_dust", "blur", "environment_shadows")]
|
[sub_resource type="QuadMesh" id="QuadMesh_yn8v8"]
|
||||||
|
size = Vector2(2, 2)
|
||||||
|
|
||||||
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_sxgg7"]
|
||||||
|
render_priority = 2
|
||||||
|
shader = ExtResource("2_r4tfj")
|
||||||
|
shader_parameter/fog_noise = ExtResource("11_tuauy")
|
||||||
|
shader_parameter/use_red_as_alpha = true
|
||||||
|
shader_parameter/fog_color = Color(0.8, 0.8509804, 0.9019608, 0.2509804)
|
||||||
|
shader_parameter/fog_density = 0.25
|
||||||
|
shader_parameter/scroll_speed = Vector2(0, 0.01)
|
||||||
|
shader_parameter/texture_scale = Vector2(1, 1)
|
||||||
|
shader_parameter/edge_softness_y = 0.16400000779
|
||||||
|
shader_parameter/edge_softness_x = 0.5
|
||||||
|
shader_parameter/night_intensity = 0.0
|
||||||
|
shader_parameter/sun_color = Color(1, 1, 1, 1)
|
||||||
|
|
||||||
|
[node name="EnvironmentManager" type="Node3D" unique_id=1611939731 node_paths=PackedStringArray("particles_wind", "particles_snow", "particles_fireflies", "particles_rain", "environment_dust", "blur", "environment_shadows", "fog")]
|
||||||
script = ExtResource("1_wecen")
|
script = ExtResource("1_wecen")
|
||||||
environment_config = SubResource("Resource_r4tfj")
|
environment_config = SubResource("Resource_r4tfj")
|
||||||
particles_wind = NodePath("Particles_Wind")
|
particles_wind = NodePath("Particles_Wind")
|
||||||
@@ -212,6 +281,7 @@ godray = ExtResource("5_411rw")
|
|||||||
environment_dust = NodePath("EnvironmentDust")
|
environment_dust = NodePath("EnvironmentDust")
|
||||||
blur = NodePath("Blur")
|
blur = NodePath("Blur")
|
||||||
environment_shadows = NodePath("EnvironmentCloudsShadows")
|
environment_shadows = NodePath("EnvironmentCloudsShadows")
|
||||||
|
fog = NodePath("Fog")
|
||||||
|
|
||||||
[node name="Particles_Fireflies" type="GPUParticles3D" parent="." unique_id=947538133]
|
[node name="Particles_Fireflies" type="GPUParticles3D" parent="." unique_id=947538133]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0)
|
||||||
@@ -222,9 +292,10 @@ process_material = SubResource("ParticleProcessMaterial_i3hjl")
|
|||||||
draw_pass_1 = SubResource("QuadMesh_b5atu")
|
draw_pass_1 = SubResource("QuadMesh_b5atu")
|
||||||
|
|
||||||
[node name="Particles_Wind" type="GPUParticles3D" parent="." unique_id=1238214694]
|
[node name="Particles_Wind" type="GPUParticles3D" parent="." unique_id=1238214694]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 50, 0)
|
transform = Transform3D(1, 0, 0, 0, -4.371139e-08, -1, 0, 1, -4.371139e-08, 0, 50, 0)
|
||||||
|
cast_shadow = 0
|
||||||
emitting = false
|
emitting = false
|
||||||
amount = 100
|
amount = 25
|
||||||
lifetime = 3.0
|
lifetime = 3.0
|
||||||
fixed_fps = 60
|
fixed_fps = 60
|
||||||
process_material = SubResource("ParticleProcessMaterial_ruhh7")
|
process_material = SubResource("ParticleProcessMaterial_ruhh7")
|
||||||
@@ -271,3 +342,15 @@ mouse_filter = 2
|
|||||||
extra_cull_margin = 16384.0
|
extra_cull_margin = 16384.0
|
||||||
mesh = SubResource("QuadMesh_sxgg7")
|
mesh = SubResource("QuadMesh_sxgg7")
|
||||||
surface_material_override/0 = SubResource("ShaderMaterial_oqt1s")
|
surface_material_override/0 = SubResource("ShaderMaterial_oqt1s")
|
||||||
|
|
||||||
|
[node name="Fog" type="Node3D" parent="." unique_id=1626352238]
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="Fog" unique_id=96635311]
|
||||||
|
transform = Transform3D(-42.075005, 7.553328e-06, 1.7196172e-13, 0, -3.7766642e-06, 45, 3.6783138e-06, 86.4, 1.9670128e-06, -41.926987, 14, 0)
|
||||||
|
mesh = SubResource("QuadMesh_yn8v8")
|
||||||
|
surface_material_override/0 = SubResource("ShaderMaterial_sxgg7")
|
||||||
|
|
||||||
|
[node name="MeshInstance3D2" type="MeshInstance3D" parent="Fog" unique_id=10121049]
|
||||||
|
transform = Transform3D(-42.075005, 7.553328e-06, 1.7196172e-13, 0, -3.7766642e-06, 45, 3.6783138e-06, 86.4, 1.9670128e-06, 59.320038, 14, 0)
|
||||||
|
mesh = SubResource("QuadMesh_yn8v8")
|
||||||
|
surface_material_override/0 = SubResource("ShaderMaterial_sxgg7")
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
class_name EnvironmentManagerRoot
|
class_name EnvironmentManagerRoot
|
||||||
extends Node3D
|
extends Node3D
|
||||||
|
|
||||||
|
const NOISE_TEXTURE: Texture2D = preload("res://core/daynight/noise.tres")
|
||||||
|
const WEATHER_SHADER: Material = preload("res://core/daynight/weather_overlay.tres")
|
||||||
|
const DYNAMIC_ENVIRONMENT_UPDATES_PER_FRAME: int = 2 #how many update of the environment (apply materials) will be done per frame
|
||||||
|
|
||||||
@export var environment_config: EnvironmentConfig
|
@export var environment_config: EnvironmentConfig
|
||||||
|
|
||||||
@export_group("Camera")
|
@export_group("Camera")
|
||||||
@@ -16,6 +20,7 @@ extends Node3D
|
|||||||
@export var environment_dust: ColorRect
|
@export var environment_dust: ColorRect
|
||||||
@export var blur: ColorRect
|
@export var blur: ColorRect
|
||||||
@export var environment_shadows: MeshInstance3D
|
@export var environment_shadows: MeshInstance3D
|
||||||
|
@export var fog: Node3D
|
||||||
|
|
||||||
@export_group("Sound")
|
@export_group("Sound")
|
||||||
@export var thunder_sounds: Array[AudioStream]
|
@export var thunder_sounds: Array[AudioStream]
|
||||||
@@ -30,9 +35,13 @@ var weather_controller: WeatherController
|
|||||||
|
|
||||||
var day_tween: Tween
|
var day_tween: Tween
|
||||||
var day_time: float = 0.0
|
var day_time: float = 0.0
|
||||||
|
var pending_environment_nodes: Dictionary = {}
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
|
||||||
|
#connect shader when new node is added
|
||||||
|
get_tree().node_added.connect(_on_tree_node_added)
|
||||||
|
|
||||||
#set noise texture 2d to materials in special group
|
#set noise texture 2d to materials in special group
|
||||||
ApplyWindNoiseToMaterials()
|
ApplyWindNoiseToMaterials()
|
||||||
#set weather overlay (snow + rain) to materials in special group
|
#set weather overlay (snow + rain) to materials in special group
|
||||||
@@ -55,6 +64,7 @@ func _ready() -> void:
|
|||||||
godray,
|
godray,
|
||||||
environment_dust,
|
environment_dust,
|
||||||
blur,
|
blur,
|
||||||
|
fog,
|
||||||
environment_shadows,
|
environment_shadows,
|
||||||
sun,
|
sun,
|
||||||
environment,
|
environment,
|
||||||
@@ -67,10 +77,67 @@ func _ready() -> void:
|
|||||||
weather_controller.name = "WeatherController"
|
weather_controller.name = "WeatherController"
|
||||||
add_child(weather_controller)
|
add_child(weather_controller)
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
_process_pending_environment_nodes()
|
||||||
|
|
||||||
|
func _on_tree_node_added(node: Node) -> void:
|
||||||
|
if node.is_in_group("wind_node") or node.is_in_group("weather_node") or node.is_in_group("weather_vegetables_node"):
|
||||||
|
_queue_dynamic_environment_node(node)
|
||||||
|
|
||||||
|
func _queue_dynamic_environment_node(node: Node) -> void:
|
||||||
|
if not is_instance_valid(node):
|
||||||
|
return
|
||||||
|
|
||||||
|
var ancestor = node.get_parent()
|
||||||
|
while ancestor != null:
|
||||||
|
if pending_environment_nodes.has(ancestor.get_instance_id()):
|
||||||
|
return
|
||||||
|
ancestor = ancestor.get_parent()
|
||||||
|
|
||||||
|
var stale_ids: Array[int] = []
|
||||||
|
for node_id in pending_environment_nodes.keys():
|
||||||
|
var pending_node = pending_environment_nodes[node_id]
|
||||||
|
if not is_instance_valid(pending_node):
|
||||||
|
stale_ids.append(node_id)
|
||||||
|
continue
|
||||||
|
if node.is_ancestor_of(pending_node):
|
||||||
|
stale_ids.append(node_id)
|
||||||
|
|
||||||
|
for node_id in stale_ids:
|
||||||
|
pending_environment_nodes.erase(node_id)
|
||||||
|
|
||||||
|
pending_environment_nodes[node.get_instance_id()] = node
|
||||||
|
|
||||||
|
func _process_pending_environment_nodes() -> void:
|
||||||
|
var processed = 0
|
||||||
|
for node_id in pending_environment_nodes.keys():
|
||||||
|
if processed >= DYNAMIC_ENVIRONMENT_UPDATES_PER_FRAME:
|
||||||
|
break
|
||||||
|
|
||||||
|
var node = pending_environment_nodes[node_id]
|
||||||
|
pending_environment_nodes.erase(node_id)
|
||||||
|
if not is_instance_valid(node):
|
||||||
|
continue
|
||||||
|
|
||||||
|
_apply_dynamic_environment_materials(node)
|
||||||
|
processed += 1
|
||||||
|
|
||||||
|
func _apply_dynamic_environment_materials(node: Node) -> void:
|
||||||
|
if not is_instance_valid(node):
|
||||||
|
return
|
||||||
|
|
||||||
|
if node.is_in_group("wind_node"):
|
||||||
|
_apply_wind_noise_to_node(node, NOISE_TEXTURE)
|
||||||
|
|
||||||
|
if node.is_in_group("weather_node"):
|
||||||
|
_apply_weather_overlay_to_node(node, WEATHER_SHADER)
|
||||||
|
|
||||||
|
if node.is_in_group("weather_vegetables_node"):
|
||||||
|
_clear_weather_overlay_from_node(node)
|
||||||
|
|
||||||
func ApplyWindNoiseToMaterials():
|
func ApplyWindNoiseToMaterials():
|
||||||
var noise_tex = preload("res://core/daynight/noise.tres")
|
|
||||||
for node in get_tree().get_nodes_in_group("wind_node"):
|
for node in get_tree().get_nodes_in_group("wind_node"):
|
||||||
_apply_wind_noise_to_node(node, noise_tex)
|
_apply_wind_noise_to_node(node, NOISE_TEXTURE)
|
||||||
|
|
||||||
func _apply_wind_noise_to_node(node: Node, noise_tex: Texture2D) -> void:
|
func _apply_wind_noise_to_node(node: Node, noise_tex: Texture2D) -> void:
|
||||||
if node is GeometryInstance3D:
|
if node is GeometryInstance3D:
|
||||||
@@ -88,15 +155,57 @@ func _apply_wind_noise_to_node(node: Node, noise_tex: Texture2D) -> void:
|
|||||||
_apply_wind_noise_to_node(child, noise_tex)
|
_apply_wind_noise_to_node(child, noise_tex)
|
||||||
|
|
||||||
func ApplyWeatherShaderToMaterials():
|
func ApplyWeatherShaderToMaterials():
|
||||||
var weather_shader = preload("res://core/daynight/weather_overlay.tres")
|
|
||||||
|
|
||||||
for node in get_tree().get_nodes_in_group("weather_node"):
|
for node in get_tree().get_nodes_in_group("weather_node"):
|
||||||
|
_apply_weather_overlay_to_node(node, WEATHER_SHADER)
|
||||||
|
|
||||||
|
for node in get_tree().get_nodes_in_group("weather_vegetables_node"):
|
||||||
|
_clear_weather_overlay_from_node(node)
|
||||||
|
|
||||||
|
func _apply_weather_overlay_to_node(node: Node, material: Material) -> void:
|
||||||
|
if node.is_in_group("weather_vegetables_node"):
|
||||||
|
_clear_weather_overlay_from_node(node)
|
||||||
|
return
|
||||||
|
|
||||||
if node is GeometryInstance3D:
|
if node is GeometryInstance3D:
|
||||||
node.material_overlay = weather_shader
|
if _geometry_uses_alpha_texture(node):
|
||||||
|
node.material_overlay = null
|
||||||
else:
|
else:
|
||||||
|
node.material_overlay = material
|
||||||
|
|
||||||
for child in node.get_children():
|
for child in node.get_children():
|
||||||
if child is GeometryInstance3D:
|
_apply_weather_overlay_to_node(child, material)
|
||||||
child.material_overlay = weather_shader
|
|
||||||
|
func _clear_weather_overlay_from_node(node: Node) -> void:
|
||||||
|
if node is GeometryInstance3D:
|
||||||
|
node.material_overlay = null
|
||||||
|
|
||||||
|
for child in node.get_children():
|
||||||
|
_clear_weather_overlay_from_node(child)
|
||||||
|
|
||||||
|
func _geometry_uses_alpha_texture(node: GeometryInstance3D) -> bool:
|
||||||
|
var material_override := node.material_override as ShaderMaterial
|
||||||
|
if _shader_material_uses_alpha_texture(material_override):
|
||||||
|
return true
|
||||||
|
|
||||||
|
if node is MeshInstance3D:
|
||||||
|
for surface_index in node.get_surface_override_material_count():
|
||||||
|
var surface_material := node.get_surface_override_material(surface_index) as ShaderMaterial
|
||||||
|
if _shader_material_uses_alpha_texture(surface_material):
|
||||||
|
return true
|
||||||
|
|
||||||
|
if node.mesh:
|
||||||
|
for surface_index in node.mesh.get_surface_count():
|
||||||
|
var mesh_material := node.mesh.surface_get_material(surface_index) as ShaderMaterial
|
||||||
|
if _shader_material_uses_alpha_texture(mesh_material):
|
||||||
|
return true
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
||||||
|
func _shader_material_uses_alpha_texture(material: ShaderMaterial) -> bool:
|
||||||
|
if material == null or material.shader == null:
|
||||||
|
return false
|
||||||
|
|
||||||
|
return material.shader.code.find("alpha_texture") != -1
|
||||||
|
|
||||||
func select_day_time(normalized_time: float) -> void:
|
func select_day_time(normalized_time: float) -> void:
|
||||||
#set show_day_time_debug = true to show debug on screen
|
#set show_day_time_debug = true to show debug on screen
|
||||||
|
|||||||
@@ -67,7 +67,6 @@ void fragment() {
|
|||||||
float is_center = step(center_sharpness, internal_n);
|
float is_center = step(center_sharpness, internal_n);
|
||||||
|
|
||||||
ALBEDO = shadow_color;
|
ALBEDO = shadow_color;
|
||||||
|
|
||||||
ALPHA = mix(opacity_edge, opacity_center, is_center) * final_fade;
|
ALPHA = mix(opacity_edge, opacity_center, is_center) * final_fade;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ uniform bool use_red_as_alpha = true;
|
|||||||
|
|
||||||
group_uniforms Settings;
|
group_uniforms Settings;
|
||||||
uniform vec4 fog_color : source_color = vec4(0.8, 0.85, 0.9, 0.5);
|
uniform vec4 fog_color : source_color = vec4(0.8, 0.85, 0.9, 0.5);
|
||||||
|
uniform float fog_density : hint_range(0.0, 1.0) = 0.25;
|
||||||
uniform vec2 scroll_speed = vec2(0.05, 0.01);
|
uniform vec2 scroll_speed = vec2(0.05, 0.01);
|
||||||
uniform vec2 texture_scale = vec2(1.0, 1.0);
|
uniform vec2 texture_scale = vec2(1.0, 1.0);
|
||||||
|
|
||||||
@@ -36,5 +37,5 @@ void fragment() {
|
|||||||
vec3 dark_fog = tinted_fog * 0.5;
|
vec3 dark_fog = tinted_fog * 0.5;
|
||||||
ALBEDO = mix(tinted_fog, dark_fog, night_intensity);
|
ALBEDO = mix(tinted_fog, dark_fog, night_intensity);
|
||||||
|
|
||||||
ALPHA = fog_color.a * noise_alpha * edge_mask;
|
ALPHA = fog_color.a * fog_density * noise_alpha * edge_mask;
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,12 @@ global uniform float global_wind_speed;
|
|||||||
global uniform float global_wind_strength;
|
global uniform float global_wind_strength;
|
||||||
global uniform vec2 global_wind_direction;
|
global uniform vec2 global_wind_direction;
|
||||||
//global uniform sampler2D global_wind_noise : filter_linear_mipmap;
|
//global uniform sampler2D global_wind_noise : filter_linear_mipmap;
|
||||||
global uniform float global_snow_amount;
|
global uniform float global_snow_start_time = -1.0;
|
||||||
|
global uniform float global_snow_accumulation_speed = 0.005;
|
||||||
|
global uniform float global_snow_melt_time = -1.0;
|
||||||
|
global uniform float global_snow_melt_speed = 0.1;
|
||||||
|
global uniform float global_snow_amount = 0.0;
|
||||||
|
global uniform float global_rain_intensity;
|
||||||
|
|
||||||
// --- PARAMETRI ESTETICI ---
|
// --- PARAMETRI ESTETICI ---
|
||||||
uniform bool billboard_enabled = true;
|
uniform bool billboard_enabled = true;
|
||||||
@@ -28,6 +33,7 @@ uniform vec4 variance_color : source_color = vec4(0.3, 0.5, 0.2, 1.0); // Colore
|
|||||||
uniform float variance_intensity : hint_range(0.0, 1.0) = 0.4; // Quanto si vedono le chiazze
|
uniform float variance_intensity : hint_range(0.0, 1.0) = 0.4; // Quanto si vedono le chiazze
|
||||||
|
|
||||||
uniform vec4 snow_color : source_color = vec4(0.85, 0.9, 0.95, 1.0);
|
uniform vec4 snow_color : source_color = vec4(0.85, 0.9, 0.95, 1.0);
|
||||||
|
uniform float snow_visibility : hint_range(0.0, 1.0) = 1.0;
|
||||||
|
|
||||||
// --- CONTROLLO GRADIENTE E RANDOM ---
|
// --- CONTROLLO GRADIENTE E RANDOM ---
|
||||||
uniform float height_min = 0.0;
|
uniform float height_min = 0.0;
|
||||||
@@ -38,6 +44,7 @@ uniform float light_steps : hint_range(1.0, 10.0) = 4.0;
|
|||||||
uniform float random_mix : hint_range(0.0, 1.0) = 0.3;
|
uniform float random_mix : hint_range(0.0, 1.0) = 0.3;
|
||||||
|
|
||||||
uniform float cast_shadow_strength : hint_range(0.0, 1.0) = 0.6;
|
uniform float cast_shadow_strength : hint_range(0.0, 1.0) = 0.6;
|
||||||
|
uniform float wetness_darkening : hint_range(0.0, 0.5) = 0.25;
|
||||||
|
|
||||||
varying vec3 v_final_color;
|
varying vec3 v_final_color;
|
||||||
varying float v_shade_factor;
|
varying float v_shade_factor;
|
||||||
@@ -49,6 +56,21 @@ float hash(vec3 p) {
|
|||||||
return fract((p.x + p.y) * p.z);
|
return fract((p.x + p.y) * p.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float get_snow_progress() {
|
||||||
|
float snow_progress = clamp(global_snow_amount, 0.0, 1.0);
|
||||||
|
|
||||||
|
if (global_snow_start_time >= 0.0) {
|
||||||
|
float timed_progress = clamp((TIME - global_snow_start_time) * global_snow_accumulation_speed, 0.0, 1.0);
|
||||||
|
snow_progress = max(snow_progress, timed_progress);
|
||||||
|
}
|
||||||
|
if (global_snow_melt_time >= 0.0) {
|
||||||
|
float melt = clamp((TIME - global_snow_melt_time) * global_snow_melt_speed, 0.0, 1.0);
|
||||||
|
snow_progress = min(snow_progress, 1.0 - melt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return snow_progress;
|
||||||
|
}
|
||||||
|
|
||||||
void vertex() {
|
void vertex() {
|
||||||
vec3 instance_pos = MODEL_MATRIX[3].xyz;
|
vec3 instance_pos = MODEL_MATRIX[3].xyz;
|
||||||
v_world_pos = instance_pos; // Salviamo la posizione dell'istanza
|
v_world_pos = instance_pos; // Salviamo la posizione dell'istanza
|
||||||
@@ -110,21 +132,26 @@ void fragment() {
|
|||||||
// Applichiamo la variazione al colore finale dell'erba
|
// Applichiamo la variazione al colore finale dell'erba
|
||||||
vec3 varied_grass_color = mix(v_final_color, variance_color.rgb, noise_sample * variance_intensity);
|
vec3 varied_grass_color = mix(v_final_color, variance_color.rgb, noise_sample * variance_intensity);
|
||||||
|
|
||||||
|
float snow_amount = smoothstep(0.0, 1.0, get_snow_progress());
|
||||||
|
|
||||||
float top_mask = 1.0 - shifted_uv.y;
|
float top_mask = 1.0 - shifted_uv.y;
|
||||||
float snow_mask = smoothstep(1.0 - global_snow_amount, 1.2 - global_snow_amount, top_mask);
|
float snow_mask = smoothstep(0.65, 1.0, top_mask) * snow_amount * snow_visibility;
|
||||||
snow_mask *= step(0.01, global_snow_amount);
|
snow_mask *= step(0.01, snow_amount);
|
||||||
|
|
||||||
vec3 dark_snow = snow_color.rgb * (1.0 - shadow_intensity);
|
vec3 dark_snow = snow_color.rgb * (1.0 - shadow_intensity);
|
||||||
vec3 shaded_snow = mix(dark_snow, snow_color.rgb, v_shade_factor);
|
vec3 shaded_snow = mix(dark_snow, snow_color.rgb, v_shade_factor);
|
||||||
|
|
||||||
// Mescoliamo il colore variato con la neve
|
// Mescoliamo il colore variato con la neve
|
||||||
vec3 final_albedo = mix(varied_grass_color, shaded_snow, snow_mask);
|
vec3 final_albedo = mix(varied_grass_color, shaded_snow, snow_mask);
|
||||||
|
float rain_int = clamp(global_rain_intensity, 0.0, 1.0);
|
||||||
|
final_albedo *= mix(1.0, 1.0 - wetness_darkening, rain_int);
|
||||||
|
float final_roughness = mix(0.02, 0.005, rain_int);
|
||||||
|
|
||||||
ALBEDO = final_albedo;
|
ALBEDO = final_albedo;
|
||||||
ALPHA = tex.r * opacity;
|
ALPHA = tex.r * opacity;
|
||||||
ALPHA_SCISSOR_THRESHOLD = 0.5;
|
ALPHA_SCISSOR_THRESHOLD = 0.5;
|
||||||
|
|
||||||
ROUGHNESS = 0.02;
|
ROUGHNESS = final_roughness;
|
||||||
}
|
}
|
||||||
|
|
||||||
void light() {
|
void light() {
|
||||||
|
|||||||
107
core/daynight/snow_cap.gd
Normal file
107
core/daynight/snow_cap.gd
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
## Procedural snow cap geometry for flat roofs and vehicles.
|
||||||
|
extends Node3D
|
||||||
|
|
||||||
|
enum PlacementMode {
|
||||||
|
AUTO_TARGET_AABB,
|
||||||
|
MANUAL_SURFACE,
|
||||||
|
}
|
||||||
|
|
||||||
|
const SNOW_CAP_SHADER: Shader = preload("res://core/daynight/snow_cap.gdshader")
|
||||||
|
|
||||||
|
@export var placement_mode: PlacementMode = PlacementMode.AUTO_TARGET_AABB
|
||||||
|
@export var target_path: NodePath
|
||||||
|
@export var size_inset: Vector2 = Vector2(0.25, 1.0)
|
||||||
|
@export var position_offset: Vector3 = Vector3(0.0, -0.08, 0.0)
|
||||||
|
@export var max_snow_height: float = 0.2
|
||||||
|
@export_range(1, 24) var subdivide_width: int = 6
|
||||||
|
@export_range(1, 24) var subdivide_depth: int = 18
|
||||||
|
@export var manual_surface_center: Vector3 = Vector3.ZERO
|
||||||
|
@export var manual_surface_size: Vector2 = Vector2(2.0, 6.0)
|
||||||
|
|
||||||
|
var _mesh_instance: MeshInstance3D
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
add_to_group("weather_overlay_ignore")
|
||||||
|
_ensure_mesh_instance()
|
||||||
|
_rebuild()
|
||||||
|
|
||||||
|
func rebuild() -> void:
|
||||||
|
_rebuild()
|
||||||
|
|
||||||
|
func _ensure_mesh_instance() -> void:
|
||||||
|
_mesh_instance = get_node_or_null("SnowCapMesh") as MeshInstance3D
|
||||||
|
if _mesh_instance != null:
|
||||||
|
return
|
||||||
|
|
||||||
|
_mesh_instance = MeshInstance3D.new()
|
||||||
|
_mesh_instance.name = "SnowCapMesh"
|
||||||
|
_mesh_instance.add_to_group("weather_overlay_ignore")
|
||||||
|
add_child(_mesh_instance)
|
||||||
|
|
||||||
|
func _rebuild() -> void:
|
||||||
|
var cap_width: float = 0.0
|
||||||
|
var cap_depth: float = 0.0
|
||||||
|
var cap_surface_center := Vector3.ZERO
|
||||||
|
|
||||||
|
if placement_mode == PlacementMode.MANUAL_SURFACE:
|
||||||
|
cap_width = manual_surface_size.x
|
||||||
|
cap_depth = manual_surface_size.y
|
||||||
|
cap_surface_center = manual_surface_center
|
||||||
|
else:
|
||||||
|
var target_mesh: MeshInstance3D = get_node_or_null(target_path) as MeshInstance3D
|
||||||
|
if target_mesh == null:
|
||||||
|
if _mesh_instance:
|
||||||
|
_mesh_instance.visible = false
|
||||||
|
return
|
||||||
|
|
||||||
|
var target_aabb: AABB = _get_target_aabb(target_mesh)
|
||||||
|
cap_width = max(target_aabb.size.x - size_inset.x, 0.1)
|
||||||
|
cap_depth = max(target_aabb.size.z - size_inset.y, 0.1)
|
||||||
|
cap_surface_center = Vector3(
|
||||||
|
target_aabb.position.x + target_aabb.size.x * 0.5,
|
||||||
|
target_aabb.position.y + target_aabb.size.y,
|
||||||
|
target_aabb.position.z + target_aabb.size.z * 0.5
|
||||||
|
)
|
||||||
|
|
||||||
|
var cap_center := cap_surface_center + Vector3(0.0, max_snow_height * 0.5, 0.0)
|
||||||
|
|
||||||
|
var box_mesh := BoxMesh.new()
|
||||||
|
box_mesh.size = Vector3(cap_width, max_snow_height, cap_depth)
|
||||||
|
box_mesh.subdivide_width = subdivide_width
|
||||||
|
box_mesh.subdivide_depth = subdivide_depth
|
||||||
|
_mesh_instance.mesh = box_mesh
|
||||||
|
_mesh_instance.position = cap_center + position_offset
|
||||||
|
_mesh_instance.material_override = _build_material(cap_width, cap_depth)
|
||||||
|
_mesh_instance.visible = true
|
||||||
|
|
||||||
|
func _build_material(cap_width: float, cap_depth: float) -> ShaderMaterial:
|
||||||
|
var material := ShaderMaterial.new()
|
||||||
|
material.shader = SNOW_CAP_SHADER
|
||||||
|
material.set_shader_parameter("max_height", max_snow_height)
|
||||||
|
material.set_shader_parameter("half_width", cap_width * 0.5)
|
||||||
|
material.set_shader_parameter("half_depth", cap_depth * 0.5)
|
||||||
|
return material
|
||||||
|
|
||||||
|
func _get_target_aabb(target_mesh: MeshInstance3D) -> AABB:
|
||||||
|
var points: Array[Vector3] = []
|
||||||
|
for point in _get_aabb_points(target_mesh.get_aabb()):
|
||||||
|
points.append(target_mesh.transform * point)
|
||||||
|
|
||||||
|
var merged := AABB(points[0], Vector3.ZERO)
|
||||||
|
for point in points:
|
||||||
|
merged = merged.expand(point)
|
||||||
|
return merged
|
||||||
|
|
||||||
|
func _get_aabb_points(aabb: AABB) -> Array[Vector3]:
|
||||||
|
var p: Vector3 = aabb.position
|
||||||
|
var s: Vector3 = aabb.size
|
||||||
|
return [
|
||||||
|
p,
|
||||||
|
p + Vector3(s.x, 0.0, 0.0),
|
||||||
|
p + Vector3(0.0, s.y, 0.0),
|
||||||
|
p + Vector3(0.0, 0.0, s.z),
|
||||||
|
p + Vector3(s.x, s.y, 0.0),
|
||||||
|
p + Vector3(s.x, 0.0, s.z),
|
||||||
|
p + Vector3(0.0, s.y, s.z),
|
||||||
|
p + s,
|
||||||
|
]
|
||||||
1
core/daynight/snow_cap.gd.uid
Normal file
1
core/daynight/snow_cap.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://bxc6ketfgedxw
|
||||||
116
core/daynight/snow_cap.gdshader
Normal file
116
core/daynight/snow_cap.gdshader
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
shader_type spatial;
|
||||||
|
render_mode blend_mix, cull_back, depth_draw_opaque;
|
||||||
|
|
||||||
|
global uniform float global_snow_start_time = -1.0;
|
||||||
|
global uniform float global_snow_accumulation_speed = 0.005;
|
||||||
|
global uniform float global_snow_melt_time = -1.0;
|
||||||
|
global uniform float global_snow_melt_speed = 0.1;
|
||||||
|
global uniform float global_snow_amount = 0.0;
|
||||||
|
global uniform vec4 global_snow_color = vec4(0.92, 0.96, 1.0, 1.0);
|
||||||
|
|
||||||
|
uniform float max_height : hint_range(0.02, 1.0) = 0.2;
|
||||||
|
uniform float half_width : hint_range(0.01, 20.0) = 1.0;
|
||||||
|
uniform float half_depth : hint_range(0.01, 20.0) = 1.0;
|
||||||
|
uniform float noise_scale : hint_range(0.05, 2.0) = 0.35;
|
||||||
|
uniform float noise_strength : hint_range(0.0, 0.4) = 0.18;
|
||||||
|
uniform float edge_rounding : hint_range(0.0, 0.3) = 0.12;
|
||||||
|
uniform float side_shade : hint_range(0.2, 1.0) = 0.82;
|
||||||
|
uniform float sparkle_strength : hint_range(0.0, 0.1) = 0.03;
|
||||||
|
|
||||||
|
varying float v_snow_amount;
|
||||||
|
varying float v_noise;
|
||||||
|
|
||||||
|
float hash(vec2 p) {
|
||||||
|
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
|
||||||
|
}
|
||||||
|
|
||||||
|
float value_noise(vec2 p) {
|
||||||
|
vec2 i = floor(p);
|
||||||
|
vec2 f = fract(p);
|
||||||
|
vec2 u = f * f * (3.0 - 2.0 * f);
|
||||||
|
|
||||||
|
float a = hash(i);
|
||||||
|
float b = hash(i + vec2(1.0, 0.0));
|
||||||
|
float c = hash(i + vec2(0.0, 1.0));
|
||||||
|
float d = hash(i + vec2(1.0, 1.0));
|
||||||
|
|
||||||
|
return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
float fbm(vec2 p) {
|
||||||
|
float value = 0.0;
|
||||||
|
float amplitude = 0.5;
|
||||||
|
float frequency = 1.0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
value += value_noise(p * frequency) * amplitude;
|
||||||
|
frequency *= 2.0;
|
||||||
|
amplitude *= 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
return clamp(value, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float get_snow_amount() {
|
||||||
|
float snow_amount = clamp(global_snow_amount, 0.0, 1.0);
|
||||||
|
if (global_snow_start_time >= 0.0) {
|
||||||
|
float timed_amount = clamp(
|
||||||
|
(TIME - global_snow_start_time) * global_snow_accumulation_speed,
|
||||||
|
0.0,
|
||||||
|
1.0
|
||||||
|
);
|
||||||
|
snow_amount = max(snow_amount, timed_amount);
|
||||||
|
}
|
||||||
|
if (global_snow_melt_time >= 0.0) {
|
||||||
|
float melt = clamp((TIME - global_snow_melt_time) * global_snow_melt_speed, 0.0, 1.0);
|
||||||
|
snow_amount = min(snow_amount, 1.0 - melt);
|
||||||
|
}
|
||||||
|
return snow_amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vertex() {
|
||||||
|
vec3 base_vertex = VERTEX;
|
||||||
|
vec3 world_pos = (MODEL_MATRIX * vec4(base_vertex, 1.0)).xyz;
|
||||||
|
float snow_amount = get_snow_amount();
|
||||||
|
float noise_val = fbm(world_pos.xz * noise_scale);
|
||||||
|
float thickness = max_height * snow_amount * mix(
|
||||||
|
1.0 - noise_strength,
|
||||||
|
1.0 + noise_strength,
|
||||||
|
noise_val
|
||||||
|
);
|
||||||
|
float footprint_growth = smoothstep(0.0, 0.35, snow_amount);
|
||||||
|
|
||||||
|
float from_bottom = clamp((base_vertex.y + max_height * 0.5) / max_height, 0.0, 1.0);
|
||||||
|
VERTEX.y = -max_height * 0.5 + thickness * from_bottom;
|
||||||
|
VERTEX.x *= mix(0.92, 1.0, footprint_growth);
|
||||||
|
VERTEX.z *= mix(0.94, 1.0, footprint_growth);
|
||||||
|
|
||||||
|
float edge_x = abs(base_vertex.x) / max(half_width, 0.001);
|
||||||
|
float edge_z = abs(base_vertex.z) / max(half_depth, 0.001);
|
||||||
|
float edge_mask = smoothstep(0.55, 1.0, max(edge_x, edge_z));
|
||||||
|
float top_mask = smoothstep(0.6, 1.0, from_bottom) * snow_amount;
|
||||||
|
float round_factor = edge_rounding * edge_mask * top_mask;
|
||||||
|
VERTEX.x *= 1.0 - round_factor;
|
||||||
|
VERTEX.z *= 1.0 - round_factor;
|
||||||
|
|
||||||
|
v_snow_amount = snow_amount;
|
||||||
|
v_noise = noise_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fragment() {
|
||||||
|
if (v_snow_amount <= 0.001) {
|
||||||
|
ALPHA = 0.0;
|
||||||
|
ALBEDO = global_snow_color.rgb;
|
||||||
|
ROUGHNESS = 1.0;
|
||||||
|
SPECULAR = 0.0;
|
||||||
|
} else {
|
||||||
|
float facing_up = clamp(NORMAL.y, 0.0, 1.0);
|
||||||
|
float shade = mix(-sparkle_strength, sparkle_strength, v_noise);
|
||||||
|
vec3 snow_albedo = clamp(global_snow_color.rgb + vec3(shade), 0.0, 1.0);
|
||||||
|
|
||||||
|
ALBEDO = mix(snow_albedo * side_shade, snow_albedo, facing_up);
|
||||||
|
ROUGHNESS = mix(0.95, 0.72, facing_up);
|
||||||
|
SPECULAR = 0.18;
|
||||||
|
ALPHA = smoothstep(0.0, 0.28, v_snow_amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
1
core/daynight/snow_cap.gdshader.uid
Normal file
1
core/daynight/snow_cap.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://c7js7ytvewmab
|
||||||
@@ -6,10 +6,11 @@ global uniform vec2 global_wind_direction;
|
|||||||
global uniform float global_wind_scale;
|
global uniform float global_wind_scale;
|
||||||
global uniform float global_wind_strength;
|
global uniform float global_wind_strength;
|
||||||
global uniform float global_wind_fade;
|
global uniform float global_wind_fade;
|
||||||
global uniform float global_snow_start_time;
|
global uniform float global_snow_start_time = -1.0;
|
||||||
global uniform float global_snow_accumulation_speed;
|
global uniform float global_snow_accumulation_speed = 0.005;
|
||||||
global uniform float global_snow_melt_time;
|
global uniform float global_snow_melt_time = -1.0;
|
||||||
global uniform float global_snow_melt_speed;
|
global uniform float global_snow_melt_speed = 0.1;
|
||||||
|
global uniform float global_snow_amount = 0.0;
|
||||||
global uniform vec4 global_snow_color;
|
global uniform vec4 global_snow_color;
|
||||||
global uniform float global_rain_intensity;
|
global uniform float global_rain_intensity;
|
||||||
|
|
||||||
@@ -30,6 +31,7 @@ uniform float light_steps : hint_range(1.0, 10.0) = 4.0;
|
|||||||
uniform float random_mix : hint_range(0.0, 1.0) = 0.3;
|
uniform float random_mix : hint_range(0.0, 1.0) = 0.3;
|
||||||
uniform float cast_shadow_strength : hint_range(0.0, 1.0) = 0.6;
|
uniform float cast_shadow_strength : hint_range(0.0, 1.0) = 0.6;
|
||||||
uniform float wetness_darkening : hint_range(0.0, 0.5) = 0.25;
|
uniform float wetness_darkening : hint_range(0.0, 0.5) = 0.25;
|
||||||
|
uniform float snow_visibility : hint_range(0.0, 1.0) = 1.0;
|
||||||
|
|
||||||
varying vec3 v_final_color;
|
varying vec3 v_final_color;
|
||||||
varying float v_shade_factor;
|
varying float v_shade_factor;
|
||||||
@@ -40,6 +42,21 @@ float hash(vec3 p) {
|
|||||||
return fract((p.x + p.y) * p.z);
|
return fract((p.x + p.y) * p.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float get_snow_progress() {
|
||||||
|
float snow_progress = clamp(global_snow_amount, 0.0, 1.0);
|
||||||
|
|
||||||
|
if (global_snow_start_time >= 0.0) {
|
||||||
|
float timed_progress = clamp((TIME - global_snow_start_time) * global_snow_accumulation_speed, 0.0, 1.0);
|
||||||
|
snow_progress = max(snow_progress, timed_progress);
|
||||||
|
}
|
||||||
|
if (global_snow_melt_time >= 0.0) {
|
||||||
|
float melt = clamp((TIME - global_snow_melt_time) * global_snow_melt_speed, 0.0, 1.0);
|
||||||
|
snow_progress = min(snow_progress, 1.0 - melt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return snow_progress;
|
||||||
|
}
|
||||||
|
|
||||||
void vertex() {
|
void vertex() {
|
||||||
vec3 instance_pos = MODEL_MATRIX[3].xyz;
|
vec3 instance_pos = MODEL_MATRIX[3].xyz;
|
||||||
|
|
||||||
@@ -88,17 +105,10 @@ void fragment() {
|
|||||||
vec4 tex = texture(alpha_texture, shifted_uv);
|
vec4 tex = texture(alpha_texture, shifted_uv);
|
||||||
|
|
||||||
// Snow accumulation
|
// Snow accumulation
|
||||||
float snow_amount = 0.0;
|
float snow_amount = pow(get_snow_progress(), 0.55);
|
||||||
if (global_snow_start_time >= 0.0) {
|
|
||||||
snow_amount = clamp((TIME - global_snow_start_time) * global_snow_accumulation_speed, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
if (global_snow_melt_time >= 0.0) {
|
|
||||||
float melt = clamp((TIME - global_snow_melt_time) * global_snow_melt_speed, 0.0, 1.0);
|
|
||||||
snow_amount *= (1.0 - melt);
|
|
||||||
}
|
|
||||||
|
|
||||||
float top_mask = 1.0 - shifted_uv.y;
|
float top_mask = 1.0 - shifted_uv.y;
|
||||||
float snow_mask = smoothstep(1.0 - snow_amount, 1.2 - snow_amount, top_mask);
|
float snow_mask = smoothstep(1.0 - snow_amount * 1.35, 1.08 - snow_amount * 1.35, top_mask) * snow_visibility;
|
||||||
snow_mask *= step(0.01, snow_amount);
|
snow_mask *= step(0.01, snow_amount);
|
||||||
|
|
||||||
vec3 dark_snow = global_snow_color.rgb * (1.0 - shadow_intensity);
|
vec3 dark_snow = global_snow_color.rgb * (1.0 - shadow_intensity);
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
shader_type spatial;
|
shader_type spatial;
|
||||||
render_mode blend_mix, depth_draw_always;
|
render_mode blend_mix, depth_draw_always;
|
||||||
|
|
||||||
|
global uniform float global_rain_intensity;
|
||||||
|
global uniform vec4 global_water_color = vec4(0.285, 0.534, 0.487, 1.0);
|
||||||
|
global uniform float global_snow_start_time = -1.0;
|
||||||
|
global uniform float global_snow_accumulation_speed = 0.005;
|
||||||
|
global uniform float global_snow_melt_time = -1.0;
|
||||||
|
global uniform float global_snow_melt_speed = 0.1;
|
||||||
|
global uniform float global_snow_amount = 0.0;
|
||||||
|
global uniform vec4 global_snow_color = vec4(0.92, 0.96, 1.0, 1.0);
|
||||||
|
|
||||||
//Water color
|
//Water color
|
||||||
uniform vec4 deep_water_color : source_color = vec4(0.0, 0.1, 0.2, 1.0);
|
uniform vec4 deep_water_color : source_color = vec4(0.0, 0.1, 0.2, 1.0);
|
||||||
uniform vec4 shallow_water_color : source_color = vec4(0.0, 0.4, 0.7, 1.0);
|
uniform vec4 shallow_water_color : source_color = vec4(0.0, 0.4, 0.7, 1.0);
|
||||||
@@ -26,6 +35,21 @@ uniform sampler2D depth_texture : hint_depth_texture, filter_linear_mipmap;
|
|||||||
varying vec2 world_pos_xz;
|
varying vec2 world_pos_xz;
|
||||||
varying vec2 local_uv;
|
varying vec2 local_uv;
|
||||||
|
|
||||||
|
float get_snow_progress() {
|
||||||
|
float snow_progress = clamp(global_snow_amount, 0.0, 1.0);
|
||||||
|
|
||||||
|
if (global_snow_start_time >= 0.0) {
|
||||||
|
float timed_progress = clamp((TIME - global_snow_start_time) * global_snow_accumulation_speed, 0.0, 1.0);
|
||||||
|
snow_progress = max(snow_progress, timed_progress);
|
||||||
|
}
|
||||||
|
if (global_snow_melt_time >= 0.0) {
|
||||||
|
float melt = clamp((TIME - global_snow_melt_time) * global_snow_melt_speed, 0.0, 1.0);
|
||||||
|
snow_progress = min(snow_progress, 1.0 - melt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return snow_progress;
|
||||||
|
}
|
||||||
|
|
||||||
void vertex() {
|
void vertex() {
|
||||||
world_pos_xz = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xz;
|
world_pos_xz = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xz;
|
||||||
local_uv = UV;
|
local_uv = UV;
|
||||||
@@ -41,12 +65,15 @@ void fragment() {
|
|||||||
|
|
||||||
float water_depth_gradient = exp(-depth_difference * beer_law_factor);
|
float water_depth_gradient = exp(-depth_difference * beer_law_factor);
|
||||||
vec4 base_water = mix(deep_water_color, shallow_water_color, water_depth_gradient);
|
vec4 base_water = mix(deep_water_color, shallow_water_color, water_depth_gradient);
|
||||||
|
float rain_intensity = clamp(global_rain_intensity, 0.0, 1.0);
|
||||||
|
base_water.rgb = mix(base_water.rgb, global_water_color.rgb, 0.7);
|
||||||
|
|
||||||
vec2 pos = world_pos_xz * ripple_scale;
|
vec2 pos = world_pos_xz * ripple_scale;
|
||||||
vec2 cell = floor(pos);
|
vec2 cell = floor(pos);
|
||||||
vec2 local_pos = fract(pos) - 0.5;
|
vec2 local_pos = fract(pos) - 0.5;
|
||||||
float random_val = fract(sin(dot(cell, vec2(12.9898, 78.233))) * 43758.5453);
|
float random_val = fract(sin(dot(cell, vec2(12.9898, 78.233))) * 43758.5453);
|
||||||
float is_active_cell = step(1.0 - ripple_density, random_val);
|
float active_ripple_density = ripple_density * rain_intensity;
|
||||||
|
float is_active_cell = step(1.0 - active_ripple_density, random_val);
|
||||||
|
|
||||||
float ring = 0.0;
|
float ring = 0.0;
|
||||||
if (is_active_cell > 0.0) {
|
if (is_active_cell > 0.0) {
|
||||||
@@ -56,6 +83,7 @@ void fragment() {
|
|||||||
- smoothstep(local_time, local_time + ripple_thickness, dist);
|
- smoothstep(local_time, local_time + ripple_thickness, dist);
|
||||||
ring *= (1.0 - local_time);
|
ring *= (1.0 - local_time);
|
||||||
}
|
}
|
||||||
|
ring *= rain_intensity;
|
||||||
|
|
||||||
vec2 ref_uv = SCREEN_UV;
|
vec2 ref_uv = SCREEN_UV;
|
||||||
|
|
||||||
@@ -75,8 +103,15 @@ void fragment() {
|
|||||||
float is_sky = step(ref_depth_raw, 0.00001); // Protezione anti-cielo
|
float is_sky = step(ref_depth_raw, 0.00001); // Protezione anti-cielo
|
||||||
reflection_mask *= (1.0 - is_sky);
|
reflection_mask *= (1.0 - is_sky);
|
||||||
|
|
||||||
vec3 final_rgb = mix(base_water.rgb, screen_ref, reflection_strength * reflection_mask);
|
float snow_progress = get_snow_progress();
|
||||||
|
float active_snowfall = step(0.0, global_snow_start_time) * (1.0 - step(0.0, global_snow_melt_time));
|
||||||
|
float reflection_snow_damping = max(smoothstep(0.0, 0.08, snow_progress), active_snowfall * 0.75);
|
||||||
|
float effective_reflection_strength = reflection_strength * (1.0 - reflection_snow_damping * 0.85);
|
||||||
|
|
||||||
|
vec3 final_rgb = mix(base_water.rgb, screen_ref, effective_reflection_strength * reflection_mask);
|
||||||
final_rgb = mix(final_rgb, ripple_color.rgb, ring * ripple_color.a);
|
final_rgb = mix(final_rgb, ripple_color.rgb, ring * ripple_color.a);
|
||||||
|
float water_snow_amount = smoothstep(0.15, 1.0, snow_progress) * 0.18;
|
||||||
|
final_rgb = mix(final_rgb, global_snow_color.rgb, water_snow_amount);
|
||||||
|
|
||||||
ALBEDO = final_rgb;
|
ALBEDO = final_rgb;
|
||||||
|
|
||||||
|
|||||||
241
core/daynight/water_river.gdshader
Normal file
241
core/daynight/water_river.gdshader
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
#define USE_CAUSTICS 1
|
||||||
|
#define USE_REFRACTION 1
|
||||||
|
#define USE_DISPLACEMENT 1
|
||||||
|
#define USE_STYLIZED_LIGHTING 0
|
||||||
|
#define USE_UNSHADED 0
|
||||||
|
|
||||||
|
shader_type spatial;
|
||||||
|
#if USE_UNSHADED
|
||||||
|
render_mode unshaded, depth_draw_never;
|
||||||
|
#else
|
||||||
|
render_mode depth_draw_never;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uniform sampler2D DEPTH_TEXTURE: hint_depth_texture;
|
||||||
|
|
||||||
|
group_uniforms Color;
|
||||||
|
uniform vec4 surface_color : source_color = vec4(0.2,1.0,0.8,1.0);
|
||||||
|
uniform vec4 depth_color : source_color = vec4(0.08,0.2,0.4,1.0);
|
||||||
|
uniform vec4 foam_color : source_color = vec4(1.0);
|
||||||
|
uniform float depth_size = 12.0;
|
||||||
|
|
||||||
|
group_uniforms Roughness;
|
||||||
|
uniform float surface_roughness : hint_range(0.0, 1.0, 0.01) = 0.05;
|
||||||
|
uniform float foam_roughness : hint_range(0.0, 1.0, 0.01) = 0.05;
|
||||||
|
|
||||||
|
#if USE_CAUSTICS
|
||||||
|
group_uniforms Caustics;
|
||||||
|
uniform sampler2D caustics_texture;
|
||||||
|
uniform float caustics_strength = 2.0;
|
||||||
|
uniform vec2 caustics_scale = vec2(0.5);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
group_uniforms Wave;
|
||||||
|
uniform sampler2D wave_texture;
|
||||||
|
uniform float wave_softness : hint_range(0.0, 10.0, 0.1) = 3.0;
|
||||||
|
uniform vec2 wave_scale = vec2(0.2);
|
||||||
|
uniform vec2 wave_layer_scale = vec2(1.5);
|
||||||
|
uniform float wave_highlight : hint_range(0.0, 1.0, 0.05) = 0.5;
|
||||||
|
|
||||||
|
group_uniforms Wave.Motion;
|
||||||
|
uniform vec2 wave_velocity = vec2(0.02);
|
||||||
|
instance uniform vec2 river_flow_direction = vec2(0.0, 0.0);
|
||||||
|
|
||||||
|
group_uniforms Foam;
|
||||||
|
uniform sampler2D foam_texture;
|
||||||
|
uniform float edge_foam_depth_size = 1.0;
|
||||||
|
uniform float wave_foam_amount : hint_range(0.0, 1.0, 0.01) = 0.8;
|
||||||
|
uniform float foam_start : hint_range(0.0, 1.0, 0.05) = 0.15;
|
||||||
|
uniform float foam_end : hint_range(0.0, 1.0, 0.05) = 0.3;
|
||||||
|
uniform float foam_exponent = 2.0;
|
||||||
|
|
||||||
|
#if USE_REFRACTION
|
||||||
|
group_uniforms Refraction;
|
||||||
|
uniform float refraction_amount = 0.5;
|
||||||
|
uniform float refraction_exponent = 0.5;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_DISPLACEMENT
|
||||||
|
group_uniforms Displacement;
|
||||||
|
uniform float displacement_amount = 0.3;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_STYLIZED_LIGHTING && !USE_UNSHADED
|
||||||
|
group_uniforms Lighting;
|
||||||
|
uniform float diffuse_steps = 12.0;
|
||||||
|
uniform float diffuse_smoothness : hint_range(0.0, 1.0, 0.01) = 0.2;
|
||||||
|
uniform float specular_steps = 12.0;
|
||||||
|
uniform float specular_smoothness : hint_range(0.0, 1.0, 0.01) = 0.2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uniform sampler2D screen_texture : hint_screen_texture;
|
||||||
|
varying vec3 world_pos;
|
||||||
|
varying vec2 world_wave_velocity;
|
||||||
|
|
||||||
|
#if USE_CAUSTICS
|
||||||
|
vec3 sample_caustics(vec2 uv){
|
||||||
|
vec2 caustics_uv = uv * caustics_scale;
|
||||||
|
return vec3(
|
||||||
|
texture(caustics_texture, caustics_uv).r,
|
||||||
|
texture(caustics_texture, caustics_uv+vec2(0.02,0.02)).r,
|
||||||
|
texture(caustics_texture, caustics_uv+vec2(0.03,0.01)).r
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
vec4 sample_world_dpos(vec2 screen_uv, mat4 inv_proj_mat, mat4 inv_view_mat){
|
||||||
|
vec4 clip_pos = vec4(screen_uv * 2.0 - 1.0, texture(DEPTH_TEXTURE, screen_uv).r, 1.0);
|
||||||
|
vec4 view_pos = inv_proj_mat * clip_pos;
|
||||||
|
view_pos /= view_pos.w;
|
||||||
|
vec4 world_dpos = inv_view_mat * view_pos;
|
||||||
|
return world_dpos;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 sample_wave(sampler2D tex, vec2 uv, vec2 velocity, float lod){
|
||||||
|
vec2 base_uv = uv * wave_scale;
|
||||||
|
vec2 wave_uv1 = (base_uv * wave_layer_scale) + (TIME * -velocity);
|
||||||
|
float wave1 = textureLod(tex, wave_uv1, lod).r;
|
||||||
|
|
||||||
|
vec2 wave_uv2 = base_uv + (TIME * velocity);
|
||||||
|
vec4 wave2 = textureLod(tex, wave_uv2 - (wave1 * 0.1), lod);
|
||||||
|
|
||||||
|
return wave2;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 sample_wave_normal(vec2 uv, vec2 velocity, float center_wave) {
|
||||||
|
vec2 normal_offset = vec2(0.25, 0.0);
|
||||||
|
float wave_x = sample_wave(wave_texture, uv + normal_offset.xy, velocity, wave_softness).r;
|
||||||
|
float wave_z = sample_wave(wave_texture, uv + normal_offset.yx, velocity, wave_softness).r;
|
||||||
|
vec2 slope = vec2(center_wave - wave_x, center_wave - wave_z) * 0.35;
|
||||||
|
return normalize(vec3(slope, 1.0)) * 0.5 + 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 get_world_wave_velocity(mat4 model_matrix) {
|
||||||
|
float velocity_length = length(wave_velocity);
|
||||||
|
if (velocity_length <= 0.0001) {
|
||||||
|
return vec2(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float flow_direction_length = length(river_flow_direction);
|
||||||
|
if (flow_direction_length > 0.0001) {
|
||||||
|
return (river_flow_direction / flow_direction_length) * velocity_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 world_direction_3d = (model_matrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;
|
||||||
|
vec2 world_direction = world_direction_3d.xz;
|
||||||
|
float world_direction_length = length(world_direction);
|
||||||
|
if (world_direction_length <= 0.0001) {
|
||||||
|
return wave_velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (world_direction / world_direction_length) * velocity_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vertex(){
|
||||||
|
world_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
|
||||||
|
world_wave_velocity = get_world_wave_velocity(MODEL_MATRIX);
|
||||||
|
|
||||||
|
#if USE_DISPLACEMENT
|
||||||
|
float wave = sample_wave(wave_texture, world_pos.xz, world_wave_velocity, wave_softness).r;
|
||||||
|
VERTEX.y += wave*displacement_amount;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void fragment() {
|
||||||
|
float wave = sample_wave(wave_texture, world_pos.xz, world_wave_velocity, wave_softness).r;
|
||||||
|
wave = smoothstep(0.0,1.0,wave);
|
||||||
|
|
||||||
|
vec2 screen_uv = SCREEN_UV;
|
||||||
|
|
||||||
|
// Refraction
|
||||||
|
#if USE_REFRACTION
|
||||||
|
screen_uv += ((pow(wave, refraction_exponent)*2.0 - 0.5) * 0.01 * refraction_amount);
|
||||||
|
|
||||||
|
vec4 world_dpos = sample_world_dpos(screen_uv, INV_PROJECTION_MATRIX, INV_VIEW_MATRIX);
|
||||||
|
|
||||||
|
float pre_depth = pow(clamp((world_dpos.y - world_pos.y + depth_size)/depth_size, 0.0, 1.0), 4.0);
|
||||||
|
screen_uv = mix(screen_uv, SCREEN_UV, pre_depth);
|
||||||
|
if(world_dpos.y - world_pos.y > 0.0){
|
||||||
|
screen_uv = SCREEN_UV;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
vec4 world_dpos = sample_world_dpos(screen_uv, INV_PROJECTION_MATRIX, INV_VIEW_MATRIX);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
world_dpos = sample_world_dpos(screen_uv, INV_PROJECTION_MATRIX, INV_VIEW_MATRIX);
|
||||||
|
|
||||||
|
vec2 surface_uv = world_dpos.xz * 0.2;
|
||||||
|
|
||||||
|
float depth = pow(clamp((world_dpos.y - world_pos.y + depth_size)/depth_size, 0.0, 1.0), 4.0);
|
||||||
|
|
||||||
|
// Caustics
|
||||||
|
#if USE_CAUSTICS
|
||||||
|
vec3 caustics1 = sample_caustics(surface_uv + (TIME * -world_wave_velocity));
|
||||||
|
vec3 caustics2 = sample_caustics((surface_uv + (caustics1.r*0.05)) + (TIME * (world_wave_velocity*0.5)));
|
||||||
|
vec3 caustics = caustics2 * (1.0 - depth);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Edge Foam
|
||||||
|
float edge_foam_depth = clamp((world_dpos.y - world_pos.y + edge_foam_depth_size)/edge_foam_depth_size, 0.0, 1.0);
|
||||||
|
|
||||||
|
// Wave Foam
|
||||||
|
float wave_foam = wave;
|
||||||
|
float foam = max(edge_foam_depth, wave_foam * wave_foam_amount);
|
||||||
|
|
||||||
|
float foam_shape = 1.0 - texture(foam_texture, world_pos.xz* 0.5).r;
|
||||||
|
foam = clamp((foam - foam_start) / (foam_end - foam_start), 0.0, 1.0);
|
||||||
|
foam = clamp((foam - foam_shape) / (1.0 - foam_shape), 0.0, 1.0);
|
||||||
|
foam = pow(foam, foam_exponent);
|
||||||
|
|
||||||
|
vec3 flat_color = mix(depth_color, surface_color, depth).rgb;
|
||||||
|
|
||||||
|
vec4 screen = texture(screen_texture, screen_uv);
|
||||||
|
vec3 color = screen.rgb;
|
||||||
|
#if USE_CAUSTICS
|
||||||
|
color += vec3(pow(caustics * caustics_strength, vec3(2.0)));
|
||||||
|
#endif
|
||||||
|
color = mix(flat_color, color, 0.4 * depth);
|
||||||
|
color = mix(color, surface_color.rgb, wave * wave_highlight);
|
||||||
|
color = mix(color, foam_color.rgb, foam);
|
||||||
|
|
||||||
|
#if !USE_UNSHADED
|
||||||
|
vec3 wave_normal_map = sample_wave_normal(world_pos.xz, world_wave_velocity, wave);
|
||||||
|
NORMAL_MAP = wave_normal_map;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ROUGHNESS = mix(surface_roughness, foam_roughness, foam);
|
||||||
|
|
||||||
|
ALBEDO = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USE_STYLIZED_LIGHTING && !USE_UNSHADED
|
||||||
|
void light(){
|
||||||
|
float ndotl = dot(NORMAL, LIGHT) * ATTENUATION;
|
||||||
|
//ndotl = smoothstep(0.0,1.0-ROUGHNESS,ndotl);
|
||||||
|
float light = ndotl;
|
||||||
|
|
||||||
|
float light_mult = light * diffuse_steps;
|
||||||
|
float light_step_base = floor(light_mult);
|
||||||
|
float light_factor = light_mult - light_step_base;
|
||||||
|
|
||||||
|
light_factor = smoothstep(0.5 - diffuse_smoothness * 0.5, 0.5 + diffuse_smoothness * 0.5, light_factor);
|
||||||
|
light = (light_step_base + light_factor) / diffuse_steps;
|
||||||
|
|
||||||
|
DIFFUSE_LIGHT += (LIGHT_COLOR+ALBEDO) * light / PI;
|
||||||
|
|
||||||
|
float roughness = mix(0.01, 0.99, ROUGHNESS);
|
||||||
|
vec3 h = normalize(VIEW + LIGHT);
|
||||||
|
float ndoth = clamp(dot(NORMAL, h), 0.0, 1.0) * ATTENUATION;
|
||||||
|
float specular = clamp(pow(ndoth, 16.0/(roughness)), 0.1, 0.99);
|
||||||
|
specular = mix(pow(specular, 2.0-roughness),0.00,pow(roughness, 0.1));
|
||||||
|
|
||||||
|
float specular_mult = specular * specular_steps;
|
||||||
|
float specular_step_base = floor(specular_mult);
|
||||||
|
float specular_factor = specular_mult - specular_step_base;
|
||||||
|
|
||||||
|
specular_factor = smoothstep(0.5 - specular_smoothness * 0.5, 0.5 + specular_smoothness * 0.5, specular_factor);
|
||||||
|
specular = (specular_step_base + specular_factor) / specular_steps;
|
||||||
|
|
||||||
|
SPECULAR_LIGHT += (LIGHT_COLOR + ALBEDO) * specular;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
1
core/daynight/water_river.gdshader.uid
Normal file
1
core/daynight/water_river.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://cb12c2j8rfu6a
|
||||||
@@ -14,6 +14,7 @@ var godray: PackedScene
|
|||||||
var environment_dust: ColorRect
|
var environment_dust: ColorRect
|
||||||
var blur: ColorRect
|
var blur: ColorRect
|
||||||
var environment_shadows: MeshInstance3D
|
var environment_shadows: MeshInstance3D
|
||||||
|
var fog: Node3D
|
||||||
|
|
||||||
var sun: DirectionalLight3D
|
var sun: DirectionalLight3D
|
||||||
var environment: WorldEnvironment
|
var environment: WorldEnvironment
|
||||||
@@ -33,12 +34,15 @@ var rain_tween: Tween
|
|||||||
var rain_audio_tween: Tween
|
var rain_audio_tween: Tween
|
||||||
var puddle_tween: Tween
|
var puddle_tween: Tween
|
||||||
var puddle_amount: float = 0.0
|
var puddle_amount: float = 0.0
|
||||||
|
var clouds_tween: Tween
|
||||||
|
|
||||||
var snow_tween: Tween
|
var snow_tween: Tween
|
||||||
|
var snow_weather_tween: Tween
|
||||||
var snow_particles_tween: Tween
|
var snow_particles_tween: Tween
|
||||||
var is_snowing: bool = false
|
var is_snowing: bool = false
|
||||||
var is_snow_accumulated: bool = false
|
var is_snow_accumulated: bool = false
|
||||||
var actual_snow_amount: float = 0.0
|
var actual_snow_amount: float = 0.0
|
||||||
|
var snow_weather_amount: float = 0.0
|
||||||
|
|
||||||
var is_storm: bool = false
|
var is_storm: bool = false
|
||||||
var cold_tween: Tween
|
var cold_tween: Tween
|
||||||
@@ -49,10 +53,13 @@ var current_wind_speed: float = 0.0
|
|||||||
var current_wind_strength: float = 0.0
|
var current_wind_strength: float = 0.0
|
||||||
var current_wind_fade: float = 0.0
|
var current_wind_fade: float = 0.0
|
||||||
var max_wind_amount: int = 0
|
var max_wind_amount: int = 0
|
||||||
|
var random_weather_restore_tween: Tween
|
||||||
|
var random_event_remaining: float = 0.0
|
||||||
|
var random_event_label_seconds: int = -1
|
||||||
|
|
||||||
func _init(wind: GPUParticles3D, snow: GPUParticles3D,
|
func _init(wind: GPUParticles3D, snow: GPUParticles3D,
|
||||||
fireflies: GPUParticles3D, rain: GPUParticles3D, ray: PackedScene,
|
fireflies: GPUParticles3D, rain: GPUParticles3D, ray: PackedScene,
|
||||||
dust: ColorRect, blurr: ColorRect, envshadows: MeshInstance3D,
|
dust: ColorRect, blurr: ColorRect, thefog: Node3D, envshadows: MeshInstance3D,
|
||||||
thesun: DirectionalLight3D, theenvironment: WorldEnvironment, environmentconfig: EnvironmentConfig,
|
thesun: DirectionalLight3D, theenvironment: WorldEnvironment, environmentconfig: EnvironmentConfig,
|
||||||
thecamera: Camera3D, thecamerapivot: Node3D, thundersounds: Array[AudioStream], rainsounds: Array[AudioStream]) -> void:
|
thecamera: Camera3D, thecamerapivot: Node3D, thundersounds: Array[AudioStream], rainsounds: Array[AudioStream]) -> void:
|
||||||
particles_wind = wind
|
particles_wind = wind
|
||||||
@@ -63,6 +70,7 @@ func _init(wind: GPUParticles3D, snow: GPUParticles3D,
|
|||||||
sun = thesun
|
sun = thesun
|
||||||
environment_dust = dust
|
environment_dust = dust
|
||||||
blur = blurr
|
blur = blurr
|
||||||
|
fog = thefog
|
||||||
environment_shadows = envshadows
|
environment_shadows = envshadows
|
||||||
environment = theenvironment
|
environment = theenvironment
|
||||||
environment_config = environmentconfig
|
environment_config = environmentconfig
|
||||||
@@ -86,6 +94,7 @@ func _init(wind: GPUParticles3D, snow: GPUParticles3D,
|
|||||||
|
|
||||||
toggle_dust(environment_config.enable_dust)
|
toggle_dust(environment_config.enable_dust)
|
||||||
toggle_blur(environment_config.enable_blur)
|
toggle_blur(environment_config.enable_blur)
|
||||||
|
toggle_fog(environment_config.enable_fog)
|
||||||
|
|
||||||
#set camera pivot if available
|
#set camera pivot if available
|
||||||
if camera_pivot:
|
if camera_pivot:
|
||||||
@@ -98,13 +107,17 @@ func _ready() -> void:
|
|||||||
UIEvents.toggle_snow.connect(toggle_snow)
|
UIEvents.toggle_snow.connect(toggle_snow)
|
||||||
UIEvents.toggle_wind.connect(toggle_wind)
|
UIEvents.toggle_wind.connect(toggle_wind)
|
||||||
UIEvents.wind_change.connect(change_wind_strength)
|
UIEvents.wind_change.connect(change_wind_strength)
|
||||||
|
UIEvents.trigger_random_weather.connect(trigger_random_weather_event)
|
||||||
UIEvents.toggle_fireflies.connect(toggle_fireflies)
|
UIEvents.toggle_fireflies.connect(toggle_fireflies)
|
||||||
UIEvents.toggle_storm.connect(toggle_storm)
|
UIEvents.toggle_storm.connect(toggle_storm)
|
||||||
UIEvents.toggle_dust.connect(toggle_dust)
|
UIEvents.toggle_dust.connect(toggle_dust)
|
||||||
UIEvents.toggle_blur.connect(toggle_blur)
|
UIEvents.toggle_blur.connect(toggle_blur)
|
||||||
|
UIEvents.toggle_fog.connect(toggle_fog)
|
||||||
UIEvents.toggle_shadows.connect(toggle_shadows)
|
UIEvents.toggle_shadows.connect(toggle_shadows)
|
||||||
|
_emit_weather_event_label()
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
|
_update_random_event_label(delta)
|
||||||
|
|
||||||
_follow_camera()
|
_follow_camera()
|
||||||
|
|
||||||
@@ -122,6 +135,7 @@ func _process(delta: float) -> void:
|
|||||||
var base_grad_top: Color
|
var base_grad_top: Color
|
||||||
var base_grad_bot: Color
|
var base_grad_bot: Color
|
||||||
var base_grad_intensity: float
|
var base_grad_intensity: float
|
||||||
|
var base_water_color: Color
|
||||||
var base_rotation_sun: Vector3
|
var base_rotation_sun: Vector3
|
||||||
|
|
||||||
if is_raining:
|
if is_raining:
|
||||||
@@ -149,6 +163,7 @@ func _process(delta: float) -> void:
|
|||||||
base_grad_top = environment_config.grad_top_morning.lerp(environment_config.grad_top_afternoon, t)
|
base_grad_top = environment_config.grad_top_morning.lerp(environment_config.grad_top_afternoon, t)
|
||||||
base_grad_bot = environment_config.grad_top_morning.lerp(environment_config.grad_bot_afternoon, t)
|
base_grad_bot = environment_config.grad_top_morning.lerp(environment_config.grad_bot_afternoon, t)
|
||||||
base_grad_intensity = lerp(environment_config.grad_intensity_morning, environment_config.grad_intensity_afternoon, t)
|
base_grad_intensity = lerp(environment_config.grad_intensity_morning, environment_config.grad_intensity_afternoon, t)
|
||||||
|
base_water_color = environment_config.water_color_morning.lerp(environment_config.water_color_afternoon, t)
|
||||||
base_rotation_sun = environment_config.sun_rotation_morning.lerp(environment_config.sun_rotation_afternoon, t)
|
base_rotation_sun = environment_config.sun_rotation_morning.lerp(environment_config.sun_rotation_afternoon, t)
|
||||||
else:
|
else:
|
||||||
var t = day_time - 2.0
|
var t = day_time - 2.0
|
||||||
@@ -162,6 +177,7 @@ func _process(delta: float) -> void:
|
|||||||
base_grad_top = environment_config.grad_top_afternoon.lerp(environment_config.grad_top_night, t)
|
base_grad_top = environment_config.grad_top_afternoon.lerp(environment_config.grad_top_night, t)
|
||||||
base_grad_bot = environment_config.grad_bot_afternoon.lerp(environment_config.grad_bot_night, t)
|
base_grad_bot = environment_config.grad_bot_afternoon.lerp(environment_config.grad_bot_night, t)
|
||||||
base_grad_intensity = lerp(environment_config.grad_intensity_afternoon, environment_config.grad_intensity_night, t)
|
base_grad_intensity = lerp(environment_config.grad_intensity_afternoon, environment_config.grad_intensity_night, t)
|
||||||
|
base_water_color = environment_config.water_color_afternoon.lerp(environment_config.water_color_night, t)
|
||||||
base_rotation_sun = environment_config.sun_rotation_afternoon.lerp(environment_config.sun_rotation_night, t)
|
base_rotation_sun = environment_config.sun_rotation_afternoon.lerp(environment_config.sun_rotation_night, t)
|
||||||
|
|
||||||
var weather_color = environment_config.rain_mode_color
|
var weather_color = environment_config.rain_mode_color
|
||||||
@@ -173,11 +189,12 @@ func _process(delta: float) -> void:
|
|||||||
var final_sky_horizon = base_sky_horizon.lerp(base_sky_horizon * weather_color, clamp(rain_intensity, 0.0, 1.0))
|
var final_sky_horizon = base_sky_horizon.lerp(base_sky_horizon * weather_color, clamp(rain_intensity, 0.0, 1.0))
|
||||||
var final_fog_color = base_fog_color.lerp(base_fog_color * weather_color, clamp(rain_intensity, 0.0, 1.0))
|
var final_fog_color = base_fog_color.lerp(base_fog_color * weather_color, clamp(rain_intensity, 0.0, 1.0))
|
||||||
var final_fog_density = lerp(base_fog_density, base_fog_density * 4.0, clamp(rain_intensity, 0.0, 1.0))
|
var final_fog_density = lerp(base_fog_density, base_fog_density * 4.0, clamp(rain_intensity, 0.0, 1.0))
|
||||||
|
var final_water_color = base_water_color.darkened(clamp(environment_config.water_darkening_rain, 0.0, 1.0) * clamp(rain_intensity, 0.0, 1.0))
|
||||||
|
|
||||||
final_tint = final_tint.lerp(final_tint * environment_config.snow_mode_color, actual_snow_amount)
|
final_tint = final_tint.lerp(final_tint * environment_config.snow_mode_color, snow_weather_amount)
|
||||||
final_sky_top = final_sky_top.lerp(final_sky_top * environment_config.snow_mode_color, actual_snow_amount)
|
final_sky_top = final_sky_top.lerp(final_sky_top * environment_config.snow_mode_color, snow_weather_amount)
|
||||||
final_sky_horizon = final_sky_horizon.lerp(final_sky_horizon * environment_config.snow_mode_color, actual_snow_amount)
|
final_sky_horizon = final_sky_horizon.lerp(final_sky_horizon * environment_config.snow_mode_color, snow_weather_amount)
|
||||||
final_fog_color = final_fog_color.lerp(final_fog_color * environment_config.snow_mode_color, actual_snow_amount)
|
final_fog_color = final_fog_color.lerp(final_fog_color * environment_config.snow_mode_color, snow_weather_amount)
|
||||||
|
|
||||||
#Shader parameters for global trunk_shader
|
#Shader parameters for global trunk_shader
|
||||||
var final_grad_top = base_grad_top.lerp(base_grad_top * weather_color, clamp(rain_intensity, 0.0, 1.0))
|
var final_grad_top = base_grad_top.lerp(base_grad_top * weather_color, clamp(rain_intensity, 0.0, 1.0))
|
||||||
@@ -186,12 +203,13 @@ func _process(delta: float) -> void:
|
|||||||
RenderingServer.global_shader_parameter_set("global_gradient_color_top", final_grad_top)
|
RenderingServer.global_shader_parameter_set("global_gradient_color_top", final_grad_top)
|
||||||
RenderingServer.global_shader_parameter_set("global_gradient_color_bot", final_grad_bot)
|
RenderingServer.global_shader_parameter_set("global_gradient_color_bot", final_grad_bot)
|
||||||
RenderingServer.global_shader_parameter_set("global_gradient_intensity", base_grad_intensity)
|
RenderingServer.global_shader_parameter_set("global_gradient_intensity", base_grad_intensity)
|
||||||
|
RenderingServer.global_shader_parameter_set("global_water_color", final_water_color)
|
||||||
|
|
||||||
var night_val = clamp(day_time - 2.0, 0.0, 1.0)
|
var night_val = clamp(day_time - 2.0, 0.0, 1.0)
|
||||||
|
|
||||||
#Snow exposure compensation
|
#Snow exposure compensation
|
||||||
var snow_light_attenuation = lerp(1.0, 0.55, actual_snow_amount * (1.0 - night_val))
|
var snow_light_attenuation = lerp(1.0, 0.55, snow_weather_amount * (1.0 - night_val))
|
||||||
var snow_glow_attenuation = lerp(1.0, 0.5, actual_snow_amount)
|
var snow_glow_attenuation = lerp(1.0, 0.5, snow_weather_amount)
|
||||||
var final_bloom = lerp(base_bloom, base_bloom * 0.5, rain_intensity) * snow_glow_attenuation
|
var final_bloom = lerp(base_bloom, base_bloom * 0.5, rain_intensity) * snow_glow_attenuation
|
||||||
|
|
||||||
# We calculate the final exposure by applying snow damping directly to the camera exposure
|
# We calculate the final exposure by applying snow damping directly to the camera exposure
|
||||||
@@ -232,16 +250,37 @@ func _process(delta: float) -> void:
|
|||||||
sky_mat.set_shader_parameter("sun_color", final_tint)
|
sky_mat.set_shader_parameter("sun_color", final_tint)
|
||||||
sky_mat.set_shader_parameter("night_intensity", night_val)
|
sky_mat.set_shader_parameter("night_intensity", night_val)
|
||||||
|
|
||||||
|
var cloud_density_amount: float = maxf(clamp(rain_intensity, 0.0, 1.0), clamp(snow_weather_amount, 0.0, 1.0))
|
||||||
|
var current_cloud_density: float = lerp(environment_config.base_cloud_density, environment_config.rain_cloud_density, cloud_density_amount)
|
||||||
|
|
||||||
if environment_config.material_clouds:
|
if environment_config.material_clouds:
|
||||||
var current_density = lerp(0.4, 1.0, rain_intensity)
|
environment_config.material_clouds.set_shader_parameter("cloud_density", current_cloud_density)
|
||||||
environment_config.material_clouds.set_shader_parameter("cloud_density", current_density)
|
var current_sharpness = lerp(0.14, 0.0, cloud_density_amount)
|
||||||
var current_sharpness = lerp(0.14, 0.0, rain_intensity)
|
|
||||||
environment_config.material_clouds.set_shader_parameter("center_sharpness", current_sharpness)
|
environment_config.material_clouds.set_shader_parameter("center_sharpness", current_sharpness)
|
||||||
|
|
||||||
|
var env_shadow_mat = environment_shadows.get_surface_override_material(0) if environment_shadows else null
|
||||||
|
if env_shadow_mat:
|
||||||
|
env_shadow_mat.set_shader_parameter("cloud_density", current_cloud_density)
|
||||||
|
|
||||||
if environment_config.material_fog:
|
if environment_config.material_fog:
|
||||||
|
environment_config.material_fog.set_shader_parameter("fog_color", final_fog_color)
|
||||||
|
environment_config.material_fog.set_shader_parameter("fog_density", clamp(final_fog_density * 25.0, 0.0, 1.0))
|
||||||
environment_config.material_fog.set_shader_parameter("night_intensity", night_val)
|
environment_config.material_fog.set_shader_parameter("night_intensity", night_val)
|
||||||
environment_config.material_fog.set_shader_parameter("sun_color", final_tint)
|
environment_config.material_fog.set_shader_parameter("sun_color", final_tint)
|
||||||
|
|
||||||
|
if fog:
|
||||||
|
for child in fog.get_children():
|
||||||
|
var fog_mesh := child as MeshInstance3D
|
||||||
|
if fog_mesh == null:
|
||||||
|
continue
|
||||||
|
var fog_material := fog_mesh.get_surface_override_material(0) as ShaderMaterial
|
||||||
|
if fog_material == null:
|
||||||
|
continue
|
||||||
|
fog_material.set_shader_parameter("fog_color", final_fog_color)
|
||||||
|
fog_material.set_shader_parameter("fog_density", clamp(final_fog_density * 25.0, 0.0, 1.0))
|
||||||
|
fog_material.set_shader_parameter("night_intensity", night_val)
|
||||||
|
fog_material.set_shader_parameter("sun_color", final_tint)
|
||||||
|
|
||||||
func create_sound_players():
|
func create_sound_players():
|
||||||
rain_audio_player = AudioStreamPlayer.new()
|
rain_audio_player = AudioStreamPlayer.new()
|
||||||
rain_audio_player.name = "RainAudioPlayer"
|
rain_audio_player.name = "RainAudioPlayer"
|
||||||
@@ -265,6 +304,23 @@ func _get_weather_anchor_position() -> Variant:
|
|||||||
return camera.global_position
|
return camera.global_position
|
||||||
return null
|
return null
|
||||||
|
|
||||||
|
func _get_weather_anchor_basis() -> Variant:
|
||||||
|
var source_basis: Basis
|
||||||
|
if camera_pivot and is_instance_valid(camera_pivot):
|
||||||
|
source_basis = camera_pivot.global_basis
|
||||||
|
elif camera and is_instance_valid(camera):
|
||||||
|
source_basis = camera.global_basis
|
||||||
|
else:
|
||||||
|
return null
|
||||||
|
|
||||||
|
var forward := -source_basis.z
|
||||||
|
forward.y = 0.0
|
||||||
|
if forward.length_squared() <= 0.0001:
|
||||||
|
return Basis.IDENTITY
|
||||||
|
forward = forward.normalized()
|
||||||
|
var right := forward.cross(Vector3.UP).normalized()
|
||||||
|
return Basis(right, Vector3.UP, -forward)
|
||||||
|
|
||||||
func _follow_camera() -> void:
|
func _follow_camera() -> void:
|
||||||
var cam_pos = _get_weather_anchor_position()
|
var cam_pos = _get_weather_anchor_position()
|
||||||
if cam_pos == null:
|
if cam_pos == null:
|
||||||
@@ -277,6 +333,12 @@ func _follow_camera() -> void:
|
|||||||
particles_wind.global_position = Vector3(cam_pos.x, cam_pos.y, cam_pos.z)
|
particles_wind.global_position = Vector3(cam_pos.x, cam_pos.y, cam_pos.z)
|
||||||
if particles_fireflies:
|
if particles_fireflies:
|
||||||
particles_fireflies.global_position = Vector3(cam_pos.x, particles_fireflies.position.y, cam_pos.z)
|
particles_fireflies.global_position = Vector3(cam_pos.x, particles_fireflies.position.y, cam_pos.z)
|
||||||
|
if fog:
|
||||||
|
fog.global_position = Vector3(cam_pos.x, fog.global_position.y, cam_pos.z)
|
||||||
|
#used to follow camera pivot or camera
|
||||||
|
var anchor_basis = _get_weather_anchor_basis()
|
||||||
|
if anchor_basis != null:
|
||||||
|
fog.global_basis = anchor_basis
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Fireflies
|
#region Fireflies
|
||||||
@@ -307,6 +369,7 @@ func toggle_wind(value: bool):
|
|||||||
particles_wind.emitting = is_windy
|
particles_wind.emitting = is_windy
|
||||||
|
|
||||||
_apply_wind_state()
|
_apply_wind_state()
|
||||||
|
_emit_weather_event_label()
|
||||||
|
|
||||||
#disable wind and set default values and materials
|
#disable wind and set default values and materials
|
||||||
func init_wind():
|
func init_wind():
|
||||||
@@ -410,6 +473,67 @@ func _update_wind_amount_from_strength(value: float) -> void:
|
|||||||
|
|
||||||
environment_config.wind_amount = roundi(max_wind_amount * amount_ratio)
|
environment_config.wind_amount = roundi(max_wind_amount * amount_ratio)
|
||||||
|
|
||||||
|
func trigger_random_weather_event(duration: float = 0.0) -> void:
|
||||||
|
if random_weather_restore_tween and random_weather_restore_tween.is_valid():
|
||||||
|
random_weather_restore_tween.kill()
|
||||||
|
random_event_remaining = 0.0
|
||||||
|
random_event_label_seconds = -1
|
||||||
|
|
||||||
|
var previous_rain: bool = is_raining
|
||||||
|
var previous_snow: bool = is_snowing
|
||||||
|
var previous_wind: bool = is_windy
|
||||||
|
var previous_storm: bool = is_storm
|
||||||
|
var random_event_index: int = randi_range(0, 3)
|
||||||
|
match random_event_index:
|
||||||
|
0:
|
||||||
|
_apply_weather_event_state(false, true, false, false)
|
||||||
|
1:
|
||||||
|
_apply_weather_event_state(true, false, false, false)
|
||||||
|
2:
|
||||||
|
_apply_weather_event_state(false, false, true, false)
|
||||||
|
_:
|
||||||
|
_apply_weather_event_state(true, false, false, true)
|
||||||
|
|
||||||
|
if duration > 0.0:
|
||||||
|
random_event_remaining = duration
|
||||||
|
_emit_weather_event_label()
|
||||||
|
random_weather_restore_tween = create_tween()
|
||||||
|
random_weather_restore_tween.tween_interval(duration)
|
||||||
|
random_weather_restore_tween.tween_callback(func():
|
||||||
|
random_event_remaining = 0.0
|
||||||
|
random_event_label_seconds = -1
|
||||||
|
_apply_weather_event_state(previous_rain, previous_snow, previous_wind, previous_storm)
|
||||||
|
)
|
||||||
|
|
||||||
|
func _update_random_event_label(delta: float) -> void:
|
||||||
|
if random_event_remaining <= 0.0:
|
||||||
|
return
|
||||||
|
|
||||||
|
random_event_remaining = maxf(random_event_remaining - delta, 0.0)
|
||||||
|
var display_seconds: int = ceili(random_event_remaining)
|
||||||
|
if display_seconds != random_event_label_seconds:
|
||||||
|
random_event_label_seconds = display_seconds
|
||||||
|
_emit_weather_event_label()
|
||||||
|
|
||||||
|
func _apply_weather_event_state(rain_enabled: bool, snow_enabled: bool, wind_enabled: bool, storm_enabled: bool = false) -> void:
|
||||||
|
if is_storm and not storm_enabled:
|
||||||
|
toggle_storm(false)
|
||||||
|
if is_raining and not rain_enabled:
|
||||||
|
toggle_rain(false)
|
||||||
|
if is_snowing and not snow_enabled:
|
||||||
|
toggle_snow(false)
|
||||||
|
if is_windy and not wind_enabled:
|
||||||
|
toggle_wind(false)
|
||||||
|
|
||||||
|
if not is_raining and rain_enabled:
|
||||||
|
toggle_rain(true)
|
||||||
|
if not is_snowing and snow_enabled:
|
||||||
|
toggle_snow(true)
|
||||||
|
if not is_windy and wind_enabled:
|
||||||
|
toggle_wind(true)
|
||||||
|
if not is_storm and storm_enabled:
|
||||||
|
toggle_storm(true)
|
||||||
|
|
||||||
func _apply_cloud_config() -> void:
|
func _apply_cloud_config() -> void:
|
||||||
var dir = environment_config.wind_direction
|
var dir = environment_config.wind_direction
|
||||||
var cloud_scale = environment_config.cloud_scale
|
var cloud_scale = environment_config.cloud_scale
|
||||||
@@ -441,6 +565,7 @@ func _apply_cloud_config() -> void:
|
|||||||
|
|
||||||
func toggle_storm(value: bool):
|
func toggle_storm(value: bool):
|
||||||
is_storm = value
|
is_storm = value
|
||||||
|
_emit_weather_event_label()
|
||||||
|
|
||||||
#set lightning
|
#set lightning
|
||||||
func init_lightning():
|
func init_lightning():
|
||||||
@@ -554,6 +679,7 @@ func toggle_rain(value: bool):
|
|||||||
is_raining = value
|
is_raining = value
|
||||||
|
|
||||||
if not particles_rain:
|
if not particles_rain:
|
||||||
|
_emit_weather_event_label()
|
||||||
return
|
return
|
||||||
|
|
||||||
if is_raining and is_snowing:
|
if is_raining and is_snowing:
|
||||||
@@ -587,6 +713,7 @@ func toggle_rain(value: bool):
|
|||||||
trigger_after_rain())
|
trigger_after_rain())
|
||||||
puddle_tween = create_tween()
|
puddle_tween = create_tween()
|
||||||
puddle_tween.tween_method(set_puddle_amount, puddle_amount, 0.0, environment_config.puddle_dry_time)
|
puddle_tween.tween_method(set_puddle_amount, puddle_amount, 0.0, environment_config.puddle_dry_time)
|
||||||
|
_emit_weather_event_label()
|
||||||
|
|
||||||
func trigger_morning() -> void:
|
func trigger_morning() -> void:
|
||||||
spawn_single_godray()
|
spawn_single_godray()
|
||||||
@@ -683,12 +810,47 @@ func toggle_snow(value: bool):
|
|||||||
var target_snow_amount: float = 1.0 if is_snowing else 0.0
|
var target_snow_amount: float = 1.0 if is_snowing else 0.0
|
||||||
if snow_tween and snow_tween.is_valid():
|
if snow_tween and snow_tween.is_valid():
|
||||||
snow_tween.kill()
|
snow_tween.kill()
|
||||||
|
if snow_weather_tween and snow_weather_tween.is_valid():
|
||||||
|
snow_weather_tween.kill()
|
||||||
|
var snow_amount_transition_duration: float = _get_snow_amount_transition_duration(is_snowing)
|
||||||
snow_tween = create_tween()
|
snow_tween = create_tween()
|
||||||
snow_tween.tween_method(init_snow_amount, actual_snow_amount, target_snow_amount, environment_config.snow_transaction_time)
|
snow_tween.tween_method(
|
||||||
|
init_snow_amount,
|
||||||
|
actual_snow_amount,
|
||||||
|
target_snow_amount,
|
||||||
|
snow_amount_transition_duration
|
||||||
|
)
|
||||||
|
snow_weather_tween = create_tween()
|
||||||
|
snow_weather_tween.tween_method(
|
||||||
|
init_snow_weather_amount,
|
||||||
|
snow_weather_amount,
|
||||||
|
target_snow_amount,
|
||||||
|
environment_config.snow_fade_time
|
||||||
|
)
|
||||||
|
_emit_weather_event_label()
|
||||||
|
|
||||||
|
func _emit_weather_event_label() -> void:
|
||||||
|
var weather_label := "Weather: Clear"
|
||||||
|
if is_storm:
|
||||||
|
weather_label = "Weather: Storm"
|
||||||
|
else:
|
||||||
|
var active_events: Array[String] = []
|
||||||
|
if is_snowing:
|
||||||
|
active_events.append("Snow")
|
||||||
|
if is_raining:
|
||||||
|
active_events.append("Rain")
|
||||||
|
if is_windy:
|
||||||
|
active_events.append("Wind")
|
||||||
|
if not active_events.is_empty():
|
||||||
|
weather_label = "Weather: %s" % " + ".join(active_events)
|
||||||
|
if random_event_remaining > 0.0:
|
||||||
|
weather_label += " (%s'')" % ceili(random_event_remaining)
|
||||||
|
UIEvents.weather_event_changed.emit(weather_label)
|
||||||
|
|
||||||
#disable snow and set default values and shader
|
#disable snow and set default values and shader
|
||||||
func init_snow(value: float = 0.0):
|
func init_snow(value: float = 0.0):
|
||||||
actual_snow_amount = value
|
actual_snow_amount = value
|
||||||
|
snow_weather_amount = value
|
||||||
RenderingServer.global_shader_parameter_set("global_snow_amount", value)
|
RenderingServer.global_shader_parameter_set("global_snow_amount", value)
|
||||||
|
|
||||||
if particles_snow:
|
if particles_snow:
|
||||||
@@ -699,6 +861,13 @@ func init_snow(value: float = 0.0):
|
|||||||
RenderingServer.global_shader_parameter_set("global_snow_color", environment_config.snow_color)
|
RenderingServer.global_shader_parameter_set("global_snow_color", environment_config.snow_color)
|
||||||
RenderingServer.global_shader_parameter_set("global_snow_accumulation_speed", environment_config.snow_accumulation_speed)
|
RenderingServer.global_shader_parameter_set("global_snow_accumulation_speed", environment_config.snow_accumulation_speed)
|
||||||
RenderingServer.global_shader_parameter_set("global_snow_melt_speed", environment_config.snow_melt_speed)
|
RenderingServer.global_shader_parameter_set("global_snow_melt_speed", environment_config.snow_melt_speed)
|
||||||
|
RenderingServer.global_shader_parameter_set("global_snow_max_accumulation", environment_config.snow_max_accumulation)
|
||||||
|
RenderingServer.global_shader_parameter_set("global_snow_cap_enabled", environment_config.show_snow_accumulation_volume)
|
||||||
|
RenderingServer.global_shader_parameter_set("global_snow_cap_height", environment_config.snow_cap_height)
|
||||||
|
RenderingServer.global_shader_parameter_set("global_snow_cap_flatness_start", environment_config.snow_cap_flatness_start)
|
||||||
|
RenderingServer.global_shader_parameter_set("global_snow_cap_flatness_end", environment_config.snow_cap_flatness_end)
|
||||||
|
RenderingServer.global_shader_parameter_set("global_snow_cap_noise_scale", environment_config.snow_cap_noise_scale)
|
||||||
|
RenderingServer.global_shader_parameter_set("global_snow_cap_noise_strength", environment_config.snow_cap_noise_strength)
|
||||||
RenderingServer.global_shader_parameter_set("global_snow_start_time", -1.0)
|
RenderingServer.global_shader_parameter_set("global_snow_start_time", -1.0)
|
||||||
RenderingServer.global_shader_parameter_set("global_snow_melt_time", -1.0)
|
RenderingServer.global_shader_parameter_set("global_snow_melt_time", -1.0)
|
||||||
|
|
||||||
@@ -706,6 +875,9 @@ func init_snow_amount(value: float):
|
|||||||
actual_snow_amount = value
|
actual_snow_amount = value
|
||||||
RenderingServer.global_shader_parameter_set("global_snow_amount", value)
|
RenderingServer.global_shader_parameter_set("global_snow_amount", value)
|
||||||
|
|
||||||
|
func init_snow_weather_amount(value: float):
|
||||||
|
snow_weather_amount = value
|
||||||
|
|
||||||
func start_snow_accumulation() -> void:
|
func start_snow_accumulation() -> void:
|
||||||
RenderingServer.global_shader_parameter_set("global_snow_melt_time", -1.0)
|
RenderingServer.global_shader_parameter_set("global_snow_melt_time", -1.0)
|
||||||
RenderingServer.global_shader_parameter_set("global_snow_start_time", Time.get_ticks_msec() / 1000.0)
|
RenderingServer.global_shader_parameter_set("global_snow_start_time", Time.get_ticks_msec() / 1000.0)
|
||||||
@@ -714,6 +886,18 @@ func start_snow_melt() -> void:
|
|||||||
RenderingServer.global_shader_parameter_set("global_snow_melt_time", Time.get_ticks_msec() / 1000.0)
|
RenderingServer.global_shader_parameter_set("global_snow_melt_time", Time.get_ticks_msec() / 1000.0)
|
||||||
RenderingServer.global_shader_parameter_set("global_snow_melt_speed", environment_config.snow_melt_speed)
|
RenderingServer.global_shader_parameter_set("global_snow_melt_speed", environment_config.snow_melt_speed)
|
||||||
|
|
||||||
|
func _get_snow_amount_transition_duration(is_accumulating: bool) -> float:
|
||||||
|
if environment_config == null:
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
var speed: float = environment_config.snow_melt_speed
|
||||||
|
if is_accumulating:
|
||||||
|
speed = environment_config.snow_accumulation_speed
|
||||||
|
if speed <= 0.0:
|
||||||
|
return environment_config.snow_transaction_time
|
||||||
|
|
||||||
|
return 1.0 / speed
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Post-Process
|
#region Post-Process
|
||||||
@@ -728,6 +912,10 @@ func toggle_blur(value: bool) -> void:
|
|||||||
|
|
||||||
ApplyPostProcessBlurConfig()
|
ApplyPostProcessBlurConfig()
|
||||||
|
|
||||||
|
func toggle_fog(value: bool) -> void:
|
||||||
|
if fog:
|
||||||
|
fog.visible = value
|
||||||
|
|
||||||
func toggle_shadows(value: bool) -> void:
|
func toggle_shadows(value: bool) -> void:
|
||||||
if environment_shadows:
|
if environment_shadows:
|
||||||
environment_shadows.visible = value
|
environment_shadows.visible = value
|
||||||
|
|||||||
@@ -3,11 +3,19 @@ render_mode blend_mix, depth_draw_never;
|
|||||||
|
|
||||||
//Snow globals
|
//Snow globals
|
||||||
global uniform float global_snow_start_time = -1.0;
|
global uniform float global_snow_start_time = -1.0;
|
||||||
global uniform float global_snow_accumulation_speed = 0.1;
|
global uniform float global_snow_accumulation_speed = 0.005;
|
||||||
global uniform float global_snow_melt_time = -1.0;
|
global uniform float global_snow_melt_time = -1.0;
|
||||||
global uniform float global_snow_melt_speed = 0.1;
|
global uniform float global_snow_melt_speed = 0.1;
|
||||||
|
global uniform float global_snow_amount = 0.0;
|
||||||
global uniform float global_snow_threshold = 0.5;
|
global uniform float global_snow_threshold = 0.5;
|
||||||
global uniform vec4 global_snow_color = vec4(0.92, 0.96, 1.0, 1.0);
|
global uniform vec4 global_snow_color = vec4(0.92, 0.96, 1.0, 1.0);
|
||||||
|
global uniform float global_snow_max_accumulation = 0.72;
|
||||||
|
global uniform bool global_snow_cap_enabled = true;
|
||||||
|
global uniform float global_snow_cap_height = 0.06;
|
||||||
|
global uniform float global_snow_cap_flatness_start = 0.72;
|
||||||
|
global uniform float global_snow_cap_flatness_end = 0.96;
|
||||||
|
global uniform float global_snow_cap_noise_scale = 0.22;
|
||||||
|
global uniform float global_snow_cap_noise_strength = 0.18;
|
||||||
uniform float snow_noise_scale : hint_range(0.01, 1.0) = 0.15;
|
uniform float snow_noise_scale : hint_range(0.01, 1.0) = 0.15;
|
||||||
uniform float snow_edge_softness : hint_range(0.01, 0.5) = 0.2;
|
uniform float snow_edge_softness : hint_range(0.01, 0.5) = 0.2;
|
||||||
uniform float snow_roughness_variation : hint_range(0.0, 0.3) = 0.15;
|
uniform float snow_roughness_variation : hint_range(0.0, 0.3) = 0.15;
|
||||||
@@ -29,6 +37,55 @@ uniform float puddle_threshold : hint_range(0.0, 0.8) = 0.45;
|
|||||||
|
|
||||||
uniform sampler2D noise_texture : filter_linear_mipmap, repeat_enable;
|
uniform sampler2D noise_texture : filter_linear_mipmap, repeat_enable;
|
||||||
|
|
||||||
|
varying float v_snow_amount;
|
||||||
|
varying float v_snow_cap_mask;
|
||||||
|
|
||||||
|
float hash(vec2 p) {
|
||||||
|
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
|
||||||
|
}
|
||||||
|
|
||||||
|
float value_noise(vec2 p) {
|
||||||
|
vec2 i = floor(p);
|
||||||
|
vec2 f = fract(p);
|
||||||
|
vec2 u = f * f * (3.0 - 2.0 * f);
|
||||||
|
|
||||||
|
float a = hash(i);
|
||||||
|
float b = hash(i + vec2(1.0, 0.0));
|
||||||
|
float c = hash(i + vec2(0.0, 1.0));
|
||||||
|
float d = hash(i + vec2(1.0, 1.0));
|
||||||
|
|
||||||
|
return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
float fbm(vec2 p) {
|
||||||
|
float value = 0.0;
|
||||||
|
float amplitude = 0.5;
|
||||||
|
float frequency = 1.0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
value += value_noise(p * frequency) * amplitude;
|
||||||
|
frequency *= 2.0;
|
||||||
|
amplitude *= 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
return clamp(value, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float get_snow_progress() {
|
||||||
|
float snow_progress = clamp(global_snow_amount, 0.0, 1.0);
|
||||||
|
|
||||||
|
if (global_snow_start_time >= 0.0) {
|
||||||
|
float timed_progress = clamp((TIME - global_snow_start_time) * global_snow_accumulation_speed, 0.0, 1.0);
|
||||||
|
snow_progress = max(snow_progress, timed_progress);
|
||||||
|
}
|
||||||
|
if (global_snow_melt_time >= 0.0) {
|
||||||
|
float melt = clamp((TIME - global_snow_melt_time) * global_snow_melt_speed, 0.0, 1.0);
|
||||||
|
snow_progress = min(snow_progress, 1.0 - melt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return snow_progress;
|
||||||
|
}
|
||||||
|
|
||||||
float ripple_ring(vec2 uv, float time_offset) {
|
float ripple_ring(vec2 uv, float time_offset) {
|
||||||
float d = length(uv);
|
float d = length(uv);
|
||||||
float ring = sin(d * 30.0 - TIME * ripple_speed + time_offset) * 0.5 + 0.5;
|
float ring = sin(d * 30.0 - TIME * ripple_speed + time_offset) * 0.5 + 0.5;
|
||||||
@@ -36,6 +93,27 @@ float ripple_ring(vec2 uv, float time_offset) {
|
|||||||
return ring * fade;
|
return ring * fade;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vertex() {
|
||||||
|
float snow_progress = get_snow_progress();
|
||||||
|
float snow_accumulation = snow_progress * global_snow_max_accumulation;
|
||||||
|
vec3 world_pos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
|
||||||
|
vec3 world_normal = normalize((MODEL_MATRIX * vec4(NORMAL, 0.0)).xyz);
|
||||||
|
|
||||||
|
float flat_surface = smoothstep(
|
||||||
|
max(global_snow_threshold, global_snow_cap_flatness_start),
|
||||||
|
global_snow_cap_flatness_end,
|
||||||
|
world_normal.y
|
||||||
|
);
|
||||||
|
float accumulation_growth = smoothstep(0.08, 0.65, snow_progress);
|
||||||
|
float cap_noise = fbm(world_pos.xz * global_snow_cap_noise_scale + vec2(11.3, 4.7));
|
||||||
|
float cap_variation = mix(1.0 - global_snow_cap_noise_strength, 1.0 + global_snow_cap_noise_strength, cap_noise);
|
||||||
|
|
||||||
|
v_snow_amount = snow_progress;
|
||||||
|
v_snow_cap_mask = flat_surface * accumulation_growth * cap_variation * (global_snow_cap_enabled ? 1.0 : 0.0);
|
||||||
|
|
||||||
|
VERTEX += NORMAL * (global_snow_cap_height * snow_accumulation * v_snow_cap_mask);
|
||||||
|
}
|
||||||
|
|
||||||
void fragment() {
|
void fragment() {
|
||||||
vec3 world_pos = (INV_VIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
|
vec3 world_pos = (INV_VIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
|
||||||
vec3 world_normal = normalize((INV_VIEW_MATRIX * vec4(NORMAL, 0.0)).xyz);
|
vec3 world_normal = normalize((INV_VIEW_MATRIX * vec4(NORMAL, 0.0)).xyz);
|
||||||
@@ -43,25 +121,24 @@ void fragment() {
|
|||||||
float noise_val = texture(noise_texture, world_pos.xz * snow_noise_scale).r;
|
float noise_val = texture(noise_texture, world_pos.xz * snow_noise_scale).r;
|
||||||
|
|
||||||
//Snow
|
//Snow
|
||||||
float snow_amount = 0.0;
|
float snow_progress = v_snow_amount;
|
||||||
if (global_snow_start_time >= 0.0) {
|
float snow_accumulation = snow_progress * global_snow_max_accumulation;
|
||||||
snow_amount = clamp((TIME - global_snow_start_time) * global_snow_accumulation_speed, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
if (global_snow_melt_time >= 0.0) {
|
|
||||||
float melt = clamp((TIME - global_snow_melt_time) * global_snow_melt_speed, 0.0, 1.0);
|
|
||||||
snow_amount *= (1.0 - melt);
|
|
||||||
}
|
|
||||||
|
|
||||||
float snow_edge = smoothstep(
|
float snow_edge = smoothstep(
|
||||||
global_snow_threshold - snow_edge_softness,
|
global_snow_threshold - snow_edge_softness,
|
||||||
global_snow_threshold + snow_edge_softness,
|
global_snow_threshold + snow_edge_softness,
|
||||||
facing_up + (noise_val - 0.5) * 0.4
|
facing_up
|
||||||
);
|
);
|
||||||
float snow_coverage = smoothstep(0.0, 0.6, noise_val + snow_amount - 0.4);
|
float flat_accumulation = smoothstep(0.0, 0.35, v_snow_cap_mask) * snow_accumulation;
|
||||||
float snow_factor = snow_edge * snow_coverage * snow_amount;
|
float snow_variation = mix(0.75, 1.15, noise_val);
|
||||||
|
float snow_coverage = clamp(snow_progress * snow_variation + flat_accumulation * 0.25, 0.0, 1.0);
|
||||||
|
float snow_factor = max(snow_edge * snow_coverage, flat_accumulation);
|
||||||
|
float snow_opacity = clamp(snow_factor, 0.0, 1.0);
|
||||||
|
snow_opacity = max(snow_opacity, flat_accumulation * 0.9);
|
||||||
|
|
||||||
float shade = mix(-snow_color_variation, snow_color_variation, noise_val);
|
float shade = mix(-snow_color_variation, snow_color_variation, noise_val);
|
||||||
vec3 snow_albedo = clamp(global_snow_color.rgb + vec3(shade), 0.0, 1.0);
|
vec3 snow_albedo = clamp(global_snow_color.rgb + vec3(shade), 0.0, 1.0);
|
||||||
|
snow_albedo = mix(snow_albedo, vec3(1.0), 0.18 + snow_opacity * 0.12);
|
||||||
float snow_rough = mix(0.15 - snow_roughness_variation, 0.15 + snow_roughness_variation, noise_val);
|
float snow_rough = mix(0.15 - snow_roughness_variation, 0.15 + snow_roughness_variation, noise_val);
|
||||||
|
|
||||||
//Rain
|
//Rain
|
||||||
@@ -173,7 +250,7 @@ void fragment() {
|
|||||||
ALBEDO = snow_albedo;
|
ALBEDO = snow_albedo;
|
||||||
ROUGHNESS = snow_rough;
|
ROUGHNESS = snow_rough;
|
||||||
METALLIC = 0.0;
|
METALLIC = 0.0;
|
||||||
ALPHA = snow_factor;
|
ALPHA = snow_opacity;
|
||||||
} else {
|
} else {
|
||||||
ALBEDO = rain_albedo;
|
ALBEDO = rain_albedo;
|
||||||
ROUGHNESS = rain_rough;
|
ROUGHNESS = rain_rough;
|
||||||
|
|||||||
@@ -5,3 +5,17 @@
|
|||||||
[resource]
|
[resource]
|
||||||
render_priority = 0
|
render_priority = 0
|
||||||
shader = ExtResource("1_weather")
|
shader = ExtResource("1_weather")
|
||||||
|
shader_parameter/snow_noise_scale = 0.15
|
||||||
|
shader_parameter/snow_edge_softness = 0.2
|
||||||
|
shader_parameter/snow_roughness_variation = 0.15
|
||||||
|
shader_parameter/snow_color_variation = 0.05
|
||||||
|
shader_parameter/ripple_scale = 1.5
|
||||||
|
shader_parameter/ripple_speed = 2.0
|
||||||
|
shader_parameter/ripple_layers = 3.0
|
||||||
|
shader_parameter/streak_scale = 2.0
|
||||||
|
shader_parameter/streak_speed = 0.8
|
||||||
|
shader_parameter/wetness_darkening = 0.25
|
||||||
|
shader_parameter/wet_roughness = 0.05
|
||||||
|
shader_parameter/rain_normal_strength = 0.4
|
||||||
|
shader_parameter/puddle_noise_scale = 0.08
|
||||||
|
shader_parameter/puddle_threshold = 0.45
|
||||||
|
|||||||
@@ -2,21 +2,19 @@ shader_type spatial;
|
|||||||
render_mode blend_mix, depth_draw_never, cull_disabled;
|
render_mode blend_mix, depth_draw_never, cull_disabled;
|
||||||
|
|
||||||
// Snow globals
|
// Snow globals
|
||||||
global uniform float global_snow_start_time;
|
global uniform float global_snow_start_time = -1.0;
|
||||||
global uniform float global_snow_accumulation_speed;
|
global uniform float global_snow_accumulation_speed = 0.005;
|
||||||
global uniform float global_snow_melt_time;
|
global uniform float global_snow_melt_time = -1.0;
|
||||||
global uniform float global_snow_melt_speed;
|
global uniform float global_snow_melt_speed = 0.1;
|
||||||
|
global uniform float global_snow_amount = 0.0;
|
||||||
global uniform vec4 global_snow_color;
|
global uniform vec4 global_snow_color;
|
||||||
|
|
||||||
// Rain globals
|
|
||||||
global uniform float global_rain_intensity;
|
|
||||||
global uniform float global_rain_puddle_amount;
|
|
||||||
|
|
||||||
// Snow parameters
|
|
||||||
uniform float snow_edge_softness : hint_range(0.01, 0.5) = 0.15;
|
uniform float snow_edge_softness : hint_range(0.01, 0.5) = 0.15;
|
||||||
uniform float snow_color_variation : hint_range(0.0, 0.15) = 0.05;
|
uniform float snow_color_variation : hint_range(0.0, 0.15) = 0.05;
|
||||||
|
|
||||||
|
|
||||||
// Rain wetness parameters
|
// Rain wetness parameters
|
||||||
|
global uniform float global_rain_intensity;
|
||||||
|
global uniform float global_rain_puddle_amount;
|
||||||
uniform float ripple_scale : hint_range(0.1, 5.0) = 1.5;
|
uniform float ripple_scale : hint_range(0.1, 5.0) = 1.5;
|
||||||
uniform float ripple_speed : hint_range(0.5, 5.0) = 2.0;
|
uniform float ripple_speed : hint_range(0.5, 5.0) = 2.0;
|
||||||
uniform float ripple_layers : hint_range(1.0, 4.0) = 3.0;
|
uniform float ripple_layers : hint_range(1.0, 4.0) = 3.0;
|
||||||
@@ -37,6 +35,21 @@ float ripple_ring(vec2 uv, float time_offset) {
|
|||||||
return ring * fade;
|
return ring * fade;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float get_snow_progress() {
|
||||||
|
float snow_progress = clamp(global_snow_amount, 0.0, 1.0);
|
||||||
|
|
||||||
|
if (global_snow_start_time >= 0.0) {
|
||||||
|
float timed_progress = clamp((TIME - global_snow_start_time) * global_snow_accumulation_speed, 0.0, 1.0);
|
||||||
|
snow_progress = max(snow_progress, timed_progress);
|
||||||
|
}
|
||||||
|
if (global_snow_melt_time >= 0.0) {
|
||||||
|
float melt = clamp((TIME - global_snow_melt_time) * global_snow_melt_speed, 0.0, 1.0);
|
||||||
|
snow_progress = min(snow_progress, 1.0 - melt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return snow_progress;
|
||||||
|
}
|
||||||
|
|
||||||
void fragment() {
|
void fragment() {
|
||||||
vec3 world_pos = (INV_VIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
|
vec3 world_pos = (INV_VIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
|
||||||
|
|
||||||
@@ -44,18 +57,10 @@ void fragment() {
|
|||||||
float facing_up = 1.0;
|
float facing_up = 1.0;
|
||||||
|
|
||||||
// Snow accumulation
|
// Snow accumulation
|
||||||
float snow_amount = 0.0;
|
float snow_amount = get_snow_progress();
|
||||||
if (global_snow_start_time >= 0.0) {
|
|
||||||
snow_amount = clamp((TIME - global_snow_start_time) * global_snow_accumulation_speed, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
if (global_snow_melt_time >= 0.0) {
|
|
||||||
float melt = clamp((TIME - global_snow_melt_time) * global_snow_melt_speed, 0.0, 1.0);
|
|
||||||
snow_amount *= (1.0 - melt);
|
|
||||||
}
|
|
||||||
|
|
||||||
// UV-based snow mask: accumulates from the top of the quad
|
// Plain surfaces fade in uniformly to avoid patchy strip-like accumulation.
|
||||||
float top_mask = 1.0 - UV.y;
|
float snow_mask = smoothstep(0.0, 1.0, snow_amount);
|
||||||
float snow_mask = smoothstep(1.0 - snow_amount, 1.0 - snow_amount + snow_edge_softness, top_mask);
|
|
||||||
snow_mask *= step(0.01, snow_amount);
|
snow_mask *= step(0.01, snow_amount);
|
||||||
|
|
||||||
// Snow color with slight variation
|
// Snow color with slight variation
|
||||||
|
|||||||
@@ -1,7 +1,21 @@
|
|||||||
[gd_resource type="ShaderMaterial" format=3]
|
[gd_resource type="ShaderMaterial" format=3 uid="uid://b34bnqbrtxktw"]
|
||||||
|
|
||||||
[ext_resource type="Shader" path="res://core/daynight/weather_plain_shader.gdshader" id="1_weather_plain"]
|
[ext_resource type="Shader" uid="uid://do8puw7u8dvry" path="res://core/daynight/weather_plain_shader.gdshader" id="1_weather_plain"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://bpswbjh4jj1ou" path="res://core/daynight/noise.tres" id="2_noise"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
render_priority = 0
|
render_priority = 0
|
||||||
shader = ExtResource("1_weather_plain")
|
shader = ExtResource("1_weather_plain")
|
||||||
|
shader_parameter/snow_edge_softness = 0.15
|
||||||
|
shader_parameter/snow_color_variation = 0.05
|
||||||
|
shader_parameter/ripple_scale = 1.5
|
||||||
|
shader_parameter/ripple_speed = 2.0
|
||||||
|
shader_parameter/ripple_layers = 3.0
|
||||||
|
shader_parameter/streak_scale = 2.0
|
||||||
|
shader_parameter/streak_speed = 0.8
|
||||||
|
shader_parameter/wetness_darkening = 0.25
|
||||||
|
shader_parameter/wet_roughness = 0.05
|
||||||
|
shader_parameter/rain_normal_strength = 0.4
|
||||||
|
shader_parameter/puddle_noise_scale = 0.08
|
||||||
|
shader_parameter/puddle_threshold = 0.45
|
||||||
|
shader_parameter/noise_texture = ExtResource("2_noise")
|
||||||
|
|||||||
@@ -1,31 +1,26 @@
|
|||||||
shader_type spatial;
|
shader_type spatial;
|
||||||
render_mode unshaded;
|
render_mode unshaded;
|
||||||
|
|
||||||
global uniform float global_wind_speed = 1.0; //0.0 = calm, 1.0 = normal, 2.0+ = strong
|
// --- PARAMETRI ---
|
||||||
global uniform vec2 global_wind_direction = vec2(1.0, 0.0);
|
uniform float time_scale = 3.0;
|
||||||
|
uniform float wave_amplitude = 0.5; // Quanto curva a destra/sinistra
|
||||||
uniform float wave_frequency = 1.0;
|
uniform float wave_frequency = 1.0; // Ogni quanto fa la curva
|
||||||
uniform float base_amplitude = 0.5;
|
|
||||||
uniform float secondary_ratio = 0.6;
|
|
||||||
uniform float time_scale_base = 3.0;
|
|
||||||
|
|
||||||
void vertex() {
|
void vertex() {
|
||||||
|
// Creiamo un offset unico per ogni particella in modo che non si muovano tutte uguali
|
||||||
float random_seed_offset = INSTANCE_CUSTOM.x * 100.0;
|
float random_seed_offset = INSTANCE_CUSTOM.x * 100.0;
|
||||||
float scaled_time = (TIME + random_seed_offset) * (time_scale_base * global_wind_speed);
|
float scaled_time = (TIME + random_seed_offset) * time_scale;
|
||||||
float amplitude = base_amplitude * global_wind_speed;
|
|
||||||
|
|
||||||
vec2 wind_dir = normalize(global_wind_direction);
|
// Applichiamo SOLO la curva morbida all'asse X (o Z, a seconda di come orienti la scena)
|
||||||
vec2 wind_perp = vec2(-wind_dir.y, wind_dir.x); //90° perpendicular
|
// Usiamo VERTEX.y per far sì che la curva si propaghi lungo tutta la lunghezza della scia
|
||||||
|
VERTEX.x += sin(VERTEX.y * wave_frequency + scaled_time) * wave_amplitude;
|
||||||
|
|
||||||
float primary_sway = sin(VERTEX.y * wave_frequency + scaled_time) * amplitude;
|
// Niente più "VERTEX.y += t;", quindi niente più teletrasporti!
|
||||||
float secondary_sway = sin(VERTEX.y * wave_frequency * 1.3 + scaled_time * 0.7 + 1.57)
|
|
||||||
* (amplitude * secondary_ratio);
|
|
||||||
|
|
||||||
VERTEX.x += primary_sway * wind_dir.x + secondary_sway * wind_perp.x;
|
|
||||||
VERTEX.z += primary_sway * wind_dir.y + secondary_sway * wind_perp.y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void fragment() {
|
void fragment() {
|
||||||
|
// Il colore e l'alpha (per lo spawn dolce e la morte lenta)
|
||||||
|
// vengono comandati dalla Color Ramp del GPUParticles3D!
|
||||||
ALBEDO = COLOR.rgb;
|
ALBEDO = COLOR.rgb;
|
||||||
ALPHA = COLOR.a;
|
ALPHA = COLOR.a;
|
||||||
}
|
}
|
||||||
@@ -81,8 +81,9 @@ extends Resource
|
|||||||
#Post-process effect toggles (initial values)
|
#Post-process effect toggles (initial values)
|
||||||
@export_group("Post Process")
|
@export_group("Post Process")
|
||||||
@export var enable_dust: bool = false #Floating dust particles overlay
|
@export var enable_dust: bool = false #Floating dust particles overlay
|
||||||
@export var enable_blur: bool = false #Screen blur effect
|
@export var enable_blur: bool = true #Screen blur effect
|
||||||
@export var enable_environment_shadows: bool = true #Cloud shadow projection on terrain
|
@export var enable_environment_shadows: bool = true #Cloud shadow projection on terrain
|
||||||
|
@export var enable_fog: bool = false #Enable fog around the train
|
||||||
@export var blur_amount: float = 0.6
|
@export var blur_amount: float = 0.6
|
||||||
|
|
||||||
@export_group("Dust")
|
@export_group("Dust")
|
||||||
@@ -97,19 +98,21 @@ extends Resource
|
|||||||
@export var material_fog: ShaderMaterial #Fog overlay shader material
|
@export var material_fog: ShaderMaterial #Fog overlay shader material
|
||||||
@export var material_drops: StandardMaterial3D #Rain drops material (albedo tinted by sky)
|
@export var material_drops: StandardMaterial3D #Rain drops material (albedo tinted by sky)
|
||||||
@export var material_clouds: ShaderMaterial #Cloud layer shader material
|
@export var material_clouds: ShaderMaterial #Cloud layer shader material
|
||||||
|
@export var base_cloud_density: float = 0.4 #default cloud density
|
||||||
|
|
||||||
#Rain weather settings
|
#Rain weather settings
|
||||||
@export_group("Rain")
|
@export_group("Rain")
|
||||||
@export var rain_mode_color: Color = Color(0.5, 0.6, 0.7, 1.0) #Sky/light darkening color during rain
|
@export var rain_mode_color: Color = Color(0.85, 0.89, 0.93, 1.0) #Sky/light darkening color during rain
|
||||||
@export var rain_fade_time: float = 5.0 #Seconds for rain particles to fade in/out
|
@export var rain_fade_time: float = 5.0 #Seconds for rain particles to fade in/out
|
||||||
@export var rain_audio_volume_db: float = -10.0 #Target rain loop volume in decibels
|
@export var rain_audio_volume_db: float = -10.0 #Target rain loop volume in decibels
|
||||||
@export var puddle_form_time: float = 15.0 #Seconds for puddles to fully form
|
@export var puddle_form_time: float = 15.0 #Seconds for puddles to fully form
|
||||||
@export var puddle_dry_time: float = 20.0 #Seconds for puddles to fully dry after rain stops
|
@export var puddle_dry_time: float = 20.0 #Seconds for puddles to fully dry after rain stops
|
||||||
|
@export var rain_cloud_density: float = 1.0 #the cloud density when is rainy
|
||||||
|
|
||||||
#Storm settings (applied on top of rain when storm is active)
|
#Storm settings (applied on top of rain when storm is active)
|
||||||
@export_group("Storm")
|
@export_group("Storm")
|
||||||
@export var storm_rain_intensity_multiplier: float = 1.5 #Rain intensity target during storm (1.0 = normal rain)
|
@export var storm_rain_intensity_multiplier: float = 1.5 #Rain intensity target during storm (1.0 = normal rain)
|
||||||
@export var storm_mode_color: Color = Color(0.476, 0.531, 0.639, 1.0) #Additional sky darkening color during storm
|
@export var storm_mode_color: Color = Color(0.78, 0.83, 0.89, 1.0) #Additional sky darkening color during storm
|
||||||
|
|
||||||
#Lightning and thunder configuration
|
#Lightning and thunder configuration
|
||||||
@export_group("Lightning and Thunders")
|
@export_group("Lightning and Thunders")
|
||||||
@@ -133,15 +136,27 @@ extends Resource
|
|||||||
@export var godray_spawn_height: float = 5.0 #Y world position where god rays spawn
|
@export var godray_spawn_height: float = 5.0 #Y world position where god rays spawn
|
||||||
@export var godray_scale: Vector3 = Vector3(2.0, 6.0, 2.0) #Scale of the god ray mesh
|
@export var godray_scale: Vector3 = Vector3(2.0, 6.0, 2.0) #Scale of the god ray mesh
|
||||||
|
|
||||||
|
#Train start settings
|
||||||
|
@export_group("Train Start")
|
||||||
|
@export var train_start_from_random_position: bool = true #When enabled the train starts from a random offset on the rail curve instead of a stop
|
||||||
|
@export_range(0, 64, 1, "or_greater") var train_start_stop_index: int = 1 #Stop index used for the train start when random start is disabled
|
||||||
|
|
||||||
#Snow settings
|
#Snow settings
|
||||||
@export_group("Snow")
|
@export_group("Snow")
|
||||||
@export var snow_amount: float = 0.0 #Initial snow coverage amount (0.0 = none, 1.0 = full)
|
@export var snow_amount: float = 0.0 #Initial snow coverage amount (0.0 = none, 1.0 = full)
|
||||||
@export var snow_transaction_time: float = 10.0 #Seconds for snow shader to fully transition in/out
|
@export var snow_transaction_time: float = 10.0 #Seconds for snow shader to fully transition in/out
|
||||||
@export var snow_fade_time: float = 5.0 #Seconds for snow particles to fade in/out
|
@export var snow_fade_time: float = 5.0 #Seconds for snow particles to fade in/out
|
||||||
@export var snow_threshold: float = 0.4 #Normal Y threshold for snow accumulation on surfaces
|
@export var snow_threshold: float = 0.4 #Normal Y threshold for snow accumulation on surfaces
|
||||||
@export var snow_accumulation_speed: float = 0.02 #Accumulation speed: 0.1 -> 10s, 0.05 -> 20s, 0.02 -> 50s, 0.2 -> 5s
|
@export var snow_accumulation_speed: float = 0.005 #Accumulation speed: 0.005 -> ~200s, 0.01 -> 100s, 0.02 -> 50s
|
||||||
@export var snow_melt_speed: float = 0.05 #Speed at which accumulated snow melts away
|
@export var snow_melt_speed: float = 0.05 #Speed at which accumulated snow melts away
|
||||||
|
@export var show_snow_accumulation_volume: bool = true #Enables vertex snow buildup; when false snow only changes surface color
|
||||||
|
@export var snow_max_accumulation: float = 0.25 #Maximum accumulated snow factor applied to coverage and thickness
|
||||||
@export var snow_color: Color = Color(0.9, 0.95, 1.0) #Albedo color of snow on surfaces
|
@export var snow_color: Color = Color(0.9, 0.95, 1.0) #Albedo color of snow on surfaces
|
||||||
|
@export var snow_cap_height: float = 0.03 #Maximum snow thickness extruded on flat surfaces
|
||||||
|
@export var snow_cap_flatness_start: float = 0.85 #Surface normal Y where cap buildup starts
|
||||||
|
@export var snow_cap_flatness_end: float = 0.96 #Surface normal Y where cap buildup reaches full effect
|
||||||
|
@export var snow_cap_noise_scale: float = 0.22 #Noise scale used to vary the snow cap silhouette
|
||||||
|
@export var snow_cap_noise_strength: float = 0.12 #How much the cap noise changes the accumulated thickness
|
||||||
@export var snow_mode_color: Color = Color(0.556, 0.62, 0.683, 1.0) #Sky/light darkening color during snow
|
@export var snow_mode_color: Color = Color(0.556, 0.62, 0.683, 1.0) #Sky/light darkening color during snow
|
||||||
|
|
||||||
#Wind settings
|
#Wind settings
|
||||||
@@ -152,7 +167,7 @@ extends Resource
|
|||||||
@export var wind_direction: Vector2 = Vector2(0.5, 0.4) #Global wind direction (XZ)
|
@export var wind_direction: Vector2 = Vector2(0.5, 0.4) #Global wind direction (XZ)
|
||||||
@export var wind_speed: float = 0.2 #Global wind animation speed
|
@export var wind_speed: float = 0.2 #Global wind animation speed
|
||||||
@export var wind_scale: float = 0.025 #Global wind noise scale
|
@export var wind_scale: float = 0.025 #Global wind noise scale
|
||||||
@export var wind_strength: float = 0.6 #Global wind displacement strength
|
@export var wind_strength: float = 0.3 #Global wind displacement strength
|
||||||
@export var cloud_scale: float = 0.5 #Cloud noise scale in sky shader
|
@export var cloud_scale: float = 0.5 #Cloud noise scale in sky shader
|
||||||
@export var cloud_speed: float = 0.05 #Cloud movement speed in sky shader
|
@export var cloud_speed: float = 0.05 #Cloud movement speed in sky shader
|
||||||
@export_range(0.01, 1.0) var cloud_scale_envshadows_rate: float = 0.01 #Cloud scale multiplier for environment shadows
|
@export_range(0.01, 1.0) var cloud_scale_envshadows_rate: float = 0.01 #Cloud scale multiplier for environment shadows
|
||||||
@@ -164,3 +179,14 @@ extends Resource
|
|||||||
@export var fireflies_amount: int = 60 #Number of firefly particles
|
@export var fireflies_amount: int = 60 #Number of firefly particles
|
||||||
@export var fireflies_spawn_ray: float = 20.0 #Horizontal spawn radius
|
@export var fireflies_spawn_ray: float = 20.0 #Horizontal spawn radius
|
||||||
@export var fireflies_spawn_height: float = 3.0 #Vertical spawn range
|
@export var fireflies_spawn_height: float = 3.0 #Vertical spawn range
|
||||||
|
|
||||||
|
#Water settings
|
||||||
|
@export_group("Water")
|
||||||
|
@export var water_color_morning: Color = Color(0.285, 0.534, 0.487, 1.0) #Tint for morning
|
||||||
|
@export var water_color_afternoon: Color = Color(0.889, 0.733, 0.205, 1.0) #Tint for afternoon (sunset)
|
||||||
|
@export var water_color_night: Color = Color(0.728, 0.54, 0.986, 1.0); #Tint for night
|
||||||
|
@export var water_darkening_rain: float = 0.7 #Percentage of darkening when is rainy
|
||||||
|
|
||||||
|
#Random events
|
||||||
|
@export_group("Random Events")
|
||||||
|
@export var random_event_duration: float = 30.0 #Duration time for random event
|
||||||
|
|||||||
32
core/game_state/game_state.gd
Normal file
32
core/game_state/game_state.gd
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
const SAVE_PATH: String = "user://savegame.json"
|
||||||
|
|
||||||
|
var save_data: SaveGameData = SaveGameData.new()
|
||||||
|
var is_loaded: bool = false
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
load_game()
|
||||||
|
|
||||||
|
func save_game() -> void:
|
||||||
|
var save_file = FileAccess.open(SAVE_PATH, FileAccess.WRITE)
|
||||||
|
var json_string = JSON.stringify(save_data.to_dictionary())
|
||||||
|
save_file.store_line(json_string)
|
||||||
|
|
||||||
|
func load_game() -> void:
|
||||||
|
if not FileAccess.file_exists(SAVE_PATH):
|
||||||
|
save_data = SaveGameData.new()
|
||||||
|
is_loaded = true
|
||||||
|
return
|
||||||
|
|
||||||
|
var file = FileAccess.open(SAVE_PATH, FileAccess.READ)
|
||||||
|
var json_string = file.get_as_text()
|
||||||
|
|
||||||
|
var json = JSON.new()
|
||||||
|
var parse_result = json.parse(json_string)
|
||||||
|
|
||||||
|
save_data = SaveGameData.new()
|
||||||
|
if parse_result == OK and json.data is Dictionary:
|
||||||
|
save_data = SaveGameData.from_dictionary(json.data)
|
||||||
|
|
||||||
|
is_loaded = true
|
||||||
1
core/game_state/game_state.gd.uid
Normal file
1
core/game_state/game_state.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://b17g2w2g101o6
|
||||||
34
core/game_state/save_game_data.gd
Normal file
34
core/game_state/save_game_data.gd
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
class_name SaveGameData
|
||||||
|
extends Resource
|
||||||
|
|
||||||
|
var unlocked_collectibles_ids: Array[StringName] = []
|
||||||
|
var saved_photos: Array[String] = []
|
||||||
|
var audio_bus_volumes: Dictionary[String, float] = {}
|
||||||
|
|
||||||
|
func to_dictionary() -> Dictionary:
|
||||||
|
var serialized_collectible_ids: Array[String] = []
|
||||||
|
for collectible_id in unlocked_collectibles_ids:
|
||||||
|
serialized_collectible_ids.append(str(collectible_id))
|
||||||
|
|
||||||
|
return {
|
||||||
|
"unlocked_collectibles_ids": serialized_collectible_ids,
|
||||||
|
"saved_photos": saved_photos,
|
||||||
|
"audio_bus_volumes": audio_bus_volumes,
|
||||||
|
}
|
||||||
|
|
||||||
|
static func from_dictionary(data: Dictionary) -> SaveGameData:
|
||||||
|
var save_game_data := SaveGameData.new()
|
||||||
|
|
||||||
|
if data.has("unlocked_collectibles_ids"):
|
||||||
|
for collectible_id in data["unlocked_collectibles_ids"]:
|
||||||
|
save_game_data.unlocked_collectibles_ids.append(StringName(str(collectible_id)))
|
||||||
|
|
||||||
|
if data.has("saved_photos"):
|
||||||
|
for photo_path in data["saved_photos"]:
|
||||||
|
save_game_data.saved_photos.append(str(photo_path))
|
||||||
|
|
||||||
|
if data.has("audio_bus_volumes") and data["audio_bus_volumes"] is Dictionary:
|
||||||
|
for bus_name in data["audio_bus_volumes"]:
|
||||||
|
save_game_data.audio_bus_volumes[str(bus_name)] = float(data["audio_bus_volumes"][bus_name])
|
||||||
|
|
||||||
|
return save_game_data
|
||||||
1
core/game_state/save_game_data.gd.uid
Normal file
1
core/game_state/save_game_data.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://bxmvs842r82vl
|
||||||
4
core/photo_mode/data/collectible_library.gd
Normal file
4
core/photo_mode/data/collectible_library.gd
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
class_name CollectibleLibrary
|
||||||
|
extends Resource
|
||||||
|
|
||||||
|
@export var collectibles: Array[CollectibleResource]
|
||||||
1
core/photo_mode/data/collectible_library.gd.uid
Normal file
1
core/photo_mode/data/collectible_library.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://hhuufh87skq5
|
||||||
31
core/photo_mode/data/collectible_library.tres
Normal file
31
core/photo_mode/data/collectible_library.tres
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
[gd_resource type="Resource" script_class="CollectibleLibrary" format=3 uid="uid://c6pkpvsvimafb"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://bj34o0org55ei" path="res://core/photo_mode/data/collectible_resource.gd" id="1_3cgvf"]
|
||||||
|
[ext_resource type="Script" uid="uid://hhuufh87skq5" path="res://core/photo_mode/data/collectible_library.gd" id="2_ggu10"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://cx8d233y32kmu" path="res://icon.svg" id="2_pxmdy"]
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_3cgvf"]
|
||||||
|
script = ExtResource("1_3cgvf")
|
||||||
|
id = &"cane"
|
||||||
|
title = "Cane"
|
||||||
|
image = ExtResource("2_pxmdy")
|
||||||
|
metadata/_custom_type_script = "uid://bj34o0org55ei"
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_ggu10"]
|
||||||
|
script = ExtResource("1_3cgvf")
|
||||||
|
id = &"gatto"
|
||||||
|
title = "Gatto"
|
||||||
|
image = ExtResource("2_pxmdy")
|
||||||
|
metadata/_custom_type_script = "uid://bj34o0org55ei"
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_pxmdy"]
|
||||||
|
script = ExtResource("1_3cgvf")
|
||||||
|
id = &"farfalla"
|
||||||
|
title = "Farfalla"
|
||||||
|
image = ExtResource("2_pxmdy")
|
||||||
|
metadata/_custom_type_script = "uid://bj34o0org55ei"
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
script = ExtResource("2_ggu10")
|
||||||
|
collectibles = Array[ExtResource("1_3cgvf")]([SubResource("Resource_3cgvf"), SubResource("Resource_ggu10"), SubResource("Resource_pxmdy")])
|
||||||
|
metadata/_custom_type_script = "uid://hhuufh87skq5"
|
||||||
6
core/photo_mode/data/collectible_resource.gd
Normal file
6
core/photo_mode/data/collectible_resource.gd
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
class_name CollectibleResource
|
||||||
|
extends Resource
|
||||||
|
|
||||||
|
@export var id: StringName
|
||||||
|
@export var title: String
|
||||||
|
@export var image: Texture2D
|
||||||
1
core/photo_mode/data/collectible_resource.gd.uid
Normal file
1
core/photo_mode/data/collectible_resource.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://bj34o0org55ei
|
||||||
60
core/photo_mode/managers/collection_manager.gd
Normal file
60
core/photo_mode/managers/collection_manager.gd
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
signal on_collectible_unlocked(collectible_id: StringName)
|
||||||
|
signal on_photo_saved(filePath: String)
|
||||||
|
|
||||||
|
var collectibles_library: CollectibleLibrary = preload("res://core/photo_mode/data/collectible_library.tres")
|
||||||
|
|
||||||
|
var unlocked_collectibles_ids: Array[StringName] = []
|
||||||
|
var saved_photos: Array[String] = []
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
load_save_data()
|
||||||
|
|
||||||
|
func unlock_collectible(collectible_id: StringName) -> void:
|
||||||
|
if not collectible_id in unlocked_collectibles_ids:
|
||||||
|
var new_collectible = get_collectible_by_id(collectible_id)
|
||||||
|
if new_collectible:
|
||||||
|
unlocked_collectibles_ids.append(collectible_id)
|
||||||
|
sync_save_data()
|
||||||
|
on_collectible_unlocked.emit(collectible_id)
|
||||||
|
|
||||||
|
func get_collectible_by_id(id: StringName) -> CollectibleResource:
|
||||||
|
for collectible in collectibles_library.collectibles:
|
||||||
|
if collectible.id == id:
|
||||||
|
return collectible
|
||||||
|
return null
|
||||||
|
|
||||||
|
func get_all_collectibles() -> Array[CollectibleResource]:
|
||||||
|
return collectibles_library.collectibles
|
||||||
|
|
||||||
|
func get_unlocked_collectible_ids() -> Array[StringName]:
|
||||||
|
return unlocked_collectibles_ids
|
||||||
|
|
||||||
|
func save_photo_to_disk_async() -> void:
|
||||||
|
await RenderingServer.frame_post_draw
|
||||||
|
var image = get_viewport().get_texture().get_image()
|
||||||
|
|
||||||
|
if not DirAccess.dir_exists_absolute("user://photos"):
|
||||||
|
DirAccess.make_dir_absolute("user://photos")
|
||||||
|
|
||||||
|
var timestamp = str(Time.get_unix_time_from_system())
|
||||||
|
var file_path = "user://photos/photo_" + timestamp + ".png"
|
||||||
|
image.save_png(file_path)
|
||||||
|
|
||||||
|
saved_photos.append(file_path)
|
||||||
|
sync_save_data()
|
||||||
|
on_photo_saved.emit(file_path)
|
||||||
|
|
||||||
|
func sync_save_data() -> void:
|
||||||
|
GameState.save_data.unlocked_collectibles_ids = unlocked_collectibles_ids.duplicate()
|
||||||
|
GameState.save_data.saved_photos = saved_photos.duplicate()
|
||||||
|
|
||||||
|
func load_save_data() -> void:
|
||||||
|
unlocked_collectibles_ids = GameState.save_data.unlocked_collectibles_ids.duplicate()
|
||||||
|
saved_photos = GameState.save_data.saved_photos.duplicate()
|
||||||
|
|
||||||
|
if unlocked_collectibles_ids.is_empty() and saved_photos.is_empty():
|
||||||
|
unlocked_collectibles_ids.append(&"cane")
|
||||||
|
|
||||||
|
sync_save_data()
|
||||||
1
core/photo_mode/managers/collection_manager.gd.uid
Normal file
1
core/photo_mode/managers/collection_manager.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://c3kq1qddpm8tf
|
||||||
6
core/photo_mode/runtime/collectible.gd
Normal file
6
core/photo_mode/runtime/collectible.gd
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
extends Area3D
|
||||||
|
|
||||||
|
@export var collectible_data: CollectibleResource
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
add_to_group("collectible")
|
||||||
1
core/photo_mode/runtime/collectible.gd.uid
Normal file
1
core/photo_mode/runtime/collectible.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://62d14boivr3g
|
||||||
11
core/photo_mode/runtime/collectible.tscn
Normal file
11
core/photo_mode/runtime/collectible.tscn
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[gd_scene format=3 uid="uid://bmkxt6btcx8qr"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://62d14boivr3g" path="res://core/photo_mode/runtime/collectible.gd" id="1_xse8c"]
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_xse8c"]
|
||||||
|
|
||||||
|
[node name="Collectible" type="Area3D" unique_id=1229019813]
|
||||||
|
script = ExtResource("1_xse8c")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=1479480920]
|
||||||
|
shape = SubResource("BoxShape3D_xse8c")
|
||||||
94
core/photo_mode/runtime/photo_mode_controller.gd
Normal file
94
core/photo_mode/runtime/photo_mode_controller.gd
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
extends Node3D
|
||||||
|
|
||||||
|
@export_group("Speed")
|
||||||
|
@export var pan_speed: float = 5.0
|
||||||
|
@export var rotation_speed: float = 0.003
|
||||||
|
|
||||||
|
@export_group("Bounds")
|
||||||
|
@export var movement_bounds: AABB
|
||||||
|
|
||||||
|
@export_group("Ref")
|
||||||
|
@export var rotation_target: Node3D
|
||||||
|
|
||||||
|
@onready var camera: Camera3D = $%Camera3D
|
||||||
|
|
||||||
|
var total_yaw: float = 0.0
|
||||||
|
var total_pitch: float = 0.0
|
||||||
|
var orbit_distance: float = 0.0
|
||||||
|
var current_pan: Vector2 = Vector2.ZERO
|
||||||
|
var is_active: bool = false
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
total_yaw = global_rotation.y
|
||||||
|
total_pitch = global_rotation.x
|
||||||
|
|
||||||
|
if rotation_target:
|
||||||
|
orbit_distance = global_position.distance_to(rotation_target.global_position)
|
||||||
|
|
||||||
|
func _unhandled_input(event: InputEvent) -> void:
|
||||||
|
if event.is_action_pressed("toggle_photo_mode"):
|
||||||
|
is_active = !is_active
|
||||||
|
|
||||||
|
get_tree().paused = is_active
|
||||||
|
|
||||||
|
if !is_active:
|
||||||
|
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
||||||
|
else:
|
||||||
|
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
||||||
|
|
||||||
|
if event is InputEventMouseMotion and is_active:
|
||||||
|
total_yaw -= event.relative.x * rotation_speed
|
||||||
|
|
||||||
|
if event.is_action_pressed("take_photo"):
|
||||||
|
take_photo_async()
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
if not rotation_target:
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
var pan_input = Input.get_vector("photo_pan_left", "photo_pan_right", "photo_pan_up", "photo_pan_down")
|
||||||
|
var rot_basis = Basis.from_euler(Vector3(total_pitch, total_yaw, 0))
|
||||||
|
|
||||||
|
if pan_input != Vector2.ZERO and is_active:
|
||||||
|
current_pan.x += pan_input.x * pan_speed * delta
|
||||||
|
current_pan.y += -pan_input.y * pan_speed * delta
|
||||||
|
|
||||||
|
if movement_bounds.size != Vector3.ZERO:
|
||||||
|
current_pan.x = clampf(current_pan.x, movement_bounds.position.x, movement_bounds.position.x + movement_bounds.size.x)
|
||||||
|
current_pan.y = clampf(current_pan.y, movement_bounds.position.y, movement_bounds.position.y + movement_bounds.size.y)
|
||||||
|
|
||||||
|
var right_dir = rot_basis.x.normalized()
|
||||||
|
var up_dir = rot_basis.y.normalized()
|
||||||
|
|
||||||
|
var final_pan_offset = (right_dir * current_pan.x) + (up_dir * current_pan.y)
|
||||||
|
|
||||||
|
var orbit_pos = rotation_target.global_position + (rot_basis * Vector3(0, 0, orbit_distance))
|
||||||
|
|
||||||
|
global_position = orbit_pos + final_pan_offset
|
||||||
|
global_basis = rot_basis
|
||||||
|
|
||||||
|
func take_photo_async() -> void:
|
||||||
|
if !is_active:
|
||||||
|
return
|
||||||
|
|
||||||
|
var targets = get_tree().get_nodes_in_group("collectible")
|
||||||
|
var space_state = get_world_3d().direct_space_state
|
||||||
|
|
||||||
|
await CollectionManager.save_photo_to_disk_async()
|
||||||
|
|
||||||
|
for target in targets:
|
||||||
|
if not target.collectible_data:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if camera.is_position_in_frustum(target.global_position):
|
||||||
|
var query = PhysicsRayQueryParameters3D.create(camera.global_position, target.global_position)
|
||||||
|
query.collide_with_areas = true
|
||||||
|
query.collide_with_bodies = true
|
||||||
|
|
||||||
|
var result = space_state.intersect_ray(query)
|
||||||
|
|
||||||
|
if result and result.collider == target:
|
||||||
|
CollectionManager.unlock_collectible(target.collectible_data.id)
|
||||||
|
|
||||||
|
GameState.save_game()
|
||||||
1
core/photo_mode/runtime/photo_mode_controller.gd.uid
Normal file
1
core/photo_mode/runtime/photo_mode_controller.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://d7ln6iru6mq6
|
||||||
10
core/photo_mode/runtime/photo_mode_controller.tscn
Normal file
10
core/photo_mode/runtime/photo_mode_controller.tscn
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[gd_scene format=3 uid="uid://vni5kjalum6d"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://d7ln6iru6mq6" path="res://core/photo_mode/runtime/photo_mode_controller.gd" id="1_uhpya"]
|
||||||
|
|
||||||
|
[node name="PhotoModeController" type="Node3D" unique_id=695158870]
|
||||||
|
process_mode = 3
|
||||||
|
script = ExtResource("1_uhpya")
|
||||||
|
|
||||||
|
[node name="Camera3D" type="Camera3D" parent="." unique_id=1369039645]
|
||||||
|
unique_name_in_owner = true
|
||||||
34
core/photo_mode/ui/collectible_gallery.gd
Normal file
34
core/photo_mode/ui/collectible_gallery.gd
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
@export var collectible_ui_scene: PackedScene
|
||||||
|
|
||||||
|
@onready var grid_container: GridContainer = $%CollectibleGrid
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
CollectionManager.on_collectible_unlocked.connect(_unlock_collectible)
|
||||||
|
setup()
|
||||||
|
|
||||||
|
func setup() -> void:
|
||||||
|
var unlocked_collectible_ids = CollectionManager.get_unlocked_collectible_ids()
|
||||||
|
var collectibles = CollectionManager.get_all_collectibles()
|
||||||
|
|
||||||
|
for child in grid_container.get_children():
|
||||||
|
child.queue_free()
|
||||||
|
|
||||||
|
for collectible in collectibles:
|
||||||
|
_add_collectible(collectible)
|
||||||
|
if unlocked_collectible_ids.has(collectible.id):
|
||||||
|
_unlock_collectible(collectible.id)
|
||||||
|
|
||||||
|
func on_collectible_unlocked(collectible_id: StringName) -> void:
|
||||||
|
_unlock_collectible(collectible_id)
|
||||||
|
|
||||||
|
func _add_collectible(collectible: CollectibleResource) -> void:
|
||||||
|
var collectible_ui: CollectibleUI = collectible_ui_scene.instantiate()
|
||||||
|
collectible_ui.setup(collectible)
|
||||||
|
grid_container.add_child(collectible_ui)
|
||||||
|
|
||||||
|
func _unlock_collectible(collectible_id: StringName) -> void:
|
||||||
|
for collectible_ui in grid_container.get_children():
|
||||||
|
if collectible_ui.collectible_resource.id == collectible_id:
|
||||||
|
collectible_ui.unlock()
|
||||||
1
core/photo_mode/ui/collectible_gallery.gd.uid
Normal file
1
core/photo_mode/ui/collectible_gallery.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dq3qtcrdnikl7
|
||||||
50
core/photo_mode/ui/collectible_gallery.tscn
Normal file
50
core/photo_mode/ui/collectible_gallery.tscn
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
[gd_scene format=3 uid="uid://bvw086glfpcba"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://dq3qtcrdnikl7" path="res://core/photo_mode/ui/collectible_gallery.gd" id="1_67tug"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://dp7dvfauh5rpx" path="res://core/photo_mode/ui/collectible_ui.tscn" id="2_or234"]
|
||||||
|
|
||||||
|
[node name="CollectibleGallery" type="Control" unique_id=354419843]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_67tug")
|
||||||
|
collectible_ui_scene = ExtResource("2_or234")
|
||||||
|
|
||||||
|
[node name="PanelContainer" type="PanelContainer" parent="." unique_id=640179265]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -350.0
|
||||||
|
offset_top = -350.0
|
||||||
|
offset_right = 350.0
|
||||||
|
offset_bottom = 350.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="PanelContainer" unique_id=125147979]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/margin_left = 12
|
||||||
|
theme_override_constants/margin_top = 12
|
||||||
|
theme_override_constants/margin_right = 12
|
||||||
|
theme_override_constants/margin_bottom = 12
|
||||||
|
|
||||||
|
[node name="ScrollContainer" type="ScrollContainer" parent="PanelContainer/MarginContainer" unique_id=348576028]
|
||||||
|
layout_mode = 2
|
||||||
|
draw_focus_border = true
|
||||||
|
|
||||||
|
[node name="CollectibleGrid" type="GridContainer" parent="PanelContainer/MarginContainer/ScrollContainer" unique_id=1187865988]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 6
|
||||||
|
size_flags_vertical = 2
|
||||||
|
theme_override_constants/h_separation = 12
|
||||||
|
theme_override_constants/v_separation = 12
|
||||||
|
columns = 3
|
||||||
22
core/photo_mode/ui/collectible_ui.gd
Normal file
22
core/photo_mode/ui/collectible_ui.gd
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
class_name CollectibleUI
|
||||||
|
|
||||||
|
@onready var label: Label = $%CollectibleName
|
||||||
|
@onready var texture_rect: TextureRect = $%CollectibleTexture
|
||||||
|
var collectible_resource: CollectibleResource
|
||||||
|
|
||||||
|
func setup(collectible: CollectibleResource) -> void:
|
||||||
|
collectible_resource = collectible
|
||||||
|
if !label:
|
||||||
|
label = $%CollectibleName
|
||||||
|
label.text = collectible_resource.title
|
||||||
|
if collectible.image:
|
||||||
|
if !texture_rect:
|
||||||
|
texture_rect = $%CollectibleTexture
|
||||||
|
texture_rect.texture = collectible_resource.image
|
||||||
|
|
||||||
|
func unlock() -> void:
|
||||||
|
if !texture_rect:
|
||||||
|
texture_rect = $%CollectibleTexture
|
||||||
|
texture_rect.set_modulate(Color(1,1,1,1))
|
||||||
1
core/photo_mode/ui/collectible_ui.gd.uid
Normal file
1
core/photo_mode/ui/collectible_ui.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dxh8e1n16qjpp
|
||||||
49
core/photo_mode/ui/collectible_ui.tscn
Normal file
49
core/photo_mode/ui/collectible_ui.tscn
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
[gd_scene format=3 uid="uid://dp7dvfauh5rpx"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://dxh8e1n16qjpp" path="res://core/photo_mode/ui/collectible_ui.gd" id="1_tu5nx"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://cx8d233y32kmu" path="res://icon.svg" id="1_x3wje"]
|
||||||
|
|
||||||
|
[node name="CollectibleUI" type="Control" unique_id=201865221]
|
||||||
|
custom_minimum_size = Vector2(200, 200)
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 0
|
||||||
|
offset_right = 200.0
|
||||||
|
offset_bottom = 200.0
|
||||||
|
script = ExtResource("1_tu5nx")
|
||||||
|
|
||||||
|
[node name="Panel" type="PanelContainer" parent="." unique_id=1372516531]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="Panel" unique_id=1141643525]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/margin_left = 12
|
||||||
|
theme_override_constants/margin_top = 12
|
||||||
|
theme_override_constants/margin_right = 12
|
||||||
|
theme_override_constants/margin_bottom = 12
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="Panel/MarginContainer" unique_id=1841409877]
|
||||||
|
layout_mode = 2
|
||||||
|
alignment = 1
|
||||||
|
|
||||||
|
[node name="CollectibleName" type="Label" parent="Panel/MarginContainer/VBoxContainer" unique_id=117774359]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 0
|
||||||
|
text = "Collectible"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="HSeparator" type="HSeparator" parent="Panel/MarginContainer/VBoxContainer" unique_id=1345822244]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="CollectibleTexture" type="TextureRect" parent="Panel/MarginContainer/VBoxContainer" unique_id=506844785]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
modulate = Color(0.16206557, 0.1620656, 0.16206557, 1)
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
texture = ExtResource("1_x3wje")
|
||||||
|
stretch_mode = 3
|
||||||
11
core/photo_mode/ui/photo.gd
Normal file
11
core/photo_mode/ui/photo.gd
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
class_name Photo
|
||||||
|
|
||||||
|
@onready var texture_rect: TextureRect = $%PhotoTexture
|
||||||
|
|
||||||
|
func setup(texture: Texture) -> void:
|
||||||
|
if texture:
|
||||||
|
if !texture_rect:
|
||||||
|
texture_rect = $%PhotoTexture
|
||||||
|
texture_rect.texture = texture
|
||||||
1
core/photo_mode/ui/photo.gd.uid
Normal file
1
core/photo_mode/ui/photo.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dsey5dvc11vpq
|
||||||
38
core/photo_mode/ui/photo.tscn
Normal file
38
core/photo_mode/ui/photo.tscn
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
[gd_scene format=3 uid="uid://cvus62qkop3qi"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://dsey5dvc11vpq" path="res://core/photo_mode/ui/photo.gd" id="1_u0arp"]
|
||||||
|
|
||||||
|
[node name="Photo" type="Control" unique_id=201865221]
|
||||||
|
custom_minimum_size = Vector2(200, 200)
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 0
|
||||||
|
offset_right = 200.0
|
||||||
|
offset_bottom = 200.0
|
||||||
|
script = ExtResource("1_u0arp")
|
||||||
|
|
||||||
|
[node name="ColorRect" type="ColorRect" parent="." unique_id=1208008621]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_right = 200.0
|
||||||
|
offset_bottom = 200.0
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="ColorRect" unique_id=1141643525]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
theme_override_constants/margin_left = 12
|
||||||
|
theme_override_constants/margin_top = 12
|
||||||
|
theme_override_constants/margin_right = 12
|
||||||
|
theme_override_constants/margin_bottom = 12
|
||||||
|
|
||||||
|
[node name="Panel" type="PanelContainer" parent="ColorRect/MarginContainer" unique_id=1372516531]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="PhotoTexture" type="TextureRect" parent="ColorRect/MarginContainer/Panel" unique_id=506844785]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
expand_mode = 1
|
||||||
|
stretch_mode = 6
|
||||||
27
core/photo_mode/ui/photo_gallery.gd
Normal file
27
core/photo_mode/ui/photo_gallery.gd
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
@export var photo_scene: PackedScene
|
||||||
|
|
||||||
|
@onready var grid_container: GridContainer = $%PhotoGrid
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
CollectionManager.on_photo_saved.connect(_create_photo_thumbnail)
|
||||||
|
load_gallery()
|
||||||
|
|
||||||
|
func load_gallery() -> void:
|
||||||
|
for child in grid_container.get_children():
|
||||||
|
child.queue_free()
|
||||||
|
|
||||||
|
var saved_photos = CollectionManager.saved_photos
|
||||||
|
|
||||||
|
for file_path in saved_photos:
|
||||||
|
if FileAccess.file_exists(file_path):
|
||||||
|
_create_photo_thumbnail(file_path)
|
||||||
|
|
||||||
|
func _create_photo_thumbnail(file_path: String) -> void:
|
||||||
|
var image = Image.load_from_file(file_path)
|
||||||
|
if image:
|
||||||
|
var photo: Photo = photo_scene.instantiate()
|
||||||
|
var texture = ImageTexture.create_from_image(image)
|
||||||
|
photo.setup(texture)
|
||||||
|
grid_container.add_child(photo)
|
||||||
1
core/photo_mode/ui/photo_gallery.gd.uid
Normal file
1
core/photo_mode/ui/photo_gallery.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://k4iqrlkbjppl
|
||||||
50
core/photo_mode/ui/photo_gallery.tscn
Normal file
50
core/photo_mode/ui/photo_gallery.tscn
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
[gd_scene format=3 uid="uid://b6r787sik5yil"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://k4iqrlkbjppl" path="res://core/photo_mode/ui/photo_gallery.gd" id="1_bp5uf"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://cvus62qkop3qi" path="res://core/photo_mode/ui/photo.tscn" id="2_45wok"]
|
||||||
|
|
||||||
|
[node name="PhotoGallery" type="Control" unique_id=354419843]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_bp5uf")
|
||||||
|
photo_scene = ExtResource("2_45wok")
|
||||||
|
|
||||||
|
[node name="PanelContainer" type="PanelContainer" parent="." unique_id=640179265]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -350.0
|
||||||
|
offset_top = -350.0
|
||||||
|
offset_right = 350.0
|
||||||
|
offset_bottom = 350.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="PanelContainer" unique_id=125147979]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/margin_left = 12
|
||||||
|
theme_override_constants/margin_top = 12
|
||||||
|
theme_override_constants/margin_right = 12
|
||||||
|
theme_override_constants/margin_bottom = 12
|
||||||
|
|
||||||
|
[node name="ScrollContainer" type="ScrollContainer" parent="PanelContainer/MarginContainer" unique_id=348576028]
|
||||||
|
layout_mode = 2
|
||||||
|
draw_focus_border = true
|
||||||
|
|
||||||
|
[node name="PhotoGrid" type="GridContainer" parent="PanelContainer/MarginContainer/ScrollContainer" unique_id=1187865988]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 6
|
||||||
|
size_flags_vertical = 2
|
||||||
|
theme_override_constants/h_separation = 12
|
||||||
|
theme_override_constants/v_separation = 12
|
||||||
|
columns = 3
|
||||||
31
core/radio/radio.gd
Normal file
31
core/radio/radio.gd
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
extends AudioStreamPlayer
|
||||||
|
|
||||||
|
class_name Radio
|
||||||
|
|
||||||
|
@export var playlist: Array[AudioStream] = []
|
||||||
|
var current_track_index: int = 0
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
finished.connect(next_track)
|
||||||
|
|
||||||
|
func play_track(index: int = current_track_index):
|
||||||
|
if playlist.is_empty():
|
||||||
|
return
|
||||||
|
|
||||||
|
current_track_index = posmod(index, playlist.size())
|
||||||
|
stream = playlist[current_track_index]
|
||||||
|
play()
|
||||||
|
stream_paused = false
|
||||||
|
|
||||||
|
func next_track():
|
||||||
|
play_track(current_track_index + 1)
|
||||||
|
|
||||||
|
func prev_track():
|
||||||
|
play_track(current_track_index - 1)
|
||||||
|
|
||||||
|
func toggle_pause():
|
||||||
|
stream_paused = !stream_paused
|
||||||
|
|
||||||
|
func stop_radio():
|
||||||
|
stop()
|
||||||
|
stream_paused = false
|
||||||
1
core/radio/radio.gd.uid
Normal file
1
core/radio/radio.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://bwrgh6xlvhqch
|
||||||
7
core/radio/radio.tscn
Normal file
7
core/radio/radio.tscn
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[gd_scene format=3 uid="uid://cpeyt1dgrtglc"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://bwrgh6xlvhqch" path="res://core/radio/radio.gd" id="1_2akjj"]
|
||||||
|
|
||||||
|
[node name="Radio" type="AudioStreamPlayer" unique_id=1234112225]
|
||||||
|
bus = &"Music"
|
||||||
|
script = ExtResource("1_2akjj")
|
||||||
@@ -10,6 +10,10 @@ signal toggle_wind(value: bool)
|
|||||||
@warning_ignore("unused_signal")
|
@warning_ignore("unused_signal")
|
||||||
signal wind_change(value: float)
|
signal wind_change(value: float)
|
||||||
@warning_ignore("unused_signal")
|
@warning_ignore("unused_signal")
|
||||||
|
signal trigger_random_weather(duration: float)
|
||||||
|
@warning_ignore("unused_signal")
|
||||||
|
signal weather_event_changed(description: String)
|
||||||
|
@warning_ignore("unused_signal")
|
||||||
signal toggle_fireflies(value: bool)
|
signal toggle_fireflies(value: bool)
|
||||||
@warning_ignore("unused_signal")
|
@warning_ignore("unused_signal")
|
||||||
signal toggle_storm(value: bool)
|
signal toggle_storm(value: bool)
|
||||||
@@ -23,9 +27,19 @@ signal toggle_dust(value: bool)
|
|||||||
signal toggle_blur(value: bool)
|
signal toggle_blur(value: bool)
|
||||||
@warning_ignore("unused_signal")
|
@warning_ignore("unused_signal")
|
||||||
signal toggle_shadows(value: bool)
|
signal toggle_shadows(value: bool)
|
||||||
|
@warning_ignore("unused_signal")
|
||||||
|
signal toggle_fog(value: bool)
|
||||||
|
|
||||||
|
#railway signals
|
||||||
|
@warning_ignore("unused_signal")
|
||||||
|
signal update_rail_chunks()
|
||||||
|
|
||||||
#day cycle signals
|
#day cycle signals
|
||||||
@warning_ignore("unused_signal")
|
@warning_ignore("unused_signal")
|
||||||
signal toggle_pause_daytime(value: bool)
|
signal toggle_pause_daytime(value: bool)
|
||||||
@warning_ignore("unused_signal")
|
@warning_ignore("unused_signal")
|
||||||
signal day_time_changed(value: float, time_string: String)
|
signal day_time_changed(value: float, time_string: String)
|
||||||
|
@warning_ignore("unused_signal")
|
||||||
|
signal time_option_item_changed(index: int)
|
||||||
|
@warning_ignore("unused_signal")
|
||||||
|
signal day_time_option_changed(index: int)
|
||||||
|
|||||||
15
default_bus_layout.tres
Normal file
15
default_bus_layout.tres
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[gd_resource type="AudioBusLayout" format=3 uid="uid://cqvx62pwvvboj"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
bus/1/name = &"Music"
|
||||||
|
bus/1/solo = false
|
||||||
|
bus/1/mute = false
|
||||||
|
bus/1/bypass_fx = false
|
||||||
|
bus/1/volume_db = 0.0
|
||||||
|
bus/1/send = &"Master"
|
||||||
|
bus/2/name = &"SFX"
|
||||||
|
bus/2/solo = false
|
||||||
|
bus/2/mute = false
|
||||||
|
bus/2/bypass_fx = false
|
||||||
|
bus/2/volume_db = 0.0
|
||||||
|
bus/2/send = &"Master"
|
||||||
92
docs/gyms/ai/gym_ai.tscn
Normal file
92
docs/gyms/ai/gym_ai.tscn
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
[gd_scene format=3 uid="uid://dqvrhiqgkd3w1"]
|
||||||
|
|
||||||
|
[ext_resource type="PackedScene" uid="uid://clx701xdwelgx" path="res://core/ai/agents/base/ai_base.tscn" id="1_a2xtd"]
|
||||||
|
|
||||||
|
[sub_resource type="NavigationMesh" id="NavigationMesh_optuv"]
|
||||||
|
vertices = PackedVector3Array(10.984741, 0.25012434, -1.0140381, 11.234741, 0.25012434, 0.23596191, 19.484741, 0.25012434, 0.23596191, 19.484741, 0.25012434, -19.514038, 9.234741, 0.25012434, -1.0140381, -19.515259, 0.25012434, -19.514038, -19.515259, 0.25012434, -0.014038086, 8.984741, 0.25012434, -0.014038086, 10.984741, 0.25012434, 1.2359619, 19.484741, 0.25012434, 19.235962, 9.234741, 0.25012434, 1.2359619, -19.515259, 0.25012434, 19.235962)
|
||||||
|
polygons = [PackedInt32Array(1, 0, 2), PackedInt32Array(2, 0, 3), PackedInt32Array(6, 5, 4), PackedInt32Array(4, 5, 3), PackedInt32Array(3, 0, 4), PackedInt32Array(4, 7, 6), PackedInt32Array(1, 2, 8), PackedInt32Array(8, 2, 9), PackedInt32Array(6, 10, 11), PackedInt32Array(11, 10, 9), PackedInt32Array(10, 8, 9), PackedInt32Array(6, 7, 10)]
|
||||||
|
|
||||||
|
[sub_resource type="PlaneMesh" id="PlaneMesh_optuv"]
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_xtjak"]
|
||||||
|
size = Vector3(1.9942131, 0.09710693, 1.984024)
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_lmjyn"]
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_lmjyn"]
|
||||||
|
|
||||||
|
[sub_resource type="Environment" id="Environment_lmjyn"]
|
||||||
|
|
||||||
|
[node name="GymAI" type="Node3D" unique_id=868339787]
|
||||||
|
|
||||||
|
[node name="NavigationRegion3D" type="NavigationRegion3D" parent="." unique_id=774907858]
|
||||||
|
navigation_mesh = SubResource("NavigationMesh_optuv")
|
||||||
|
|
||||||
|
[node name="Floor" type="MeshInstance3D" parent="NavigationRegion3D" unique_id=1976415311]
|
||||||
|
transform = Transform3D(20, 0, 0, 0, 20, 0, 0, 0, 20, 0, -0.83473957, 0)
|
||||||
|
mesh = SubResource("PlaneMesh_optuv")
|
||||||
|
|
||||||
|
[node name="StaticBody3D" type="StaticBody3D" parent="NavigationRegion3D/Floor" unique_id=2007477719]
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="NavigationRegion3D/Floor/StaticBody3D" unique_id=1446628130]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.0036563873, -0.009703338, -0.00868988)
|
||||||
|
shape = SubResource("BoxShape3D_xtjak")
|
||||||
|
|
||||||
|
[node name="Obstacle" type="MeshInstance3D" parent="NavigationRegion3D" unique_id=710701082]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10.148018, 0.06508446, 0)
|
||||||
|
mesh = SubResource("BoxMesh_lmjyn")
|
||||||
|
|
||||||
|
[node name="StaticBody3D" type="StaticBody3D" parent="NavigationRegion3D/Obstacle" unique_id=67152580]
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="NavigationRegion3D/Obstacle/StaticBody3D" unique_id=1663742898]
|
||||||
|
shape = SubResource("BoxShape3D_lmjyn")
|
||||||
|
|
||||||
|
[node name="AIBase" parent="." unique_id=1228675528 instance=ExtResource("1_a2xtd")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.48246834, 0.21202153, 0.11262059)
|
||||||
|
|
||||||
|
[node name="Camera3D" type="Camera3D" parent="." unique_id=1148396057]
|
||||||
|
transform = Transform3D(-2.0613477e-08, 0.8818225, -0.47158146, 3.854569e-08, 0.47158146, 0.8818225, 1, -3.5527137e-15, -4.371139e-08, -18.21907, 28.71355, 0)
|
||||||
|
|
||||||
|
[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=1772424900]
|
||||||
|
environment = SubResource("Environment_lmjyn")
|
||||||
|
|
||||||
|
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=269230449]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 0.17952333, 0.98375374, 0, -0.98375374, 0.17952333, 0, 18.920979, 0)
|
||||||
|
|
||||||
|
[node name="Control" type="Control" parent="." unique_id=1072240389]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="PanelContainer" type="PanelContainer" parent="Control" unique_id=1647272132]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_left = 50.0
|
||||||
|
offset_top = 50.0
|
||||||
|
offset_right = 400.0
|
||||||
|
offset_bottom = 827.0
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="Control/PanelContainer" unique_id=272421245]
|
||||||
|
custom_minimum_size = Vector2(1, 1)
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 1
|
||||||
|
text = "System Logic:
|
||||||
|
- The NPC uses a finite state machine to switch between behaviors.
|
||||||
|
- State logic runs during physics updates, while movement is handled by the agent through NavigationAgent3D.
|
||||||
|
|
||||||
|
AI States:
|
||||||
|
- IdleState: The agent waits in place for the duration defined by wait_time.
|
||||||
|
- PatrolState: The agent selects a valid random destination and moves toward it.
|
||||||
|
|
||||||
|
Core Components:
|
||||||
|
- NavigationAgent3D: Calculates the path and reports when the destination has been reached.
|
||||||
|
- PatrolRadiusShape: Defines the random movement area used when choosing the next patrol point.
|
||||||
|
- StateMachine: Initializes the available states and handles transitions between them.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
- Speed: Movement speed of the agent.
|
||||||
|
- Wait Time: Delay in seconds on the IdleState node.
|
||||||
|
- Area Radius: Radius of the SphereShape3D used by PatrolRadiusShape."
|
||||||
|
autowrap_mode = 2
|
||||||
7
docs/gyms/photo_mode/gym_photo_mode.gd
Normal file
7
docs/gyms/photo_mode/gym_photo_mode.gd
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
extends Node3D
|
||||||
|
|
||||||
|
@onready var gallery: Control = $%Gallery
|
||||||
|
|
||||||
|
|
||||||
|
func _on_button_gallery_pressed() -> void:
|
||||||
|
gallery.visible = !gallery.visible
|
||||||
1
docs/gyms/photo_mode/gym_photo_mode.gd.uid
Normal file
1
docs/gyms/photo_mode/gym_photo_mode.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://7oglx4br38d5
|
||||||
138
docs/gyms/photo_mode/gym_photo_mode.tscn
Normal file
138
docs/gyms/photo_mode/gym_photo_mode.tscn
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
[gd_scene format=3 uid="uid://bwc8slnbu7dmn"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://7oglx4br38d5" path="res://docs/gyms/photo_mode/gym_photo_mode.gd" id="1_cl1h5"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://vni5kjalum6d" path="res://core/photo_mode/runtime/photo_mode_controller.tscn" id="2_q5kgc"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://bmkxt6btcx8qr" path="res://core/photo_mode/runtime/collectible.tscn" id="3_734hf"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://c3grftlmap4q5" path="res://tgcc/chunk/prop/tree/leaf1_alpha.png" id="4_00joj"]
|
||||||
|
[ext_resource type="Script" uid="uid://bj34o0org55ei" path="res://core/photo_mode/data/collectible_resource.gd" id="5_crfij"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://bvw086glfpcba" path="res://core/photo_mode/ui/collectible_gallery.tscn" id="6_6aab5"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://b6r787sik5yil" path="res://core/photo_mode/ui/photo_gallery.tscn" id="7_tb1ii"]
|
||||||
|
|
||||||
|
[sub_resource type="Environment" id="Environment_48mla"]
|
||||||
|
|
||||||
|
[sub_resource type="PlaneMesh" id="PlaneMesh_hh1ka"]
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_ynvi2"]
|
||||||
|
size = Vector3(1.9942131, 0.09710693, 1.984024)
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_ynvi2"]
|
||||||
|
script = ExtResource("5_crfij")
|
||||||
|
id = &"gatto"
|
||||||
|
title = "Gatto"
|
||||||
|
image = ExtResource("4_00joj")
|
||||||
|
metadata/_custom_type_script = "uid://bj34o0org55ei"
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_hh1ka"]
|
||||||
|
|
||||||
|
[node name="GymPhotoMode" type="Node3D" unique_id=1314600330]
|
||||||
|
script = ExtResource("1_cl1h5")
|
||||||
|
|
||||||
|
[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=213183287]
|
||||||
|
environment = SubResource("Environment_48mla")
|
||||||
|
|
||||||
|
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=1274975837]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 0.17952333, 0.98375374, 0, -0.98375374, 0.17952333, 0, 18.920979, 0)
|
||||||
|
|
||||||
|
[node name="Floor" type="MeshInstance3D" parent="." unique_id=958865480]
|
||||||
|
transform = Transform3D(20, 0, 0, 0, 20, 0, 0, 0, 20, 0, -0.83473957, 0)
|
||||||
|
mesh = SubResource("PlaneMesh_hh1ka")
|
||||||
|
|
||||||
|
[node name="StaticBody3D" type="StaticBody3D" parent="Floor" unique_id=2096983240]
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="Floor/StaticBody3D" unique_id=188185045]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.0036563873, -0.009703338, -0.00868988)
|
||||||
|
shape = SubResource("BoxShape3D_ynvi2")
|
||||||
|
|
||||||
|
[node name="PhotoModeController" parent="." unique_id=695158870 node_paths=PackedStringArray("rotation_target") instance=ExtResource("2_q5kgc")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 0.49999994, 0.8660254, 0, -0.8660254, 0.49999994, 0, 30, 20)
|
||||||
|
movement_bounds = AABB(-5, -5, -5, 10, 10, 10)
|
||||||
|
rotation_target = NodePath("../Node3D")
|
||||||
|
|
||||||
|
[node name="Node3D" type="Node3D" parent="." unique_id=570786250]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 10, 0)
|
||||||
|
|
||||||
|
[node name="Node3D2" type="Node3D" parent="." unique_id=15037296]
|
||||||
|
|
||||||
|
[node name="Collectible" parent="Node3D2" unique_id=1229019813 instance=ExtResource("3_734hf")]
|
||||||
|
collectible_data = SubResource("Resource_ynvi2")
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="Node3D2" unique_id=553040412]
|
||||||
|
mesh = SubResource("BoxMesh_hh1ka")
|
||||||
|
|
||||||
|
[node name="Control" type="Control" parent="." unique_id=1802496396]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
mouse_filter = 2
|
||||||
|
|
||||||
|
[node name="ButtonGallery" type="Button" parent="Control" unique_id=539195532]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_left = 50.0
|
||||||
|
offset_top = 50.0
|
||||||
|
offset_right = 163.0
|
||||||
|
offset_bottom = 81.0
|
||||||
|
text = "Menu"
|
||||||
|
|
||||||
|
[node name="Gallery" type="HSplitContainer" parent="Control" unique_id=1388833682]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
visible = false
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_left = 420.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="CollectibleGallery" parent="Control/Gallery" unique_id=354419843 instance=ExtResource("6_6aab5")]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
|
[node name="PhotoGallery" parent="Control/Gallery" unique_id=263414560 instance=ExtResource("7_tb1ii")]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
|
[node name="PanelContainer" type="PanelContainer" parent="Control" unique_id=2015953740]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_left = 50.0
|
||||||
|
offset_top = 150.0
|
||||||
|
offset_right = 400.0
|
||||||
|
offset_bottom = 927.0
|
||||||
|
|
||||||
|
[node name="ScrollContainer" type="ScrollContainer" parent="Control/PanelContainer" unique_id=1474258594]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="Control/PanelContainer/ScrollContainer" unique_id=1982569320]
|
||||||
|
custom_minimum_size = Vector2(1, 1)
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
text = "System Logic:
|
||||||
|
- The system allows players to toggle a free camera mode to photograph and collect museum items.
|
||||||
|
- Game Pause: Activating the mode pauses the SceneTree, freezing the world while allowing the camera to remain functional.
|
||||||
|
- Taking a photo saves the captured image to disk and checks which collectibles are visible and unobstructed before unlocking them.
|
||||||
|
- CollectionManager acts as a global singleton that tracks unlocked collectibles, saved photos, and the data used by the UI.
|
||||||
|
|
||||||
|
Photo Mode Actions:
|
||||||
|
- Toggle Mode(P): Switches between normal gameplay and the photo camera, capturing or releasing the mouse, and toggles the global pause state.
|
||||||
|
- Rotate(Mouse): The camera orbits around the configured target while photo mode is active.
|
||||||
|
- Pan(Input Actions): The camera can be moved horizontally and vertically within the configured bounds.
|
||||||
|
- Capture(F): Saves the current frame and performs frustum and raycast checks against collectibles in view.
|
||||||
|
|
||||||
|
Core Components:
|
||||||
|
- PhotoModeController: Manages camera inputs, movement logic, and the photo-taking process.
|
||||||
|
- Collectible: An Area3D node placed on objects to make them identifiable by the camera.
|
||||||
|
- CollectionManager: Handles the logic for unlocking items and provides data to the UI.
|
||||||
|
- CollectibleGallery: Displays all collectibles and visually highlights the unlocked ones.
|
||||||
|
- PhotoGallery: Displays the photos saved by the player during the session.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
- Pan & Rotation Speed: Defines how fast the camera moves and rotates.
|
||||||
|
- Movement Bounds: An AABB that restricts the camera's panning area.
|
||||||
|
- Collectible Data: Resource files containing the ID, title, and image for each item.
|
||||||
|
- Library: A central list of all CollectibleResources registered in the game."
|
||||||
|
autowrap_mode = 2
|
||||||
|
|
||||||
|
[connection signal="pressed" from="Control/ButtonGallery" to="." method="_on_button_gallery_pressed"]
|
||||||
35
docs/gyms/radio/gym_radio.gd
Normal file
35
docs/gyms/radio/gym_radio.gd
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
extends Node3D
|
||||||
|
|
||||||
|
@onready var radio: Radio = $%Radio
|
||||||
|
@onready var button_pause_resume: Button = $%Button_Pause_Resume
|
||||||
|
@onready var settings_menu: SettingsMenu = $%SettingsMenu
|
||||||
|
|
||||||
|
func _on_button_play_pressed() -> void:
|
||||||
|
if !radio.playing:
|
||||||
|
radio.play_track()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_button_pause_pressed() -> void:
|
||||||
|
radio.toggle_pause()
|
||||||
|
if !button_pause_resume:
|
||||||
|
button_pause_resume = $%Button_Pause_Resume
|
||||||
|
if radio.stream_paused:
|
||||||
|
button_pause_resume.text = "Resume"
|
||||||
|
else:
|
||||||
|
button_pause_resume.text = "Pause"
|
||||||
|
|
||||||
|
|
||||||
|
func _on_button_stop_pressed() -> void:
|
||||||
|
radio.stop_radio()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_button_next_pressed() -> void:
|
||||||
|
radio.next_track()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_button_previous_pressed() -> void:
|
||||||
|
radio.prev_track()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_button_settings_menu_pressed() -> void:
|
||||||
|
settings_menu.visible = !settings_menu.visible
|
||||||
1
docs/gyms/radio/gym_radio.gd.uid
Normal file
1
docs/gyms/radio/gym_radio.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://ew4b78u5tkiu
|
||||||
104
docs/gyms/radio/gym_radio.tscn
Normal file
104
docs/gyms/radio/gym_radio.tscn
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
[gd_scene format=3 uid="uid://bdkdhn1oallke"]
|
||||||
|
|
||||||
|
[ext_resource type="PackedScene" uid="uid://cpeyt1dgrtglc" path="res://core/radio/radio.tscn" id="1_8yomj"]
|
||||||
|
[ext_resource type="Script" uid="uid://ew4b78u5tkiu" path="res://docs/gyms/radio/gym_radio.gd" id="1_h5r8c"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://70cc8she43re" path="res://docs/gyms/radio/lofi_01.ogg" id="3_ltpvc"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://caqf471x0kttc" path="res://core/audio/settings/settings_menu.tscn" id="4_8pw2j"]
|
||||||
|
|
||||||
|
[node name="GymRadio" type="Node3D" unique_id=204859062]
|
||||||
|
script = ExtResource("1_h5r8c")
|
||||||
|
|
||||||
|
[node name="Radio" parent="." unique_id=1234112225 instance=ExtResource("1_8yomj")]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
playlist = Array[AudioStream]([ExtResource("3_ltpvc")])
|
||||||
|
|
||||||
|
[node name="Control" type="Control" parent="." unique_id=1232082176]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="SettingsMenu" parent="Control" unique_id=1639777294 instance=ExtResource("4_8pw2j")]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
visible = false
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
|
||||||
|
[node name="VBoxContainer2" type="VBoxContainer" parent="Control" unique_id=2092627240]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 9
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_right = 229.0
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="Control/VBoxContainer2" unique_id=2097365775]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Button_Play" type="Button" parent="Control/VBoxContainer2/VBoxContainer" unique_id=1422696340]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Play"
|
||||||
|
|
||||||
|
[node name="Button_Pause_Resume" type="Button" parent="Control/VBoxContainer2/VBoxContainer" unique_id=2016690081]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Pause"
|
||||||
|
|
||||||
|
[node name="Button_Stop" type="Button" parent="Control/VBoxContainer2/VBoxContainer" unique_id=61861870]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Stop"
|
||||||
|
|
||||||
|
[node name="Button_Next" type="Button" parent="Control/VBoxContainer2/VBoxContainer" unique_id=957606385]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Next"
|
||||||
|
|
||||||
|
[node name="Button_Previous" type="Button" parent="Control/VBoxContainer2/VBoxContainer" unique_id=929072518]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Previous"
|
||||||
|
|
||||||
|
[node name="Button_SettingsMenu" type="Button" parent="Control/VBoxContainer2/VBoxContainer" unique_id=431867154]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "SettingsMenu"
|
||||||
|
|
||||||
|
[node name="PanelContainer" type="PanelContainer" parent="Control/VBoxContainer2" unique_id=1558442050]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="ScrollContainer" type="ScrollContainer" parent="Control/VBoxContainer2/PanelContainer" unique_id=7789304]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="Control/VBoxContainer2/PanelContainer/ScrollContainer" unique_id=2043293564]
|
||||||
|
custom_minimum_size = Vector2(1, 1)
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 1
|
||||||
|
text = "System Logic:
|
||||||
|
- The system is an extension of AudioStreamPlayer designed to manage sequential audio playback.
|
||||||
|
- It automatically triggers the next track in the sequence when the current one finishes via the finished signal.
|
||||||
|
|
||||||
|
Core Functionality:
|
||||||
|
- Playlist Management: Stores a list of AudioStream resources and tracks the current song index.
|
||||||
|
- Track Navigation: Allows cycling forward and backward through the playlist with index wrapping (loops back to start/end).
|
||||||
|
- Playback Control: Supports jumping to specific tracks, toggling the pause state, and stopping the stream.
|
||||||
|
- Audio Settings: If the Music bus exists, the Settings menu can be used to test and adjust playback volume.
|
||||||
|
|
||||||
|
Key Methods:
|
||||||
|
- play_track: Loads a specific stream from the playlist and begins playback.
|
||||||
|
- next_track / prev_track: Increments or decrements the index to navigate the playlist.
|
||||||
|
- toggle_pause: Resumes or pauses the current stream without resetting its position.
|
||||||
|
|
||||||
|
Adjustable Parameters:
|
||||||
|
- Playlist: An Array in the inspector where you can assign one or more AudioStream resources."
|
||||||
|
autowrap_mode = 2
|
||||||
|
|
||||||
|
[connection signal="pressed" from="Control/VBoxContainer2/VBoxContainer/Button_Play" to="." method="_on_button_play_pressed"]
|
||||||
|
[connection signal="pressed" from="Control/VBoxContainer2/VBoxContainer/Button_Pause_Resume" to="." method="_on_button_pause_pressed"]
|
||||||
|
[connection signal="pressed" from="Control/VBoxContainer2/VBoxContainer/Button_Stop" to="." method="_on_button_stop_pressed"]
|
||||||
|
[connection signal="pressed" from="Control/VBoxContainer2/VBoxContainer/Button_Next" to="." method="_on_button_next_pressed"]
|
||||||
|
[connection signal="pressed" from="Control/VBoxContainer2/VBoxContainer/Button_Previous" to="." method="_on_button_previous_pressed"]
|
||||||
|
[connection signal="pressed" from="Control/VBoxContainer2/VBoxContainer/Button_SettingsMenu" to="." method="_on_button_settings_menu_pressed"]
|
||||||
BIN
docs/gyms/radio/lofi_01.ogg
Normal file
BIN
docs/gyms/radio/lofi_01.ogg
Normal file
Binary file not shown.
19
docs/gyms/radio/lofi_01.ogg.import
Normal file
19
docs/gyms/radio/lofi_01.ogg.import
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="oggvorbisstr"
|
||||||
|
type="AudioStreamOggVorbis"
|
||||||
|
uid="uid://70cc8she43re"
|
||||||
|
path="res://.godot/imported/lofi_01.ogg-0aacd597266806080412021811923091.oggvorbisstr"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://docs/gyms/radio/lofi_01.ogg"
|
||||||
|
dest_files=["res://.godot/imported/lofi_01.ogg-0aacd597266806080412021811923091.oggvorbisstr"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
loop=false
|
||||||
|
loop_offset=0
|
||||||
|
bpm=0
|
||||||
|
beat_count=0
|
||||||
|
bar_beats=4
|
||||||
@@ -8,12 +8,13 @@
|
|||||||
[ext_resource type="Script" uid="uid://wv6kcqkibium" path="res://core/biome_generator/biome.gd" id="5_2wjys"]
|
[ext_resource type="Script" uid="uid://wv6kcqkibium" path="res://core/biome_generator/biome.gd" id="5_2wjys"]
|
||||||
[ext_resource type="PackedScene" uid="uid://cv5xmnow451kl" path="res://core/camera.tscn" id="5_8tojn"]
|
[ext_resource type="PackedScene" uid="uid://cv5xmnow451kl" path="res://core/camera.tscn" id="5_8tojn"]
|
||||||
[ext_resource type="PackedScene" uid="uid://crlk31ecl480n" path="res://tgcc/chunk/countryside/scene/chunk_country_corner_03.tscn" id="6_21usy"]
|
[ext_resource type="PackedScene" uid="uid://crlk31ecl480n" path="res://tgcc/chunk/countryside/scene/chunk_country_corner_03.tscn" id="6_21usy"]
|
||||||
[ext_resource type="Script" uid="uid://dboerd4a6dwj7" path="res://docs/museums/biome_generator/rails.gd" id="6_pypsn"]
|
[ext_resource type="Script" uid="uid://dboerd4a6dwj7" path="res://core/biome_generator/rails.gd" id="6_pypsn"]
|
||||||
[ext_resource type="PackedScene" uid="uid://dvk3bytqn3m5s" path="res://tgcc/train/main_train.tscn" id="6_wjpfq"]
|
[ext_resource type="PackedScene" uid="uid://dvk3bytqn3m5s" path="res://tgcc/train/main_train.tscn" id="6_wjpfq"]
|
||||||
[ext_resource type="PackedScene" uid="uid://brpp7fe5noq8v" path="res://tgcc/chunk/countryside/scene/chunk_country_cross_3_01.tscn" id="7_qe84w"]
|
[ext_resource type="PackedScene" uid="uid://brpp7fe5noq8v" path="res://tgcc/chunk/countryside/scene/chunk_country_cross_3_01.tscn" id="7_qe84w"]
|
||||||
[ext_resource type="PackedScene" uid="uid://0kgjaqijaqku" path="res://docs/museums/biome_generator/rails.tscn" id="8_mb5yv"]
|
[ext_resource type="PackedScene" uid="uid://0kgjaqijaqku" path="res://docs/museums/biome_generator/rails.tscn" id="8_mb5yv"]
|
||||||
[ext_resource type="PackedScene" uid="uid://dn1btv0e0ses7" path="res://core/fireworks.tscn" id="8_xtogr"]
|
[ext_resource type="PackedScene" uid="uid://dn1btv0e0ses7" path="res://core/fireworks.tscn" id="8_xtogr"]
|
||||||
[ext_resource type="PackedScene" uid="uid://cu2chsjh8wuvp" path="res://tgcc/chunk/countryside/scene/chunk_country_straight_02.tscn" id="9_sw7bt"]
|
[ext_resource type="PackedScene" uid="uid://cu2chsjh8wuvp" path="res://tgcc/chunk/countryside/scene/chunk_country_straight_02.tscn" id="9_sw7bt"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://c73yk6858dmwn" path="res://tgcc/chunk/countryside/scene/chunk_country_cross_4_01.tscn" id="10_c7mkj"]
|
||||||
[ext_resource type="PackedScene" uid="uid://cmuvmmp7xam4o" path="res://core/daynight/environment_management.tscn" id="16_c7mkj"]
|
[ext_resource type="PackedScene" uid="uid://cmuvmmp7xam4o" path="res://core/daynight/environment_management.tscn" id="16_c7mkj"]
|
||||||
[ext_resource type="AudioStream" uid="uid://dvabvoqyya0g5" path="res://core/daynight/sounds/thunder_3.mp3" id="17_sw7bt"]
|
[ext_resource type="AudioStream" uid="uid://dvabvoqyya0g5" path="res://core/daynight/sounds/thunder_3.mp3" id="17_sw7bt"]
|
||||||
[ext_resource type="AudioStream" uid="uid://creenugno7hm" path="res://core/daynight/sounds/thunder_4.mp3" id="18_2l6dd"]
|
[ext_resource type="AudioStream" uid="uid://creenugno7hm" path="res://core/daynight/sounds/thunder_4.mp3" id="18_2l6dd"]
|
||||||
@@ -100,7 +101,7 @@ compositor_effects = Array[CompositorEffect]([SubResource("CompositorEffect_q52t
|
|||||||
[sub_resource type="Resource" id="Resource_3qrd0"]
|
[sub_resource type="Resource" id="Resource_3qrd0"]
|
||||||
script = ExtResource("5_2wjys")
|
script = ExtResource("5_2wjys")
|
||||||
name = "countryside"
|
name = "countryside"
|
||||||
available_chunks = Array[PackedScene]([ExtResource("6_21usy"), ExtResource("7_qe84w"), ExtResource("9_sw7bt")])
|
available_chunks = Array[PackedScene]([ExtResource("6_21usy"), ExtResource("7_qe84w"), ExtResource("9_sw7bt"), ExtResource("10_c7mkj")])
|
||||||
metadata/_custom_type_script = "uid://wv6kcqkibium"
|
metadata/_custom_type_script = "uid://wv6kcqkibium"
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_pypsn"]
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_pypsn"]
|
||||||
@@ -178,10 +179,10 @@ script = ExtResource("23_27ile")
|
|||||||
|
|
||||||
[node name="Snow" type="CheckButton" parent="Control" unique_id=454394427]
|
[node name="Snow" type="CheckButton" parent="Control" unique_id=454394427]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 21.0
|
offset_left = 8.0
|
||||||
offset_top = 13.0
|
offset_top = 173.0
|
||||||
offset_right = 109.0
|
offset_right = 98.0
|
||||||
offset_bottom = 44.0
|
offset_bottom = 204.0
|
||||||
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_focus_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_focus_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
|
||||||
@@ -192,10 +193,10 @@ text = "Snow"
|
|||||||
|
|
||||||
[node name="Rain" type="CheckButton" parent="Control" unique_id=837805524]
|
[node name="Rain" type="CheckButton" parent="Control" unique_id=837805524]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 21.0
|
offset_left = 8.0
|
||||||
offset_top = 41.0
|
offset_top = 201.0
|
||||||
offset_right = 109.0
|
offset_right = 96.0
|
||||||
offset_bottom = 72.0
|
offset_bottom = 232.0
|
||||||
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_focus_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_focus_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
|
||||||
@@ -206,10 +207,10 @@ text = "Rain"
|
|||||||
|
|
||||||
[node name="Wind" type="CheckButton" parent="Control" unique_id=1013004982]
|
[node name="Wind" type="CheckButton" parent="Control" unique_id=1013004982]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 21.0
|
offset_left = 8.0
|
||||||
offset_top = 91.0
|
offset_top = 231.0
|
||||||
offset_right = 109.0
|
offset_right = 96.0
|
||||||
offset_bottom = 122.0
|
offset_bottom = 262.0
|
||||||
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_focus_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_focus_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
|
||||||
@@ -220,19 +221,19 @@ text = "Wind"
|
|||||||
|
|
||||||
[node name="WindSlider" type="HSlider" parent="Control" unique_id=28050098]
|
[node name="WindSlider" type="HSlider" parent="Control" unique_id=28050098]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 26.0
|
offset_left = 103.0
|
||||||
offset_top = 124.0
|
offset_top = 238.0
|
||||||
offset_right = 205.0
|
offset_right = 187.0
|
||||||
offset_bottom = 140.0
|
offset_bottom = 254.0
|
||||||
max_value = 1.0
|
max_value = 1.0
|
||||||
step = 0.01
|
step = 0.01
|
||||||
|
|
||||||
[node name="Fireflies" type="CheckButton" parent="Control" unique_id=1046228444]
|
[node name="Fireflies" type="CheckButton" parent="Control" unique_id=1046228444]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 21.0
|
offset_left = 8.0
|
||||||
offset_top = 169.0
|
offset_top = 259.0
|
||||||
offset_right = 130.0
|
offset_right = 117.0
|
||||||
offset_bottom = 200.0
|
offset_bottom = 290.0
|
||||||
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_focus_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_focus_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
|
||||||
@@ -243,10 +244,10 @@ text = "Fireflies"
|
|||||||
|
|
||||||
[node name="Storm" type="CheckButton" parent="Control" unique_id=1792625744]
|
[node name="Storm" type="CheckButton" parent="Control" unique_id=1792625744]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 21.0
|
offset_left = 98.0
|
||||||
offset_top = 66.0
|
offset_top = 201.0
|
||||||
offset_right = 117.0
|
offset_right = 194.0
|
||||||
offset_bottom = 97.0
|
offset_bottom = 232.0
|
||||||
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_focus_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_focus_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
|
||||||
@@ -257,73 +258,88 @@ text = "Storm"
|
|||||||
|
|
||||||
[node name="DayTimeLabel" type="Label" parent="Control" unique_id=1124935856]
|
[node name="DayTimeLabel" type="Label" parent="Control" unique_id=1124935856]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 26.0
|
offset_left = 13.0
|
||||||
offset_top = 150.0
|
offset_top = 15.0
|
||||||
offset_right = 360.0
|
offset_right = 347.0
|
||||||
offset_bottom = 173.0
|
offset_bottom = 38.0
|
||||||
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_outline_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_outline_color = Color(1, 1, 1, 1)
|
||||||
text = "Time 00:00"
|
text = "Time 00:00"
|
||||||
|
|
||||||
[node name="DayTimeSlider" type="HSlider" parent="Control" unique_id=1865778345]
|
[node name="DayTimeSlider" type="HSlider" parent="Control" unique_id=1865778345]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 26.0
|
offset_left = 13.0
|
||||||
offset_top = 228.0
|
offset_top = 40.0
|
||||||
offset_right = 205.0
|
offset_right = 138.0
|
||||||
offset_bottom = 244.0
|
offset_bottom = 56.0
|
||||||
max_value = 1.0
|
max_value = 1.0
|
||||||
step = 0.01
|
step = 0.01
|
||||||
|
|
||||||
|
[node name="DayTimeOptions" type="OptionButton" parent="Control" unique_id=928646468]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_left = 13.0
|
||||||
|
offset_top = 59.0
|
||||||
|
offset_right = 124.0
|
||||||
|
offset_bottom = 90.0
|
||||||
|
selected = 1
|
||||||
|
item_count = 4
|
||||||
|
popup/item_0/text = "Sunrise"
|
||||||
|
popup/item_0/id = 1
|
||||||
|
popup/item_1/text = "Day"
|
||||||
|
popup/item_1/id = 2
|
||||||
|
popup/item_2/text = "Sunset"
|
||||||
|
popup/item_2/id = 3
|
||||||
|
popup/item_3/text = "Night"
|
||||||
|
popup/item_3/id = 4
|
||||||
|
|
||||||
[node name="Dust" type="CheckButton" parent="Control" unique_id=760281365]
|
[node name="Dust" type="CheckButton" parent="Control" unique_id=760281365]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 21.0
|
offset_left = 8.0
|
||||||
offset_top = 304.0
|
offset_top = 91.0
|
||||||
offset_right = 150.0
|
offset_right = 137.0
|
||||||
offset_bottom = 335.0
|
offset_bottom = 122.0
|
||||||
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_focus_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_focus_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_hover_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_hover_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_hover_pressed_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_hover_pressed_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_outline_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_outline_color = Color(1, 1, 1, 1)
|
||||||
button_pressed = true
|
|
||||||
text = "Dust"
|
text = "Dust"
|
||||||
|
|
||||||
[node name="Blur" type="CheckButton" parent="Control" unique_id=1083708100]
|
[node name="Blur" type="CheckButton" parent="Control" unique_id=1083708100]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 21.0
|
offset_left = 8.0
|
||||||
offset_top = 332.0
|
offset_top = 118.0
|
||||||
offset_right = 150.0
|
offset_right = 137.0
|
||||||
offset_bottom = 363.0
|
offset_bottom = 149.0
|
||||||
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_focus_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_focus_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_hover_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_hover_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_hover_pressed_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_hover_pressed_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_outline_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_outline_color = Color(1, 1, 1, 1)
|
||||||
button_pressed = true
|
|
||||||
text = "Blur"
|
text = "Blur"
|
||||||
|
|
||||||
[node name="Pause" type="CheckButton" parent="Control" unique_id=1587043871]
|
[node name="Pause" type="CheckButton" parent="Control" unique_id=1587043871]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 21.0
|
offset_left = 143.0
|
||||||
offset_top = 243.0
|
offset_top = 31.0
|
||||||
offset_right = 158.0
|
offset_right = 238.0
|
||||||
offset_bottom = 274.0
|
offset_bottom = 62.0
|
||||||
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_focus_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_focus_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_hover_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_hover_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_hover_pressed_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_hover_pressed_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_outline_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_outline_color = Color(1, 1, 1, 1)
|
||||||
text = "Pause Time"
|
text = "Pause"
|
||||||
|
|
||||||
[node name="Shadows" type="CheckButton" parent="Control" unique_id=283354318]
|
[node name="Shadows" type="CheckButton" parent="Control" unique_id=283354318]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 21.0
|
offset_left = 8.0
|
||||||
offset_top = 356.0
|
offset_top = 145.0
|
||||||
offset_right = 150.0
|
offset_right = 137.0
|
||||||
offset_bottom = 387.0
|
offset_bottom = 176.0
|
||||||
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_focus_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_focus_color = Color(1, 1, 1, 1)
|
||||||
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
|
||||||
@@ -333,20 +349,29 @@ theme_override_colors/font_outline_color = Color(1, 1, 1, 1)
|
|||||||
button_pressed = true
|
button_pressed = true
|
||||||
text = "Shadows"
|
text = "Shadows"
|
||||||
|
|
||||||
[node name="Guide" type="Label" parent="Control" unique_id=2121474959]
|
[node name="RandomWeather" type="Button" parent="Control" unique_id=1047710802]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 26.0
|
offset_left = 12.0
|
||||||
offset_top = 401.0
|
offset_top = 289.0
|
||||||
offset_right = 339.0
|
offset_right = 157.0
|
||||||
offset_bottom = 606.0
|
offset_bottom = 320.0
|
||||||
text = "R-> Reset isometric camera
|
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
||||||
C-> Toggle cinematic mode
|
theme_override_colors/font_focus_color = Color(1, 1, 1, 1)
|
||||||
Z-> soft zoom
|
theme_override_colors/font_pressed_color = Color(1, 1, 1, 1)
|
||||||
Manual controls (1-5)
|
theme_override_colors/font_hover_color = Color(1, 1, 1, 1)
|
||||||
T -> go to next stop
|
theme_override_colors/font_hover_pressed_color = Color(1, 1, 1, 1)
|
||||||
F -> fireworks
|
theme_override_colors/font_outline_color = Color(1, 1, 1, 1)
|
||||||
BACKSPACE -> stop train
|
text = "Random Weather (10\")"
|
||||||
ARROW UP/DOWN -> change train speed"
|
|
||||||
|
[node name="WeatherEventLabel" type="Label" parent="Control" unique_id=641424797]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_left = 1656.0
|
||||||
|
offset_top = 11.0
|
||||||
|
offset_right = 1908.0
|
||||||
|
offset_bottom = 34.0
|
||||||
|
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
||||||
|
theme_override_colors/font_outline_color = Color(1, 1, 1, 1)
|
||||||
|
text = "Weather: Clear"
|
||||||
|
|
||||||
[connection signal="toggled" from="Control/Snow" to="Control" method="_on_snow_toggled"]
|
[connection signal="toggled" from="Control/Snow" to="Control" method="_on_snow_toggled"]
|
||||||
[connection signal="toggled" from="Control/Rain" to="Control" method="_on_rain_toggled"]
|
[connection signal="toggled" from="Control/Rain" to="Control" method="_on_rain_toggled"]
|
||||||
@@ -355,7 +380,9 @@ ARROW UP/DOWN -> change train speed"
|
|||||||
[connection signal="toggled" from="Control/Fireflies" to="Control" method="_on_fireflies_toggled"]
|
[connection signal="toggled" from="Control/Fireflies" to="Control" method="_on_fireflies_toggled"]
|
||||||
[connection signal="toggled" from="Control/Storm" to="Control" method="_on_storm_toggled"]
|
[connection signal="toggled" from="Control/Storm" to="Control" method="_on_storm_toggled"]
|
||||||
[connection signal="value_changed" from="Control/DayTimeSlider" to="Control" method="_on_day_time_slider_value_changed"]
|
[connection signal="value_changed" from="Control/DayTimeSlider" to="Control" method="_on_day_time_slider_value_changed"]
|
||||||
|
[connection signal="item_selected" from="Control/DayTimeOptions" to="Control" method="_on_option_button_item_selected"]
|
||||||
[connection signal="toggled" from="Control/Dust" to="Control" method="_on_dust_toggled"]
|
[connection signal="toggled" from="Control/Dust" to="Control" method="_on_dust_toggled"]
|
||||||
[connection signal="toggled" from="Control/Blur" to="Control" method="_on_blur_toggled"]
|
[connection signal="toggled" from="Control/Blur" to="Control" method="_on_blur_toggled"]
|
||||||
[connection signal="toggled" from="Control/Pause" to="Control" method="_on_pause_toggled"]
|
[connection signal="toggled" from="Control/Pause" to="Control" method="_on_pause_toggled"]
|
||||||
[connection signal="toggled" from="Control/Shadows" to="Control" method="_on_shadows_toggled"]
|
[connection signal="toggled" from="Control/Shadows" to="Control" method="_on_shadows_toggled"]
|
||||||
|
[connection signal="pressed" from="Control/RandomWeather" to="Control" method="_on_random_weather_pressed"]
|
||||||
|
|||||||
457
docs/museums/biome_generator/museum_map.tscn
Normal file
457
docs/museums/biome_generator/museum_map.tscn
Normal file
File diff suppressed because one or more lines are too long
@@ -1,156 +1,8 @@
|
|||||||
[gd_scene format=3 uid="uid://0kgjaqijaqku"]
|
[gd_scene format=3 uid="uid://0kgjaqijaqku"]
|
||||||
|
|
||||||
[ext_resource type="Shader" uid="uid://d0ch5ofrgf7y6" path="res://core/daynight/trunk_shader.gdshader" id="2_0y2rr"]
|
[ext_resource type="PackedScene" uid="uid://dtee3qewqnqpm" path="res://tgcc/train/rail.tscn" id="2_u53q0"]
|
||||||
|
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_m6haf"]
|
|
||||||
render_priority = 0
|
|
||||||
shader = ExtResource("2_0y2rr")
|
|
||||||
shader_parameter/albedo_color = Color(0.08235294, 0.105882354, 0.10980392, 1)
|
|
||||||
shader_parameter/use_texture = true
|
|
||||||
shader_parameter/uv_scale = Vector2(1, 1)
|
|
||||||
shader_parameter/palette_shift_y = 0.0
|
|
||||||
shader_parameter/gradient_start_y = 0.0
|
|
||||||
shader_parameter/gradient_end_y = 10.0
|
|
||||||
shader_parameter/light_steps = 3.0
|
|
||||||
shader_parameter/step_softness = 0.1
|
|
||||||
shader_parameter/shadow_color = Color(0.4, 0.4, 0.6, 1)
|
|
||||||
shader_parameter/shadow_offset = 0.0
|
|
||||||
shader_parameter/cast_shadow_strength = 0.6
|
|
||||||
shader_parameter/use_ghibli_glint = true
|
|
||||||
shader_parameter/glint_color = Color(1, 0.95, 0.85, 1)
|
|
||||||
shader_parameter/glint_intensity = 1.0
|
|
||||||
shader_parameter/glint_sharpness = 32.0
|
|
||||||
shader_parameter/emission_color = Color(0, 0, 0, 1)
|
|
||||||
shader_parameter/emission_energy = 0.0
|
|
||||||
|
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_duyun"]
|
|
||||||
|
|
||||||
[sub_resource type="BoxMesh" id="BoxMesh_w0ibq"]
|
|
||||||
size = Vector3(0.2, 0.2, 2)
|
|
||||||
|
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_fttrp"]
|
|
||||||
render_priority = 0
|
|
||||||
shader = ExtResource("2_0y2rr")
|
|
||||||
shader_parameter/albedo_color = Color(0.08061289, 0.10506997, 0.11154168, 1)
|
|
||||||
shader_parameter/use_texture = true
|
|
||||||
shader_parameter/uv_scale = Vector2(1, 1)
|
|
||||||
shader_parameter/palette_shift_y = 0.0
|
|
||||||
shader_parameter/gradient_start_y = 0.0
|
|
||||||
shader_parameter/gradient_end_y = 10.0
|
|
||||||
shader_parameter/light_steps = 3.0
|
|
||||||
shader_parameter/step_softness = 0.1
|
|
||||||
shader_parameter/shadow_color = Color(0.4, 0.4, 0.6, 1)
|
|
||||||
shader_parameter/shadow_offset = 0.0
|
|
||||||
shader_parameter/cast_shadow_strength = 0.6
|
|
||||||
shader_parameter/use_ghibli_glint = true
|
|
||||||
shader_parameter/glint_color = Color(1, 0.95, 0.85, 1)
|
|
||||||
shader_parameter/glint_intensity = 1.0
|
|
||||||
shader_parameter/glint_sharpness = 32.0
|
|
||||||
shader_parameter/emission_color = Color(0, 0, 0, 1)
|
|
||||||
shader_parameter/emission_energy = 0.0
|
|
||||||
|
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_hb1ej"]
|
|
||||||
|
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_pp4r2"]
|
|
||||||
render_priority = 0
|
|
||||||
shader = ExtResource("2_0y2rr")
|
|
||||||
shader_parameter/albedo_color = Color(0.2584173, 0.19781098, 0.10103748, 1)
|
|
||||||
shader_parameter/use_texture = true
|
|
||||||
shader_parameter/uv_scale = Vector2(1, 1)
|
|
||||||
shader_parameter/palette_shift_y = 0.0
|
|
||||||
shader_parameter/gradient_start_y = 0.0
|
|
||||||
shader_parameter/gradient_end_y = 10.0
|
|
||||||
shader_parameter/light_steps = 3.0
|
|
||||||
shader_parameter/step_softness = 0.1
|
|
||||||
shader_parameter/shadow_color = Color(0.4, 0.4, 0.6, 1)
|
|
||||||
shader_parameter/shadow_offset = 0.0
|
|
||||||
shader_parameter/cast_shadow_strength = 0.6
|
|
||||||
shader_parameter/use_ghibli_glint = true
|
|
||||||
shader_parameter/glint_color = Color(1, 0.95, 0.85, 1)
|
|
||||||
shader_parameter/glint_intensity = 1.0
|
|
||||||
shader_parameter/glint_sharpness = 32.0
|
|
||||||
shader_parameter/emission_color = Color(0, 0, 0, 1)
|
|
||||||
shader_parameter/emission_energy = 0.0
|
|
||||||
|
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_pur2n"]
|
|
||||||
|
|
||||||
[sub_resource type="BoxMesh" id="BoxMesh_ysg1u"]
|
|
||||||
size = Vector3(2.5, 0.15, 0.5)
|
|
||||||
|
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_x2uev"]
|
|
||||||
render_priority = 0
|
|
||||||
shader = ExtResource("2_0y2rr")
|
|
||||||
shader_parameter/albedo_color = Color(0.25882354, 0.19607843, 0.101960786, 1)
|
|
||||||
shader_parameter/use_texture = true
|
|
||||||
shader_parameter/uv_scale = Vector2(1, 1)
|
|
||||||
shader_parameter/palette_shift_y = 0.0
|
|
||||||
shader_parameter/gradient_start_y = 0.0
|
|
||||||
shader_parameter/gradient_end_y = 10.0
|
|
||||||
shader_parameter/light_steps = 3.0
|
|
||||||
shader_parameter/step_softness = 0.1
|
|
||||||
shader_parameter/shadow_color = Color(0.4, 0.4, 0.6, 1)
|
|
||||||
shader_parameter/shadow_offset = 0.0
|
|
||||||
shader_parameter/cast_shadow_strength = 0.6
|
|
||||||
shader_parameter/use_ghibli_glint = true
|
|
||||||
shader_parameter/glint_color = Color(1, 0.95, 0.85, 1)
|
|
||||||
shader_parameter/glint_intensity = 1.0
|
|
||||||
shader_parameter/glint_sharpness = 32.0
|
|
||||||
shader_parameter/emission_color = Color(0, 0, 0, 1)
|
|
||||||
shader_parameter/emission_energy = 0.0
|
|
||||||
|
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_qv8m2"]
|
|
||||||
|
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_5u2u8"]
|
|
||||||
render_priority = 0
|
|
||||||
shader = ExtResource("2_0y2rr")
|
|
||||||
shader_parameter/albedo_color = Color(0.22494644, 0.08867701, 0.01631488, 1)
|
|
||||||
shader_parameter/use_texture = false
|
|
||||||
shader_parameter/uv_scale = Vector2(1, 1)
|
|
||||||
shader_parameter/palette_shift_y = 0.0
|
|
||||||
shader_parameter/gradient_start_y = 0.0
|
|
||||||
shader_parameter/gradient_end_y = 10.0
|
|
||||||
shader_parameter/light_steps = 3.0
|
|
||||||
shader_parameter/step_softness = 0.1
|
|
||||||
shader_parameter/shadow_color = Color(0.4, 0.4, 0.6, 1)
|
|
||||||
shader_parameter/shadow_offset = 0.0
|
|
||||||
shader_parameter/cast_shadow_strength = 0.6
|
|
||||||
shader_parameter/use_ghibli_glint = true
|
|
||||||
shader_parameter/glint_color = Color(1, 0.95, 0.85, 1)
|
|
||||||
shader_parameter/glint_intensity = 1.0
|
|
||||||
shader_parameter/glint_sharpness = 32.0
|
|
||||||
shader_parameter/emission_color = Color(0, 0, 0, 1)
|
|
||||||
shader_parameter/emission_energy = 0.0
|
|
||||||
|
|
||||||
[sub_resource type="BoxMesh" id="BoxMesh_m6haf"]
|
|
||||||
size = Vector3(3.705, 0.2, 1.92)
|
|
||||||
|
|
||||||
[node name="rails" type="Node3D" unique_id=1464572050 groups=["weather_node", "wind_node"]]
|
[node name="rails" type="Node3D" unique_id=1464572050 groups=["weather_node", "wind_node"]]
|
||||||
|
|
||||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="." unique_id=1040579890]
|
[node name="rail" parent="." unique_id=651719760 instance=ExtResource("2_u53q0")]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.7, 0.214, 0)
|
transform = Transform3D(1.53, 0, 0, 0, 1.53, 0, 0, 0, 1.53, 0, 0, 0)
|
||||||
material_override = SubResource("ShaderMaterial_m6haf")
|
|
||||||
material_overlay = SubResource("ShaderMaterial_duyun")
|
|
||||||
mesh = SubResource("BoxMesh_w0ibq")
|
|
||||||
|
|
||||||
[node name="MeshInstance3D2" type="MeshInstance3D" parent="." unique_id=1870708237]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.7, 0.214, 0)
|
|
||||||
material_override = SubResource("ShaderMaterial_fttrp")
|
|
||||||
material_overlay = SubResource("ShaderMaterial_hb1ej")
|
|
||||||
mesh = SubResource("BoxMesh_w0ibq")
|
|
||||||
|
|
||||||
[node name="MeshInstance3D3" type="MeshInstance3D" parent="." unique_id=170245195]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, 0.5)
|
|
||||||
material_override = SubResource("ShaderMaterial_pp4r2")
|
|
||||||
material_overlay = SubResource("ShaderMaterial_pur2n")
|
|
||||||
mesh = SubResource("BoxMesh_ysg1u")
|
|
||||||
|
|
||||||
[node name="MeshInstance3D4" type="MeshInstance3D" parent="." unique_id=1389288735]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.05, -0.5)
|
|
||||||
material_override = SubResource("ShaderMaterial_x2uev")
|
|
||||||
material_overlay = SubResource("ShaderMaterial_qv8m2")
|
|
||||||
mesh = SubResource("BoxMesh_ysg1u")
|
|
||||||
|
|
||||||
[node name="MeshInstance3D5" type="MeshInstance3D" parent="." unique_id=1376217081]
|
|
||||||
visible = false
|
|
||||||
material_override = SubResource("ShaderMaterial_5u2u8")
|
|
||||||
mesh = SubResource("BoxMesh_m6haf")
|
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
@onready var day_night: EnvironmentManagerRoot = get_node_or_null("../DayNight") as EnvironmentManagerRoot
|
@onready var day_night: EnvironmentManagerRoot = $"../DayNight"
|
||||||
|
@onready var weather_event_label: Label = $WeatherEventLabel
|
||||||
@onready var day_time_label: Label = $DayTimeLabel
|
@onready var day_time_label: Label = $DayTimeLabel
|
||||||
@onready var day_time_slider: HSlider = $DayTimeSlider
|
@onready var day_time_slider: HSlider = $DayTimeSlider
|
||||||
@onready var wind_slider: HSlider = get_node_or_null("WindSlider") as HSlider
|
@onready var wind_slider: HSlider = $WindSlider
|
||||||
|
@onready var day_time_option: OptionButton = $DayTimeOptions
|
||||||
|
|
||||||
|
var default_random_event_duration: float = 10.0
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
UIEvents.day_time_changed.connect(_on_day_time_changed)
|
UIEvents.day_time_changed.connect(_on_day_time_changed)
|
||||||
|
UIEvents.day_time_option_changed.connect(_on_day_time_option_changed)
|
||||||
|
UIEvents.weather_event_changed.connect(_on_weather_event_changed)
|
||||||
if day_night != null and day_night.environment_config != null and wind_slider != null:
|
if day_night != null and day_night.environment_config != null and wind_slider != null:
|
||||||
wind_slider.set_value_no_signal(day_night.environment_config.wind_strength)
|
wind_slider.set_value_no_signal(day_night.environment_config.wind_strength)
|
||||||
_sync_day_time_ui()
|
_sync_day_time_ui()
|
||||||
|
_on_weather_event_changed("Weather: Clear")
|
||||||
|
|
||||||
func _on_rain_toggled(toggled_on: bool) -> void:
|
func _on_rain_toggled(toggled_on: bool) -> void:
|
||||||
UIEvents.toggle_rain.emit(toggled_on)
|
UIEvents.toggle_rain.emit(toggled_on)
|
||||||
@@ -24,6 +30,12 @@ func _on_wind_toggled(toggled_on: bool) -> void:
|
|||||||
func _on_wind_slider_value_changed(value: float) -> void:
|
func _on_wind_slider_value_changed(value: float) -> void:
|
||||||
UIEvents.wind_change.emit(value)
|
UIEvents.wind_change.emit(value)
|
||||||
|
|
||||||
|
func _on_random_weather_pressed() -> void:
|
||||||
|
var duration: float = default_random_event_duration
|
||||||
|
if day_night != null and day_night.environment_config != null:
|
||||||
|
duration = day_night.environment_config.random_event_duration
|
||||||
|
UIEvents.trigger_random_weather.emit(duration)
|
||||||
|
|
||||||
func _on_fireflies_toggled(toggled_on: bool) -> void:
|
func _on_fireflies_toggled(toggled_on: bool) -> void:
|
||||||
UIEvents.toggle_fireflies.emit(toggled_on)
|
UIEvents.toggle_fireflies.emit(toggled_on)
|
||||||
|
|
||||||
@@ -44,6 +56,10 @@ func _on_day_time_changed(value: float, time_string: String) -> void:
|
|||||||
label_text = "Time %s | nt %.3f | dt %.3f" % [time_string, value, day_night.day_time]
|
label_text = "Time %s | nt %.3f | dt %.3f" % [time_string, value, day_night.day_time]
|
||||||
day_time_label.text = label_text
|
day_time_label.text = label_text
|
||||||
|
|
||||||
|
func _on_weather_event_changed(description: String) -> void:
|
||||||
|
if weather_event_label:
|
||||||
|
weather_event_label.text = description
|
||||||
|
|
||||||
func _on_fog_overlay_toggled(toggled_on: bool) -> void:
|
func _on_fog_overlay_toggled(toggled_on: bool) -> void:
|
||||||
UIEvents.toggle_fog_overlay.emit(toggled_on)
|
UIEvents.toggle_fog_overlay.emit(toggled_on)
|
||||||
|
|
||||||
@@ -74,3 +90,20 @@ func _sync_day_time_ui() -> void:
|
|||||||
day_night_controller.current_time,
|
day_night_controller.current_time,
|
||||||
day_night_controller.get_time_string()
|
day_night_controller.get_time_string()
|
||||||
)
|
)
|
||||||
|
_on_day_time_option_changed(
|
||||||
|
day_night_controller.get_time_option_index(day_night_controller.current_time)
|
||||||
|
)
|
||||||
|
|
||||||
|
func _on_day_time_option_changed(index: int) -> void:
|
||||||
|
if day_time_option == null:
|
||||||
|
return
|
||||||
|
day_time_option.select(index)
|
||||||
|
|
||||||
|
func _on_option_button_item_selected(index: int) -> void:
|
||||||
|
UIEvents.time_option_item_changed.emit(index)
|
||||||
|
|
||||||
|
func _on_fog_toggled(toggled_on: bool) -> void:
|
||||||
|
UIEvents.toggle_fog.emit(toggled_on)
|
||||||
|
|
||||||
|
func _on_update_rails_pressed() -> void:
|
||||||
|
UIEvents.update_rail_chunks.emit()
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user