changement du scene manager, amélioration du cockpit et autres
* refonte du scene manager * refonte du audio manager * premier rework des plantes * nettoyage des dossiers/fichiers * renommage de planète en region * fix des run
This commit is contained in:
@@ -1,12 +1,11 @@
|
||||
[gd_scene load_steps=30 format=3 uid="uid://b6hscxcrj065q"]
|
||||
[gd_scene load_steps=28 format=3 uid="uid://b6hscxcrj065q"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://2p5d6vogtn82" path="res://common/audio_manager/scripts/audio_manager.gd" id="1_0tvca"]
|
||||
[ext_resource type="AudioStream" uid="uid://dipnmlprwfo12" path="res://common/audio_manager/assets/ambiance/niveau/ambiance_phase_1.ogg" id="2_a4u5m"]
|
||||
[ext_resource type="AudioStream" uid="uid://bm0tdi6bd2e65" path="res://common/audio_manager/assets/ambiance/niveau/ambiance_phase_2.ogg" id="3_8nsyr"]
|
||||
[ext_resource type="AudioStream" uid="uid://dftxjfdqgsbd3" path="res://common/audio_manager/assets/ambiance/niveau/ambiance_phase_3.ogg" id="4_athui"]
|
||||
[ext_resource type="AudioStream" uid="uid://dipnmlprwfo12" path="res://common/audio_manager/assets/ambiance/niveau/ambiance_phase_1.ogg" id="2_tuvql"]
|
||||
[ext_resource type="AudioStream" uid="uid://dcbuhtc085q2x" path="res://common/audio_manager/assets/morceaux/niveau_v2/mines_phase_1.ogg" id="5_ajci6"]
|
||||
[ext_resource type="AudioStream" uid="uid://bqwiaek5b5q00" path="res://common/audio_manager/assets/morceaux/niveau/forest_phase_2.ogg" id="6_ldyhq"]
|
||||
[ext_resource type="AudioStream" uid="uid://d4lqhgf0lhgge" path="res://common/audio_manager/assets/morceaux/niveau/forest_phase_3.ogg" id="7_ol34x"]
|
||||
[ext_resource type="AudioStream" uid="uid://bpf6witukorka" path="res://common/audio_manager/assets/morceaux/autres/main_menu.ogg" id="7_tuvql"]
|
||||
[ext_resource type="AudioStream" uid="uid://brtjlgjqnrvcb" path="res://common/audio_manager/assets/morceaux/autres/truck_music.ogg" id="8_0e5ja"]
|
||||
[ext_resource type="AudioStream" uid="uid://bnxsnege8qq6e" path="res://common/audio_manager/assets/morceaux/niveau/forest_phase_4.ogg" id="8_ajci6"]
|
||||
[ext_resource type="AudioStream" uid="uid://dfrp66a4isnt6" path="res://common/audio_manager/assets/sfx/dig/dig_1.wav" id="9_gv65y"]
|
||||
@@ -24,15 +23,6 @@
|
||||
[ext_resource type="AudioStream" uid="uid://d1cpi438ep0ys" path="res://common/audio_manager/assets/sfx/announce/annnounce.wav" id="22_btfwx"]
|
||||
[ext_resource type="AudioStream" uid="uid://ccq04ahrwr3bv" path="res://common/audio_manager/assets/sfx/alarm/alarm.wav" id="23_fwu3w"]
|
||||
|
||||
[sub_resource type="AudioStreamSynchronized" id="AudioStreamSynchronized_i5lxw"]
|
||||
stream_count = 3
|
||||
stream_0/stream = ExtResource("2_a4u5m")
|
||||
stream_0/volume = 0.0
|
||||
stream_1/stream = ExtResource("3_8nsyr")
|
||||
stream_1/volume = -60.0
|
||||
stream_2/stream = ExtResource("4_athui")
|
||||
stream_2/volume = -60.0
|
||||
|
||||
[sub_resource type="AudioStreamPlaylist" id="AudioStreamPlaylist_ajci6"]
|
||||
stream_count = 4
|
||||
stream_0 = ExtResource("5_ajci6")
|
||||
@@ -66,33 +56,32 @@ streams_count = 2
|
||||
stream_0/stream = ExtResource("20_pu6t4")
|
||||
stream_1/stream = ExtResource("21_dk5s6")
|
||||
|
||||
[node name="AudioManager" type="Node" node_paths=PackedStringArray("playing_soundtracks")]
|
||||
[node name="AudioManager" type="Node"]
|
||||
process_mode = 3
|
||||
script = ExtResource("1_0tvca")
|
||||
default_fade_time = 2.0
|
||||
garden_phases_scores = Array[int]([0, 10, 30])
|
||||
playing_soundtracks = [NodePath("Ambiance/Default")]
|
||||
|
||||
[node name="Ambiance" type="Node" parent="."]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="Default" type="AudioStreamPlayer" parent="Ambiance"]
|
||||
[node name="Exterior" type="AudioStreamPlayer" parent="Ambiance"]
|
||||
unique_name_in_owner = true
|
||||
stream = SubResource("AudioStreamSynchronized_i5lxw")
|
||||
autoplay = true
|
||||
stream = ExtResource("2_tuvql")
|
||||
|
||||
[node name="Musics" type="Node" parent="."]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="Planet" type="AudioStreamPlayer" parent="Musics"]
|
||||
[node name="Region" type="AudioStreamPlayer" parent="Musics"]
|
||||
unique_name_in_owner = true
|
||||
stream = SubResource("AudioStreamPlaylist_ajci6")
|
||||
autoplay = true
|
||||
|
||||
[node name="Title" type="AudioStreamPlayer" parent="Musics"]
|
||||
unique_name_in_owner = true
|
||||
stream = ExtResource("7_tuvql")
|
||||
|
||||
[node name="Truck" type="AudioStreamPlayer" parent="Musics"]
|
||||
unique_name_in_owner = true
|
||||
stream = ExtResource("8_0e5ja")
|
||||
autoplay = true
|
||||
|
||||
[node name="Sfx" type="Node" parent="."]
|
||||
unique_name_in_owner = true
|
||||
|
||||
@@ -7,132 +7,115 @@ const MAX_VOLUME = 24.
|
||||
|
||||
@export var default_fade_time = 1.0
|
||||
|
||||
@export var garden_phase = 0
|
||||
@export var garden_phases_scores : Array[int]
|
||||
|
||||
@export var playing_soundtracks : Array[AudioStreamPlayer] = []
|
||||
@export var playing_music : AudioStreamPlayer = null
|
||||
@export var playing_ambiance : AudioStreamPlayer = null
|
||||
|
||||
var default_volumes := {}
|
||||
|
||||
func _ready():
|
||||
GameInfo.game_data.current_planet_data_updated.connect(_on_current_planet_data_updated)
|
||||
fetch_default_volumes()
|
||||
setup_volume()
|
||||
settings.sound_changed.connect(
|
||||
func(_s) : setup_volume()
|
||||
)
|
||||
for player in get_all_soundtrack_players():
|
||||
player.play()
|
||||
for player in get_all_players():
|
||||
player.stop()
|
||||
|
||||
fetch_default_volumes()
|
||||
setup_volume()
|
||||
settings.sound_changed.connect(
|
||||
func(_s) : setup_volume()
|
||||
)
|
||||
SceneManager.scene_loaded.connect(_on_change_scene)
|
||||
|
||||
func _on_change_scene(scene : Scene):
|
||||
play_ambiance()
|
||||
|
||||
match scene.scene_id:
|
||||
"TITLE":
|
||||
play_music("Title")
|
||||
"REGION":
|
||||
play_music("Region")
|
||||
play_ambiance("Exterior")
|
||||
"COCKPIT":
|
||||
play_music("Truck")
|
||||
|
||||
func fetch_default_volumes():
|
||||
var all_players := get_all_soundtrack_players()
|
||||
all_players.append_array(get_all_sfx_players())
|
||||
var all_players := get_all_players()
|
||||
|
||||
for player in all_players:
|
||||
default_volumes[player] = player.volume_db
|
||||
for player in all_players:
|
||||
default_volumes[player] = player.volume_db
|
||||
|
||||
func setup_volume():
|
||||
for player in get_all_soundtrack_players():
|
||||
player.volume_db = get_volume_from_parent(player) if (
|
||||
playing_soundtracks.find(player) != -1
|
||||
) else MIN_VOLUME
|
||||
setup_phase(player)
|
||||
for player in get_all_sfx_players():
|
||||
player.volume_db = get_volume_from_parent(player)
|
||||
for player in get_all_players():
|
||||
player.volume_db = get_volume_from_parent(player)
|
||||
|
||||
func get_volume_from_parent(player : AudioStreamPlayer) -> float:
|
||||
var settings_volume = 0.5
|
||||
var settings_volume = 0.5
|
||||
|
||||
if player.get_parent() == %Ambiance:
|
||||
settings_volume = settings.ambiance_volume
|
||||
elif player.get_parent() == %Sfx:
|
||||
settings_volume = settings.sfx_volume
|
||||
elif player.get_parent() == %Musics:
|
||||
settings_volume = settings.music_volume
|
||||
|
||||
return default_volumes[player] + lerp(MIN_VOLUME, MAX_VOLUME, settings_volume)
|
||||
if player.get_parent() == %Ambiance:
|
||||
settings_volume = settings.ambiance_volume
|
||||
elif player.get_parent() == %Sfx:
|
||||
settings_volume = settings.sfx_volume
|
||||
elif player.get_parent() == %Musics:
|
||||
settings_volume = settings.music_volume
|
||||
|
||||
return default_volumes[player] + lerp(MIN_VOLUME, MAX_VOLUME, settings_volume)
|
||||
|
||||
func update_phase():
|
||||
for player in get_all_soundtrack_players():
|
||||
var playing : bool = player.volume_db != MIN_VOLUME
|
||||
if playing:
|
||||
await set_volume(player, MIN_VOLUME).finished
|
||||
setup_phase(player)
|
||||
if playing:
|
||||
set_volume(player, get_volume_from_parent(player))
|
||||
func get_all_players() -> Array[AudioStreamPlayer]:
|
||||
var players : Array[AudioStreamPlayer] = []
|
||||
players.append_array(get_players_from_node(%Musics))
|
||||
players.append_array(get_players_from_node(%Ambiance))
|
||||
players.append_array(get_players_from_node(%Sfx))
|
||||
|
||||
func get_all_soundtrack_players() -> Array[AudioStreamPlayer]:
|
||||
var players : Array[AudioStreamPlayer] = []
|
||||
players.append_array(get_players_from_node(%Musics))
|
||||
players.append_array(get_players_from_node(%Ambiance))
|
||||
|
||||
return players
|
||||
|
||||
func get_all_sfx_players() -> Array[AudioStreamPlayer]:
|
||||
return get_players_from_node(%Sfx)
|
||||
return players
|
||||
|
||||
func get_players_from_node(node : Node) -> Array[AudioStreamPlayer]:
|
||||
var streams : Array[AudioStreamPlayer] = []
|
||||
var streams : Array[AudioStreamPlayer] = []
|
||||
|
||||
for c in node.get_children():
|
||||
if c is AudioStreamPlayer:
|
||||
streams.append(c)
|
||||
return streams
|
||||
for c in node.get_children():
|
||||
if c is AudioStreamPlayer:
|
||||
streams.append(c)
|
||||
return streams
|
||||
|
||||
func set_volume(player : AudioStreamPlayer, to : float, fade_time = default_fade_time) -> Tween:
|
||||
var fade_tween : Tween = get_tree().create_tween()
|
||||
|
||||
func _on_current_planet_data_updated(planet_data : PlanetData):
|
||||
if planet_data:
|
||||
update_garden_phase(planet_data)
|
||||
planet_data.updated.connect(update_garden_phase)
|
||||
|
||||
func update_garden_phase(planet_data : PlanetData):
|
||||
var phase : int = garden_phase
|
||||
for i in range(len(garden_phases_scores)):
|
||||
if planet_data.garden_score >= garden_phases_scores[i] and i > garden_phase:
|
||||
phase = i
|
||||
fade_tween.tween_property(player, "volume_db", to, fade_time)
|
||||
|
||||
if garden_phase != phase:
|
||||
update_phase()
|
||||
return fade_tween
|
||||
|
||||
garden_phase = phase
|
||||
func reset_volume(player : AudioStreamPlayer):
|
||||
player.volume_db = get_volume_from_parent(player)
|
||||
|
||||
func enter_planet():
|
||||
play_music(%Planet, true)
|
||||
stop_music(%Truck, true)
|
||||
func play_sfx(sfx_name : String):
|
||||
var player := %Sfx.find_child(sfx_name) as AudioStreamPlayer
|
||||
if player:
|
||||
player.play()
|
||||
else:
|
||||
printerr("Sfx %s not found" % sfx_name)
|
||||
|
||||
func enter_truck():
|
||||
play_music(%Truck, true)
|
||||
stop_music(%Planet, true)
|
||||
func play_music(music_name : String = ""):
|
||||
if playing_music:
|
||||
await set_volume(playing_music, MIN_VOLUME).finished
|
||||
if playing_music:
|
||||
playing_music.stop()
|
||||
reset_volume(playing_music)
|
||||
playing_music = null
|
||||
if music_name:
|
||||
var player := %Musics.find_child(music_name) as AudioStreamPlayer
|
||||
if player:
|
||||
playing_music = player
|
||||
player.play()
|
||||
else:
|
||||
printerr("Music %s not found" % music_name)
|
||||
|
||||
func stop_music(music : AudioStreamPlayer, with_fade = false):
|
||||
if playing_soundtracks.find(music) != -1:
|
||||
playing_soundtracks.remove_at(playing_soundtracks.find(music))
|
||||
set_volume(music, MIN_VOLUME, with_fade)
|
||||
|
||||
func play_music(player : AudioStreamPlayer, with_fade = false):
|
||||
playing_soundtracks.append(player)
|
||||
set_volume(player, get_volume_from_parent(player), with_fade)
|
||||
|
||||
func setup_phase(music : AudioStreamPlayer):
|
||||
if music.stream is AudioStreamSynchronized:
|
||||
var sync_stream = music.stream as AudioStreamSynchronized
|
||||
var phase_stream_id = min(garden_phase, sync_stream.stream_count - 1)
|
||||
for i in range(sync_stream.stream_count):
|
||||
sync_stream.set_sync_stream_volume(
|
||||
i,
|
||||
0. if i == phase_stream_id else MIN_VOLUME
|
||||
)
|
||||
|
||||
func set_volume(music : AudioStreamPlayer, to : float, fade_time = default_fade_time) -> Tween:
|
||||
var fade_tween : Tween = get_tree().create_tween()
|
||||
|
||||
fade_tween.tween_property(music, "volume_db", to, fade_time)
|
||||
|
||||
return fade_tween
|
||||
|
||||
func play_sfx(name : String):
|
||||
var player := %Sfx.find_child(name) as AudioStreamPlayer
|
||||
if player:
|
||||
player.play()
|
||||
else:
|
||||
printerr("Sfx %s not found" % name)
|
||||
func play_ambiance(ambiance_name : String = ""):
|
||||
if playing_ambiance:
|
||||
await set_volume(playing_ambiance, MIN_VOLUME).finished
|
||||
if playing_ambiance:
|
||||
playing_ambiance.stop()
|
||||
reset_volume(playing_ambiance)
|
||||
playing_ambiance = null
|
||||
if ambiance_name:
|
||||
var player := %Ambiance.find_child(ambiance_name) as AudioStreamPlayer
|
||||
if player:
|
||||
playing_ambiance = player
|
||||
player.play()
|
||||
else:
|
||||
printerr("Sfx %s not found" % ambiance_name)
|
||||
|
||||
@@ -1,100 +1,31 @@
|
||||
extends Resource
|
||||
class_name GameData
|
||||
|
||||
signal current_planet_data_updated(p : PlanetData)
|
||||
|
||||
func _init():
|
||||
set_default_unlocked()
|
||||
|
||||
@export var tutorial_done = false
|
||||
signal current_region_data_updated(p : RegionData)
|
||||
|
||||
@export var settings : SettingsData = SettingsData.new()
|
||||
|
||||
@export var current_run : RunData = RunData.new()
|
||||
@export var current_run : RunData = null
|
||||
|
||||
@export var current_planet_data : PlanetData : get = get_current_planet_data
|
||||
|
||||
@export var current_region_data : RegionData = null
|
||||
|
||||
@export var player_data : PlayerData = PlayerData.new()
|
||||
|
||||
@export var unlocked_plant_types : Array[PlantType] = []
|
||||
@export var unlocked_plant_mutations : Array[PlantMutation] = []
|
||||
@export var unlocked_machines : Array[MachineType] = []
|
||||
|
||||
@export var truck_data : TruckData = TruckData.new()
|
||||
|
||||
func _ready():
|
||||
current_run.run_point_changed.connect(
|
||||
func(): current_planet_data_updated.emit(get_current_planet_data)
|
||||
)
|
||||
|
||||
func set_default_unlocked():
|
||||
unlocked_plant_types = all_plant_types()
|
||||
unlocked_plant_mutations = all_plant_mutations()
|
||||
unlocked_machines = all_machines()
|
||||
|
||||
func reset_run():
|
||||
current_run = RunData.new()
|
||||
current_planet_data_updated.emit()
|
||||
func start_run():
|
||||
player_data.inventory.clear()
|
||||
current_run = RunData.new()
|
||||
current_run.current_run_point_changed.connect(
|
||||
func(rp : RunPoint):
|
||||
start_region(rp.region_parameter)
|
||||
)
|
||||
|
||||
func reset_player():
|
||||
player_data = PlayerData.new()
|
||||
|
||||
func reset_truck():
|
||||
truck_data = TruckData.new()
|
||||
player_data = PlayerData.new()
|
||||
|
||||
func reset_all():
|
||||
reset_run()
|
||||
reset_player()
|
||||
reset_truck()
|
||||
start_run()
|
||||
reset_player()
|
||||
|
||||
unlocked_plant_types = []
|
||||
|
||||
func unlock_plant_type(new_plant_type : PlantType):
|
||||
if not is_plant_type_unlocked(new_plant_type):
|
||||
unlocked_plant_types.append(new_plant_type.duplicate_deep())
|
||||
|
||||
func get_locked_plant_types() -> Array[PlantType]:
|
||||
var locked_plant_type : Array[PlantType] = []
|
||||
|
||||
for pt in GameInfo.game_data.all_plant_types():
|
||||
if not is_plant_type_unlocked(pt):
|
||||
locked_plant_type.append(pt)
|
||||
|
||||
return locked_plant_type
|
||||
|
||||
func get_current_planet_data():
|
||||
return current_run.get_current_planet_data()
|
||||
|
||||
func is_plant_type_unlocked(new_plant_type : PlantType):
|
||||
return unlocked_plant_types.find_custom(
|
||||
func (upt : PlantType): return new_plant_type.name == upt.name
|
||||
) != -1
|
||||
|
||||
|
||||
func all_plant_types() -> Array[PlantType]:
|
||||
return [
|
||||
preload("res://entities/plants/resources/plant_types/champ.tres"),
|
||||
preload("res://entities/plants/resources/plant_types/chardi.tres"),
|
||||
preload("res://entities/plants/resources/plant_types/ferno.tres"),
|
||||
preload("res://entities/plants/resources/plant_types/maias.tres"),
|
||||
preload("res://entities/plants/resources/plant_types/philea.tres"),
|
||||
preload("res://entities/plants/resources/plant_types/pili.tres"),
|
||||
preload("res://entities/plants/resources/plant_types/solita.tres"),
|
||||
]
|
||||
|
||||
func all_machines() -> Array[MachineType]:
|
||||
return [
|
||||
preload("res://entities/interactables/machines/solar_pannel/solar_pannel.tres"),
|
||||
]
|
||||
|
||||
func all_plant_mutations() -> Array[PlantMutation]:
|
||||
return [
|
||||
preload("res://entities/plants/resources/plant_mutations/ancient_mutation.tres"),
|
||||
preload("res://entities/plants/resources/plant_mutations/elitist_mutation.tres"),
|
||||
preload("res://entities/plants/resources/plant_mutations/ermit_mutation.tres"),
|
||||
preload("res://entities/plants/resources/plant_mutations/precocious_mutation.tres"),
|
||||
preload("res://entities/plants/resources/plant_mutations/quality_mutation.tres"),
|
||||
preload("res://entities/plants/resources/plant_mutations/quick_mutation.tres"),
|
||||
preload("res://entities/plants/resources/plant_mutations/sociable_mutation.tres"),
|
||||
preload("res://entities/plants/resources/plant_mutations/strong_mutation.tres"),
|
||||
]
|
||||
func start_region(region_param : RegionParameter):
|
||||
current_region_data = RegionData.new(region_param)
|
||||
current_region_data_updated.emit(current_region_data)
|
||||
|
||||
@@ -1,22 +1,27 @@
|
||||
extends Resource
|
||||
class_name RunData
|
||||
|
||||
const RUN_POINT_POSITION_DERIVATION = 70
|
||||
enum State {STARTED, IN_PROGRESS, FINISHED}
|
||||
|
||||
const RUN_POINT_POSITION_DERIVATION = 100
|
||||
const DIFFICULTY_INCREASE_BY_LEVEL = 1
|
||||
const RUN_POINTS_NEXT_NUMBER :Array[int] = [2,3]
|
||||
const RUN_POINT_MAX_LEVEL = 10
|
||||
|
||||
signal run_point_changed
|
||||
signal current_run_point_changed
|
||||
|
||||
var run_seed = randi()
|
||||
@export var next_run_points : Array[RunPoint] = [generate_first_run_point()]
|
||||
@export var current_run_point : RunPoint = null
|
||||
@export var current_run_point : RunPoint = null :
|
||||
set(v):
|
||||
current_run_point = v
|
||||
current_run_point_changed.emit(v)
|
||||
@export var visited_run_points : Array[RunPoint] = []
|
||||
|
||||
#region ------------------ Generation ------------------
|
||||
|
||||
func generate_first_run_point() -> RunPoint:
|
||||
return RunPoint.new(0, PlanetParameter.new())
|
||||
return RunPoint.new(0, RegionParameter.new())
|
||||
|
||||
func generate_next_run_points(run_point : RunPoint) -> Array[RunPoint]:
|
||||
var nb_next_run_points = RUN_POINTS_NEXT_NUMBER.pick_random()
|
||||
@@ -38,18 +43,18 @@ func generate_next_run_points(run_point : RunPoint) -> Array[RunPoint]:
|
||||
func generate_next_run_point(run_point : RunPoint) -> RunPoint:
|
||||
return RunPoint.new(
|
||||
run_point.level + 1,
|
||||
generate_difficulty_increased_planet_parameter(run_point.planet_parameter, DIFFICULTY_INCREASE_BY_LEVEL),
|
||||
generate_difficulty_increased_region_parameter(run_point.region_parameter, DIFFICULTY_INCREASE_BY_LEVEL),
|
||||
(run_point.position + randi_range(-RUN_POINT_POSITION_DERIVATION, RUN_POINT_POSITION_DERIVATION)) % 360
|
||||
)
|
||||
|
||||
func generate_difficulty_increased_planet_parameter(
|
||||
planet_parameter : PlanetParameter,
|
||||
func generate_difficulty_increased_region_parameter(
|
||||
region_parameter : RegionParameter,
|
||||
difficulty : int = 1
|
||||
) -> PlanetParameter:
|
||||
) -> RegionParameter:
|
||||
var i_diff := difficulty
|
||||
var new_planet_parameter = PlanetParameter.new(
|
||||
planet_parameter.charges,
|
||||
planet_parameter.objective
|
||||
var new_region_parameter = RegionParameter.new(
|
||||
region_parameter.charges,
|
||||
region_parameter.objective
|
||||
)
|
||||
while i_diff > 0:
|
||||
|
||||
@@ -58,26 +63,30 @@ func generate_difficulty_increased_planet_parameter(
|
||||
DifficultyIncreaseObjective.new()
|
||||
].filter(
|
||||
func (mod : DifficultyModifier):
|
||||
return mod.get_difficulty_cost() <= i_diff and mod.can_modifiy(new_planet_parameter)
|
||||
return mod.get_difficulty_cost() <= i_diff and mod.can_modifiy(new_region_parameter)
|
||||
)
|
||||
|
||||
var selected_difficulty_modifier = available_difficulty_modifier.pick_random()
|
||||
|
||||
selected_difficulty_modifier.modify(new_planet_parameter)
|
||||
selected_difficulty_modifier.modify(new_region_parameter)
|
||||
|
||||
i_diff -= max(1,selected_difficulty_modifier.get_difficulty_cost())
|
||||
return new_planet_parameter
|
||||
return new_region_parameter
|
||||
|
||||
#endregion
|
||||
|
||||
func get_next_run_points() -> Array[RunPoint]:
|
||||
return next_run_points
|
||||
func get_state() -> State:
|
||||
if not current_run_point:
|
||||
return State.STARTED
|
||||
elif current_run_point.level == RUN_POINT_MAX_LEVEL:
|
||||
return State.FINISHED
|
||||
else :
|
||||
return State.IN_PROGRESS
|
||||
|
||||
func get_current_planet_data() -> PlanetData:
|
||||
if current_run_point:
|
||||
return current_run_point.planet_data
|
||||
else:
|
||||
return null
|
||||
func get_next_run_points() -> Array[RunPoint]:
|
||||
if current_run_point and current_run_point.level == RUN_POINT_MAX_LEVEL:
|
||||
return []
|
||||
return next_run_points
|
||||
|
||||
func choose_next_run_point(run_point : RunPoint) -> RunPoint:
|
||||
if current_run_point:
|
||||
@@ -87,22 +96,22 @@ func choose_next_run_point(run_point : RunPoint) -> RunPoint:
|
||||
return current_run_point
|
||||
|
||||
class DifficultyModifier:
|
||||
func modify(_planet_parameter : PlanetParameter):
|
||||
func modify(_region_parameter : RegionParameter):
|
||||
pass
|
||||
|
||||
func can_modifiy(_planet_parameter : PlanetParameter) -> bool:
|
||||
func can_modifiy(_region_parameter : RegionParameter) -> bool:
|
||||
return true
|
||||
|
||||
func get_difficulty_cost() -> int:
|
||||
return 1
|
||||
|
||||
class DifficultyIncreaseObjective extends DifficultyModifier:
|
||||
func modify(planet_parameter : PlanetParameter):
|
||||
planet_parameter.objective += 1
|
||||
func modify(region_parameter : RegionParameter):
|
||||
region_parameter.objective += 1
|
||||
|
||||
class DifficultyDecreaseCharge extends DifficultyModifier:
|
||||
func modify(planet_parameter : PlanetParameter):
|
||||
planet_parameter.charges -= 1
|
||||
func modify(region_parameter : RegionParameter):
|
||||
region_parameter.charges -= 1
|
||||
|
||||
func can_modifiy(planet_parameter : PlanetParameter) -> bool:
|
||||
return planet_parameter.charges >= 3
|
||||
func can_modifiy(region_parameter : RegionParameter) -> bool:
|
||||
return region_parameter.charges >= 3
|
||||
@@ -8,53 +8,30 @@ const OBJECTIVE_ICON = preload("res://common/icons/dna.svg")
|
||||
const CHARGE_ICON = preload("res://common/icons/bolt.svg")
|
||||
|
||||
@export var level : int = 0 # X pos along the planet, and difficulty
|
||||
@export var planet_parameter : PlanetParameter = PlanetParameter.new() :
|
||||
@export var region_parameter : RegionParameter = RegionParameter.new() :
|
||||
set(v):
|
||||
planet_parameter = v
|
||||
planet_data = PlanetData.new(planet_parameter)
|
||||
@export var region_name : String = generate_region_name()
|
||||
region_parameter = v
|
||||
@export var position : int = 0 # Y pos along the planet, 0 to 360
|
||||
var planet_data : PlanetData
|
||||
|
||||
func _init(
|
||||
_level : int = 0,
|
||||
_planet_parameter : PlanetParameter = PlanetParameter.new(),
|
||||
_region_parameter : RegionParameter = RegionParameter.new(),
|
||||
_position : int = randi_range(0,360),
|
||||
_region_name : String = generate_region_name()
|
||||
):
|
||||
level = _level
|
||||
planet_parameter = _planet_parameter
|
||||
region_parameter = _region_parameter
|
||||
position = _position
|
||||
region_name = _region_name
|
||||
planet_data = PlanetData.new(planet_parameter)
|
||||
|
||||
func card_info() -> CardInfo:
|
||||
var info = CardInfo.new(region_name)
|
||||
var info = CardInfo.new(region_parameter.name)
|
||||
info.important_stat_icon = DANGER_ICON
|
||||
info.important_stat_text = "%d" % level
|
||||
|
||||
info.type_icon = TYPE_ICON
|
||||
|
||||
info.stats.append_array([
|
||||
CardStatInfo.new(tr("%d_GARDEN_POINTS") % planet_parameter.objective, OBJECTIVE_ICON),
|
||||
CardStatInfo.new(tr("%d_CHARGES_AVAILABLE") % planet_parameter.charges, CHARGE_ICON),
|
||||
CardStatInfo.new(tr("%d_GARDEN_POINTS") % region_parameter.objective, OBJECTIVE_ICON),
|
||||
CardStatInfo.new(tr("%d_CHARGES_AVAILABLE") % region_parameter.charges, CHARGE_ICON),
|
||||
])
|
||||
|
||||
return info
|
||||
|
||||
func generate_region_name() -> String:
|
||||
var vowel = ["a","e","i","o","u","y"]
|
||||
var consonants = ["b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "v", "w", "x", "z", "'"]
|
||||
|
||||
var word_len = randf_range(4,8)
|
||||
var word = ''
|
||||
var last_letter_is_vowel = false
|
||||
|
||||
for i in range(word_len):
|
||||
if last_letter_is_vowel:
|
||||
word += consonants.pick_random()
|
||||
else:
|
||||
word += vowel.pick_random()
|
||||
|
||||
last_letter_is_vowel = not last_letter_is_vowel
|
||||
return word.capitalize()
|
||||
return info
|
||||
1
common/icons/focus.svg
Normal file
1
common/icons/focus.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-focus"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M11.5 12a.5 .5 0 1 0 1 0a.5 .5 0 1 0 -1 0" fill="#ffffff" /><path d="M3 12a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" /></svg>
|
||||
|
After Width: | Height: | Size: 415 B |
43
common/icons/focus.svg.import
Normal file
43
common/icons/focus.svg.import
Normal file
@@ -0,0 +1,43 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://ba8vh5h3r6pr2"
|
||||
path="res://.godot/imported/focus.svg-cc30e969e976522254107343300a103b.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://common/icons/focus.svg"
|
||||
dest_files=["res://.godot/imported/focus.svg-cc30e969e976522254107343300a103b.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=2.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
1
common/icons/hand-stop.svg
Normal file
1
common/icons/hand-stop.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-hand-stop"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M8 13v-7.5a1.5 1.5 0 0 1 3 0v6.5" /><path d="M11 5.5v-2a1.5 1.5 0 1 1 3 0v8.5" /><path d="M14 5.5a1.5 1.5 0 0 1 3 0v6.5" /><path d="M17 7.5a1.5 1.5 0 0 1 3 0v8.5a6 6 0 0 1 -6 6h-2h.208a6 6 0 0 1 -5.012 -2.7a69.74 69.74 0 0 1 -.196 -.3c-.312 -.479 -1.407 -2.388 -3.286 -5.728a1.5 1.5 0 0 1 .536 -2.022a1.867 1.867 0 0 1 2.28 .28l1.47 1.47" /></svg>
|
||||
|
After Width: | Height: | Size: 651 B |
43
common/icons/hand-stop.svg.import
Normal file
43
common/icons/hand-stop.svg.import
Normal file
@@ -0,0 +1,43 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://3slhocr5wy3w"
|
||||
path="res://.godot/imported/hand-stop.svg-bc0d0e986bcb4b50bdd5686b5bff814b.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://common/icons/hand-stop.svg"
|
||||
dest_files=["res://.godot/imported/hand-stop.svg-bc0d0e986bcb4b50bdd5686b5bff814b.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=2.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
13
common/scene_manager/scene_manager.tscn
Normal file
13
common/scene_manager/scene_manager.tscn
Normal file
@@ -0,0 +1,13 @@
|
||||
[gd_scene load_steps=8 format=3 uid="uid://dac5wte80dwj0"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bb44144ckt2w7" path="res://common/scene_manager/scripts/scene_manager.gd" id="1_1c0qu"]
|
||||
[ext_resource type="Script" uid="uid://1ejbvr3431ac" path="res://common/scene_manager/scripts/scene.gd" id="2_c1lr7"]
|
||||
[ext_resource type="Resource" uid="uid://bvksiaiocwob5" path="res://common/scene_manager/scenes/cockpit.tres" id="3_e28ni"]
|
||||
[ext_resource type="Resource" uid="uid://bvgdq43fpl1xs" path="res://common/scene_manager/scenes/intro.tres" id="4_msho1"]
|
||||
[ext_resource type="Resource" uid="uid://boqgwjyxyb45r" path="res://common/scene_manager/scenes/region.tres" id="5_ytog4"]
|
||||
[ext_resource type="Resource" uid="uid://c27wenetitwm" path="res://common/scene_manager/scenes/region_selection.tres" id="6_chs32"]
|
||||
[ext_resource type="Resource" uid="uid://diro74w272onp" path="res://common/scene_manager/scenes/title.tres" id="7_ol3d5"]
|
||||
|
||||
[node name="SceneManager" type="Node"]
|
||||
script = ExtResource("1_1c0qu")
|
||||
scenes = Array[ExtResource("2_c1lr7")]([ExtResource("3_e28ni"), ExtResource("4_msho1"), ExtResource("5_ytog4"), ExtResource("6_chs32"), ExtResource("7_ol3d5")])
|
||||
10
common/scene_manager/scenes/cockpit.tres
Normal file
10
common/scene_manager/scenes/cockpit.tres
Normal file
@@ -0,0 +1,10 @@
|
||||
[gd_resource type="Resource" script_class="Scene" load_steps=2 format=3 uid="uid://bvksiaiocwob5"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://1ejbvr3431ac" path="res://common/scene_manager/scripts/scene.gd" id="1_tkiq8"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_tkiq8")
|
||||
scene_id = "COCKPIT"
|
||||
scene_path = "res://stages/cockpit/cockpit.tscn"
|
||||
mouse_captured = true
|
||||
metadata/_custom_type_script = "uid://1ejbvr3431ac"
|
||||
9
common/scene_manager/scenes/intro.tres
Normal file
9
common/scene_manager/scenes/intro.tres
Normal file
@@ -0,0 +1,9 @@
|
||||
[gd_resource type="Resource" script_class="Scene" load_steps=2 format=3 uid="uid://bvgdq43fpl1xs"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://1ejbvr3431ac" path="res://common/scene_manager/scripts/scene.gd" id="1_6ws88"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_6ws88")
|
||||
scene_id = "INTRO"
|
||||
scene_path = "res://stages/intro/intro.tscn"
|
||||
metadata/_custom_type_script = "uid://1ejbvr3431ac"
|
||||
10
common/scene_manager/scenes/region.tres
Normal file
10
common/scene_manager/scenes/region.tres
Normal file
@@ -0,0 +1,10 @@
|
||||
[gd_resource type="Resource" script_class="Scene" load_steps=2 format=3 uid="uid://boqgwjyxyb45r"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://1ejbvr3431ac" path="res://common/scene_manager/scripts/scene.gd" id="1_10qbh"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_10qbh")
|
||||
scene_id = "REGION"
|
||||
scene_path = "res://stages/terrain/region/region.tscn"
|
||||
need_terrain_generated = true
|
||||
metadata/_custom_type_script = "uid://1ejbvr3431ac"
|
||||
9
common/scene_manager/scenes/region_selection.tres
Normal file
9
common/scene_manager/scenes/region_selection.tres
Normal file
@@ -0,0 +1,9 @@
|
||||
[gd_resource type="Resource" script_class="Scene" load_steps=2 format=3 uid="uid://c27wenetitwm"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://1ejbvr3431ac" path="res://common/scene_manager/scripts/scene.gd" id="1_smjh0"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_smjh0")
|
||||
scene_id = "REGION_SELECTION"
|
||||
scene_path = "res://stages/region_selection/region_selection.tscn"
|
||||
metadata/_custom_type_script = "uid://1ejbvr3431ac"
|
||||
9
common/scene_manager/scenes/title.tres
Normal file
9
common/scene_manager/scenes/title.tres
Normal file
@@ -0,0 +1,9 @@
|
||||
[gd_resource type="Resource" script_class="Scene" load_steps=2 format=3 uid="uid://diro74w272onp"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://1ejbvr3431ac" path="res://common/scene_manager/scripts/scene.gd" id="1_48g2j"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_48g2j")
|
||||
scene_id = "TITLE"
|
||||
scene_path = "res://stages/title_screen/title_screen.tscn"
|
||||
metadata/_custom_type_script = "uid://1ejbvr3431ac"
|
||||
7
common/scene_manager/scripts/scene.gd
Normal file
7
common/scene_manager/scripts/scene.gd
Normal file
@@ -0,0 +1,7 @@
|
||||
extends Resource
|
||||
class_name Scene
|
||||
|
||||
@export var scene_id : String
|
||||
@export_file_path() var scene_path : String
|
||||
@export var mouse_captured := false
|
||||
@export var need_terrain_generated := false
|
||||
1
common/scene_manager/scripts/scene.gd.uid
Normal file
1
common/scene_manager/scripts/scene.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://1ejbvr3431ac
|
||||
@@ -1,25 +1,39 @@
|
||||
extends Node
|
||||
|
||||
const TITLE_SCREEN = "res://stages/title_screen/title_screen.tscn"
|
||||
const PLANET_SCENE = "res://stages/terrain/planet/planet.tscn"
|
||||
const TRUCK_SCENE = "res://stages/terrain/truck/truck.tscn"
|
||||
const INTRO_SCENE = "res://stages/intro/intro.tscn"
|
||||
const COCKPIT_SCENE = "res://stages/cockpit/cockpit.tscn"
|
||||
const REGION_SELECTION_SCREEN = "res://stages/region_selection/region_selection.tscn"
|
||||
@export var scenes : Array[Scene]
|
||||
|
||||
signal scene_loaded
|
||||
signal scene_node_ready
|
||||
signal scene_loaded(scene : Scene)
|
||||
signal scene_node_ready(scene : Scene)
|
||||
|
||||
var loading_scene = false
|
||||
var generating_node = false
|
||||
var scene_to_load := ""
|
||||
var actual_scene : Scene = null
|
||||
var next_scene_node : Node
|
||||
@onready var current_scene_node : Node = get_tree().root.get_children().back()
|
||||
|
||||
func change_scene(scene_path : String, with_loading = true):
|
||||
func search_scenes(scene_id : String) -> Scene:
|
||||
var scene_pos : int = scenes.find_custom(
|
||||
func (s : Scene):
|
||||
return s.scene_id == scene_id
|
||||
)
|
||||
if scene_pos == -1:
|
||||
return null
|
||||
else :
|
||||
return scenes[scene_pos]
|
||||
|
||||
func change_scene(scene_id : String, with_loading = true):
|
||||
|
||||
if loading_scene or generating_node:
|
||||
await scene_node_ready
|
||||
|
||||
var scene = search_scenes(scene_id)
|
||||
if not scene:
|
||||
printerr("Scene %s not found" % scene_id)
|
||||
return
|
||||
actual_scene = scene
|
||||
loading_scene = true
|
||||
scene_to_load = scene_path
|
||||
ResourceLoader.load_threaded_request(scene_to_load)
|
||||
var scene_path_to_load = scene.scene_path
|
||||
ResourceLoader.load_threaded_request(scene_path_to_load)
|
||||
LoadingScreen.loading_text = "LOADING_SCENE"
|
||||
var scene_to_hide = current_scene_node
|
||||
if with_loading:
|
||||
@@ -31,16 +45,16 @@ func change_scene(scene_path : String, with_loading = true):
|
||||
if loading_scene:
|
||||
await scene_loaded
|
||||
|
||||
next_scene_node = ResourceLoader.load_threaded_get(scene_to_load).instantiate()
|
||||
next_scene_node = ResourceLoader.load_threaded_get(scene_path_to_load).instantiate()
|
||||
if next_scene_node.has_method("hide"):
|
||||
next_scene_node.hide()
|
||||
get_tree().root.add_child(next_scene_node)
|
||||
|
||||
generating_node = true
|
||||
if next_scene_node is Planet:
|
||||
if scene.need_terrain_generated:
|
||||
LoadingScreen.loading_text = "GENERATING_TERRAIN"
|
||||
|
||||
if generating_node:
|
||||
await scene_node_ready
|
||||
|
||||
await scene_node_ready
|
||||
|
||||
if current_scene_node:
|
||||
current_scene_node.queue_free()
|
||||
@@ -48,23 +62,27 @@ func change_scene(scene_path : String, with_loading = true):
|
||||
if current_scene_node.has_method("show"):
|
||||
current_scene_node.show()
|
||||
|
||||
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED if scene.mouse_captured else Input.MOUSE_MODE_VISIBLE
|
||||
|
||||
if with_loading:
|
||||
LoadingScreen.hide_loading_screen()
|
||||
|
||||
func _process(_delta):
|
||||
if loading_scene:
|
||||
var progress = []
|
||||
var load_status := ResourceLoader.load_threaded_get_status(scene_to_load, progress)
|
||||
var load_status := ResourceLoader.load_threaded_get_status(actual_scene.scene_path, progress)
|
||||
LoadingScreen.loading_value = progress[0]
|
||||
if load_status == ResourceLoader.THREAD_LOAD_LOADED:
|
||||
loading_scene = false
|
||||
scene_loaded.emit()
|
||||
scene_loaded.emit(actual_scene)
|
||||
if load_status == ResourceLoader.THREAD_LOAD_FAILED or load_status == ResourceLoader.THREAD_LOAD_INVALID_RESOURCE:
|
||||
printerr()
|
||||
elif generating_node:
|
||||
if next_scene_node is Planet:
|
||||
if next_scene_node is Region:
|
||||
LoadingScreen.loading_value = next_scene_node.generated_value
|
||||
if next_scene_node.is_generated:
|
||||
generating_node = false
|
||||
scene_node_ready.emit()
|
||||
elif next_scene_node.is_node_ready():
|
||||
generating_node = false
|
||||
scene_node_ready.emit()
|
||||
scene_node_ready.emit(actual_scene)
|
||||
@@ -2,33 +2,33 @@ class_name Math
|
||||
|
||||
static func get_chunk_from_pos(coord) -> Vector2i:
|
||||
return Vector2i(
|
||||
floori(coord.x / (Planet.CHUNK_TILE_SIZE * Planet.TILE_SIZE)),
|
||||
floori(coord.y / (Planet.CHUNK_TILE_SIZE * Planet.TILE_SIZE))
|
||||
floori(coord.x / (Region.CHUNK_TILE_SIZE * Region.TILE_SIZE)),
|
||||
floori(coord.y / (Region.CHUNK_TILE_SIZE * Region.TILE_SIZE))
|
||||
)
|
||||
|
||||
static func get_tile_from_pos(coord) -> Vector2i:
|
||||
return Vector2i(
|
||||
floori(coord.x / (Planet.TILE_SIZE)),
|
||||
floori(coord.y / (Planet.TILE_SIZE)),
|
||||
floori(coord.x / (Region.TILE_SIZE)),
|
||||
floori(coord.y / (Region.TILE_SIZE)),
|
||||
)
|
||||
|
||||
static func get_tiles_in_circle(center: Vector2, radius : float) -> Array[Vector2i]:
|
||||
var tiles : Array[Vector2i] = []
|
||||
|
||||
for x in range(
|
||||
floori((center.x - radius/2.) / Planet.TILE_SIZE),
|
||||
ceili((center.x + radius/2.) / Planet.TILE_SIZE),
|
||||
floori((center.x - radius/2.) / Region.TILE_SIZE),
|
||||
ceili((center.x + radius/2.) / Region.TILE_SIZE),
|
||||
):
|
||||
for y in range(
|
||||
floori((center.y - radius/2.) / Planet.TILE_SIZE),
|
||||
ceili((center.y + radius/2.) / Planet.TILE_SIZE),
|
||||
floori((center.y - radius/2.) / Region.TILE_SIZE),
|
||||
ceili((center.y + radius/2.) / Region.TILE_SIZE),
|
||||
):
|
||||
if is_tile_on_circle(Vector2i(x,y), center, radius):
|
||||
tiles.append(Vector2i(x,y))
|
||||
return tiles
|
||||
|
||||
static func is_tile_on_circle(tile_coord : Vector2i, circle_center: Vector2, circle_radius : float) -> bool:
|
||||
var absolute_tile_pos : Vector2 = tile_coord * Planet.TILE_SIZE
|
||||
var absolute_tile_pos : Vector2 = tile_coord * Region.TILE_SIZE
|
||||
|
||||
# Loop over tile corners to know if the area collide
|
||||
var corners : Array[Vector2] = []
|
||||
@@ -36,8 +36,8 @@ static func is_tile_on_circle(tile_coord : Vector2i, circle_center: Vector2, cir
|
||||
for y in [0,1]:
|
||||
corners.append(
|
||||
absolute_tile_pos
|
||||
+ Vector2.RIGHT * x * Planet.TILE_SIZE
|
||||
+ Vector2.DOWN * y * Planet.TILE_SIZE
|
||||
+ Vector2.RIGHT * x * Region.TILE_SIZE
|
||||
+ Vector2.DOWN * y * Region.TILE_SIZE
|
||||
)
|
||||
|
||||
# Check if segment touch area
|
||||
|
||||
45
common/tools/scripts/random.gd
Normal file
45
common/tools/scripts/random.gd
Normal file
@@ -0,0 +1,45 @@
|
||||
class_name Random
|
||||
|
||||
const MIN_WORD_LEN = 4
|
||||
const MAX_WORD_LEN = 8
|
||||
|
||||
const VOWEL = ["a","e","i","o","u","y"]
|
||||
const CONSONANTS = ["b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "v", "w", "x", "z"]
|
||||
|
||||
|
||||
static func generate_random_name(random_seed = randi()) -> String:
|
||||
var word_len = randf_range(4,8)
|
||||
var word = ''
|
||||
var last_letter_is_vowel = false
|
||||
|
||||
for i in range(word_len):
|
||||
if last_letter_is_vowel:
|
||||
word += CONSONANTS.pick_random()
|
||||
else:
|
||||
word += VOWEL.pick_random()
|
||||
|
||||
last_letter_is_vowel = not last_letter_is_vowel
|
||||
return word.capitalize()
|
||||
|
||||
static func mutate_name(word : String) -> String:
|
||||
return word
|
||||
# TODO
|
||||
|
||||
|
||||
func shorten_name(word : String):
|
||||
if randi()%2 == 0:
|
||||
return word.left(len(word) - 1).capitalize()
|
||||
else :
|
||||
return word.right(len(word) - 1).capitalize()
|
||||
|
||||
func elongate_name(word : String):
|
||||
if randi()%2 == 0:
|
||||
var letter = CONSONANTS.pick_random() if word.left(1) in VOWEL else VOWEL.pick_random()
|
||||
return (letter + word).capitalize()
|
||||
else :
|
||||
var letter = CONSONANTS.pick_random() if word.right(1) in VOWEL else VOWEL.pick_random()
|
||||
return (word + letter).capitalize()
|
||||
|
||||
func replace_character(word : String):
|
||||
# TODO
|
||||
return word
|
||||
1
common/tools/scripts/random.gd.uid
Normal file
1
common/tools/scripts/random.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ukeanrcup7of
|
||||
272
common/vfx/materials/shaders/3d_outline.gdshader
Normal file
272
common/vfx/materials/shaders/3d_outline.gdshader
Normal file
@@ -0,0 +1,272 @@
|
||||
shader_type spatial;
|
||||
render_mode unshaded, blend_mix, depth_draw_never, depth_test_disabled;
|
||||
|
||||
/*
|
||||
AUTHOR: Hannah "EMBYR" Crawford
|
||||
ENGINE_VERSION: 4.0.3
|
||||
|
||||
HOW TO USE:
|
||||
1. Create a MeshInstance3D node and place it in your scene.
|
||||
2. Set it's size to 2x2.
|
||||
3. Enable the "Flip Faces" option.
|
||||
4. Create a new shader material with this shader.
|
||||
5. Assign the material to the MeshInstance3D
|
||||
|
||||
LIMITATIONS:
|
||||
Does not work well with TAA enabled.
|
||||
|
||||
MOBILE_NOTES:
|
||||
The mobile renderer does not have access to the normal_roughness texture
|
||||
so we must rely on techniques to reconstruct this information from the
|
||||
depth buffer.
|
||||
|
||||
If you require support on mobile please uncomment the SUPPORT_MOBILE line
|
||||
below. I have done my best to match the appearance between the two modes
|
||||
however, mobile does not take into account smooth-shaded faces.
|
||||
|
||||
The high-quality reconstruction method used on mobile is rather heavy on
|
||||
texture samples. If you would like to use the lower-quality recontruction
|
||||
method for better performance, please uncomment the NAIVE_NORMAL_RECONSTRUCTION
|
||||
line below.
|
||||
*/
|
||||
//#define SUPPORT_MOBILE
|
||||
//#define NAIVE_NORMAL_RECONSTRUCTION
|
||||
|
||||
group_uniforms outline;
|
||||
uniform vec4 outlineColor: source_color = vec4(0.0, 0.0, 0.0, 0.78);
|
||||
uniform float depth_threshold = 0.025;
|
||||
uniform float normal_threshold : hint_range(0.0, 1.5) = 0.5;
|
||||
uniform float normal_smoothing : hint_range(0.0, 1.0) = 0.25;
|
||||
|
||||
group_uniforms thickness;
|
||||
uniform float max_thickness: hint_range(0.0, 5.0) = 1.3;
|
||||
uniform float min_thickness = 0.5;
|
||||
uniform float max_distance = 75.0;
|
||||
uniform float min_distance = 2.0;
|
||||
|
||||
group_uniforms grazing_prevention;
|
||||
uniform float grazing_fresnel_power = 5.0;
|
||||
uniform float grazing_angle_mask_power = 1.0;
|
||||
uniform float grazing_angle_modulation_factor = 50.0;
|
||||
|
||||
uniform sampler2D DEPTH_TEXTURE : hint_depth_texture, filter_linear, repeat_disable;
|
||||
|
||||
#ifndef SUPPORT_MOBILE
|
||||
uniform sampler2D NORMR_TEXTURE : hint_normal_roughness_texture, filter_linear, repeat_disable;
|
||||
#else
|
||||
varying flat mat4 model_view_matrix;
|
||||
#endif// !SUPPORT_MOBILE
|
||||
|
||||
struct UVNeighbors {
|
||||
vec2 center;
|
||||
vec2 left; vec2 right; vec2 up; vec2 down;
|
||||
vec2 top_left; vec2 top_right; vec2 bottom_left; vec2 bottom_right;
|
||||
};
|
||||
|
||||
struct NeighborDepthSamples {
|
||||
float c_d;
|
||||
float l_d; float r_d; float u_d; float d_d;
|
||||
float tl_d; float tr_d; float bl_d; float br_d;
|
||||
};
|
||||
|
||||
UVNeighbors getNeighbors(vec2 center, float width, float aspect) {
|
||||
vec2 h_offset = vec2(width * aspect * 0.001, 0.0);
|
||||
vec2 v_offset = vec2(0.0, width * 0.001);
|
||||
UVNeighbors n;
|
||||
n.center = center;
|
||||
n.left = center - h_offset;
|
||||
n.right = center + h_offset;
|
||||
n.up = center - v_offset;
|
||||
n.down = center + v_offset;
|
||||
n.top_left = center - (h_offset - v_offset);
|
||||
n.top_right = center + (h_offset - v_offset);
|
||||
n.bottom_left = center - (h_offset + v_offset);
|
||||
n.bottom_right = center + (h_offset + v_offset);
|
||||
return n;
|
||||
}
|
||||
|
||||
float getMinimumDepth(NeighborDepthSamples ds){
|
||||
return min(ds.c_d, min(ds.l_d, min(ds.r_d, min(ds.u_d, min(ds.d_d, min(ds.tl_d, min(ds.tr_d, min(ds.bl_d, ds.br_d))))))));
|
||||
}
|
||||
|
||||
float getLinearDepth(float depth, vec2 uv, mat4 inv_proj) {
|
||||
vec3 ndc = vec3(uv * 2.0 - 1.0, depth);
|
||||
vec4 view = inv_proj * vec4(ndc, 1.0);
|
||||
view.xyz /= view.w;
|
||||
return -view.z;
|
||||
}
|
||||
|
||||
NeighborDepthSamples getLinearDepthSamples(UVNeighbors uvs, sampler2D depth_tex, mat4 invProjMat) {
|
||||
NeighborDepthSamples result;
|
||||
result.c_d = getLinearDepth(texture(depth_tex, uvs.center).r, uvs.center, invProjMat);
|
||||
result.l_d = getLinearDepth(texture(depth_tex, uvs.left).r , uvs.left , invProjMat);
|
||||
result.r_d = getLinearDepth(texture(depth_tex, uvs.right).r , uvs.right , invProjMat);
|
||||
result.u_d = getLinearDepth(texture(depth_tex, uvs.up).r , uvs.up , invProjMat);
|
||||
result.d_d = getLinearDepth(texture(depth_tex, uvs.down).r , uvs.down , invProjMat);
|
||||
result.tl_d = getLinearDepth(texture(depth_tex, uvs.top_left).r, uvs.top_left, invProjMat);
|
||||
result.tr_d = getLinearDepth(texture(depth_tex, uvs.top_right).r, uvs.top_right, invProjMat);
|
||||
result.bl_d = getLinearDepth(texture(depth_tex, uvs.bottom_left).r, uvs.bottom_left, invProjMat);
|
||||
result.br_d = getLinearDepth(texture(depth_tex, uvs.bottom_right).r, uvs.bottom_right, invProjMat);
|
||||
return result;
|
||||
}
|
||||
|
||||
float remap(float v, float from1, float to1, float from2, float to2) {
|
||||
return (v - from1) / (to1 - from1) * (to2 - from2) + from2;
|
||||
}
|
||||
|
||||
float fresnel(float amount, vec3 normal, vec3 view) {
|
||||
return pow((1.0 - clamp(dot(normalize(normal), normalize(view)), 0.0, 1.0 )), amount);
|
||||
}
|
||||
|
||||
float getGrazingAngleModulation(vec3 pixel_normal, vec3 view) {
|
||||
float x = clamp(((fresnel(grazing_fresnel_power, pixel_normal, view) - 1.0) / grazing_angle_mask_power) + 1.0, 0.0, 1.0);
|
||||
return (x + grazing_angle_modulation_factor) + 1.0;
|
||||
}
|
||||
|
||||
float detectEdgesDepth(NeighborDepthSamples depth_samples, vec3 pixel_normal, vec3 view) {
|
||||
float n_total =
|
||||
depth_samples.l_d +
|
||||
depth_samples.r_d +
|
||||
depth_samples.u_d +
|
||||
depth_samples.d_d +
|
||||
depth_samples.tl_d +
|
||||
depth_samples.tr_d +
|
||||
depth_samples.bl_d +
|
||||
depth_samples.br_d;
|
||||
|
||||
float t = depth_threshold * getGrazingAngleModulation(pixel_normal, view);
|
||||
return step(t, n_total - (depth_samples.c_d * 8.0));
|
||||
}
|
||||
|
||||
// Reconstruction helpers
|
||||
// Source: https://www.reddit.com/r/godot/comments/v70p2k/improved_normal_from_depth/
|
||||
#ifdef SUPPORT_MOBILE
|
||||
vec3 reconstructWorldPosition(float depth, mat4 model_view, mat4 inv_proj, vec2 screen_uv, mat4 world, mat4 inv_cam){
|
||||
vec4 pos = inverse(model_view) * inv_proj * vec4((screen_uv * 2.0 - 1.0), depth * 2.0 - 1.0, 1.0);
|
||||
pos.xyz /= (pos.w + 0.0001 * (1.-abs(sign(pos.w))));
|
||||
return (pos * inv_cam).xyz + world[3].xyz;
|
||||
}
|
||||
|
||||
#ifndef NAIVE_NORMAL_RECONSTRUCTION
|
||||
vec3 reconstructWorldNormal(sampler2D depth_tex, mat4 model_view, mat4 inv_proj, vec2 screen_uv, mat4 world, mat4 inv_cam, vec2 viewport_size) {
|
||||
vec2 e = vec2(1.0 / viewport_size);
|
||||
float c0 = texture(depth_tex, screen_uv ).r;
|
||||
float l2 = texture(depth_tex, screen_uv - vec2(2,0) * e).r;
|
||||
float l1 = texture(depth_tex, screen_uv - vec2(1,0) * e).r;
|
||||
float r1 = texture(depth_tex, screen_uv + vec2(1,0) * e).r;
|
||||
float r2 = texture(depth_tex, screen_uv + vec2(2,0) * e).r;
|
||||
float b2 = texture(depth_tex, screen_uv - vec2(0,2) * e).r;
|
||||
float b1 = texture(depth_tex, screen_uv - vec2(0,1) * e).r;
|
||||
float t1 = texture(depth_tex, screen_uv + vec2(0,1) * e).r;
|
||||
float t2 = texture(depth_tex, screen_uv + vec2(0,2) * e).r;
|
||||
|
||||
float dl = abs(l1 * l2 / (2.0 * l2 - l1) - c0);
|
||||
float dr = abs(r1 * r2 / (2.0 * r2 - r1) - c0);
|
||||
float db = abs(b1 * b2 / (2.0 * b2 - b1) - c0);
|
||||
float dt = abs(t1 * t2 / (2.0 * t2 - t1) - c0);
|
||||
|
||||
vec3 ce = reconstructWorldPosition(c0, model_view, inv_proj, screen_uv, world, inv_cam);
|
||||
|
||||
vec3 dpdx = (dl<dr) ? ce-reconstructWorldPosition(l1, model_view, inv_proj, screen_uv - vec2(1,0) * e, world, inv_cam) :
|
||||
-ce+reconstructWorldPosition(r1, model_view, inv_proj, screen_uv + vec2(1,0) * e, world, inv_cam) ;
|
||||
vec3 dpdy = (db<dt) ? ce-reconstructWorldPosition(b1, model_view, inv_proj, screen_uv - vec2(0,1) * e, world, inv_cam) :
|
||||
-ce+reconstructWorldPosition(t1, model_view, inv_proj, screen_uv + vec2(0,1) * e, world, inv_cam) ;
|
||||
|
||||
return normalize(cross(dpdx,dpdy));
|
||||
}
|
||||
#else
|
||||
vec3 reconstructWorldNormal(sampler2D depth_tex, mat4 model_view, mat4 inv_proj, vec2 screen_uv, mat4 world, mat4 inv_cam, vec2 viewport_size) {
|
||||
vec3 pos = reconstructWorldPosition(texture(depth_tex, screen_uv).x, model_view, inv_proj, screen_uv, world, inv_cam);
|
||||
return normalize(cross(dFdx(pos), dFdy(pos)));
|
||||
}
|
||||
#endif//!NAIVE_NORMAL_RECONSTRUCTION
|
||||
|
||||
float detectEdgesNormalReconstructed(UVNeighbors uvs, sampler2D depth_tex, mat4 model_view, mat4 inv_proj, vec2 screen_uv, mat4 world, mat4 inv_cam, vec2 viewport_size){
|
||||
vec3 n_u = reconstructWorldNormal(depth_tex, model_view, inv_proj, uvs.up, world, inv_cam, viewport_size);
|
||||
vec3 n_d = reconstructWorldNormal(depth_tex, model_view, inv_proj, uvs.down, world, inv_cam, viewport_size);
|
||||
vec3 n_l = reconstructWorldNormal(depth_tex, model_view, inv_proj, uvs.left, world, inv_cam, viewport_size);
|
||||
vec3 n_r = reconstructWorldNormal(depth_tex, model_view, inv_proj, uvs.right, world, inv_cam, viewport_size);
|
||||
vec3 n_tl = reconstructWorldNormal(depth_tex, model_view, inv_proj, uvs.top_left, world, inv_cam, viewport_size);
|
||||
vec3 n_tr = reconstructWorldNormal(depth_tex, model_view, inv_proj, uvs.top_right, world, inv_cam, viewport_size);
|
||||
vec3 n_bl = reconstructWorldNormal(depth_tex, model_view, inv_proj, uvs.bottom_left, world, inv_cam, viewport_size);
|
||||
vec3 n_br = reconstructWorldNormal(depth_tex, model_view, inv_proj, uvs.bottom_right, world, inv_cam, viewport_size);
|
||||
|
||||
vec3 normalFiniteDifference0 = n_tr - n_bl;
|
||||
vec3 normalFiniteDifference1 = n_tl - n_br;
|
||||
vec3 normalFiniteDifference2 = n_l - n_r;
|
||||
vec3 normalFiniteDifference3 = n_u - n_d;
|
||||
|
||||
float edgeNormal = sqrt(
|
||||
dot(normalFiniteDifference0, normalFiniteDifference0) +
|
||||
dot(normalFiniteDifference1, normalFiniteDifference1) +
|
||||
dot(normalFiniteDifference2, normalFiniteDifference2) +
|
||||
dot(normalFiniteDifference3, normalFiniteDifference3)
|
||||
) * 0.5;
|
||||
|
||||
return smoothstep(normal_threshold - normal_smoothing, normal_threshold + normal_smoothing, edgeNormal);
|
||||
}
|
||||
#else
|
||||
float detectEdgesNormal(UVNeighbors uvs, sampler2D normTex, vec3 camDirWorld){
|
||||
vec3 n_u = texture(normTex, uvs.up).xyz;
|
||||
vec3 n_d = texture(normTex, uvs.down).xyz;
|
||||
vec3 n_l = texture(normTex, uvs.left).xyz;
|
||||
vec3 n_r = texture(normTex, uvs.right).xyz;
|
||||
vec3 n_tl = texture(normTex, uvs.top_left).xyz;
|
||||
vec3 n_tr = texture(normTex, uvs.top_right).xyz;
|
||||
vec3 n_bl = texture(normTex, uvs.bottom_left).xyz;
|
||||
vec3 n_br = texture(normTex, uvs.bottom_right).xyz;
|
||||
|
||||
vec3 normalFiniteDifference0 = n_tr - n_bl;
|
||||
vec3 normalFiniteDifference1 = n_tl - n_br;
|
||||
vec3 normalFiniteDifference2 = n_l - n_r;
|
||||
vec3 normalFiniteDifference3 = n_u - n_d;
|
||||
|
||||
float edgeNormal = sqrt(
|
||||
dot(normalFiniteDifference0, normalFiniteDifference0) +
|
||||
dot(normalFiniteDifference1, normalFiniteDifference1) +
|
||||
dot(normalFiniteDifference2, normalFiniteDifference2) +
|
||||
dot(normalFiniteDifference3, normalFiniteDifference3)
|
||||
);
|
||||
|
||||
return smoothstep(normal_threshold - normal_smoothing, normal_threshold + normal_smoothing, edgeNormal);
|
||||
}
|
||||
#endif//SUPPORT_MOBILE
|
||||
|
||||
void vertex() {
|
||||
POSITION = vec4(VERTEX, 1.0);
|
||||
|
||||
#ifdef SUPPORT_MOBILE
|
||||
model_view_matrix = INV_VIEW_MATRIX * mat4(VIEW_MATRIX[0],VIEW_MATRIX[1],VIEW_MATRIX[2],VIEW_MATRIX[3]);;
|
||||
#endif
|
||||
}
|
||||
|
||||
void fragment() {
|
||||
float aspect = float(VIEWPORT_SIZE.y) / float(VIEWPORT_SIZE.x);
|
||||
|
||||
UVNeighbors n = getNeighbors(SCREEN_UV, max_thickness, aspect);
|
||||
NeighborDepthSamples depth_samples = getLinearDepthSamples(n, DEPTH_TEXTURE, INV_PROJECTION_MATRIX);
|
||||
|
||||
float min_d = getMinimumDepth(depth_samples);
|
||||
float thickness = clamp(remap(min_d, min_distance, max_distance, max_thickness, min_thickness), min_thickness, max_thickness);
|
||||
float fade_a = clamp(remap(min_d, min_distance, max_distance, 1.0, 0.0), 0.0, 1.0);
|
||||
|
||||
n = getNeighbors(SCREEN_UV, thickness, aspect);
|
||||
depth_samples = getLinearDepthSamples(n, DEPTH_TEXTURE, INV_PROJECTION_MATRIX);
|
||||
|
||||
#ifndef SUPPORT_MOBILE
|
||||
vec3 pixel_normal = texture(NORMR_TEXTURE, SCREEN_UV).xyz;
|
||||
#else
|
||||
vec3 pixel_normal = reconstructWorldNormal(DEPTH_TEXTURE, model_view_matrix, INV_PROJECTION_MATRIX, SCREEN_UV, MODEL_MATRIX, INV_VIEW_MATRIX, VIEWPORT_SIZE.xy);
|
||||
#endif
|
||||
|
||||
float depthEdges = detectEdgesDepth(depth_samples, pixel_normal, VIEW);
|
||||
|
||||
#ifndef SUPPORT_MOBILE
|
||||
float normEdges = min(detectEdgesNormal(n, NORMR_TEXTURE, CAMERA_DIRECTION_WORLD), 1.0);
|
||||
#else
|
||||
float normEdges = min(detectEdgesNormalReconstructed(n, DEPTH_TEXTURE, model_view_matrix, INV_PROJECTION_MATRIX, SCREEN_UV, MODEL_MATRIX, INV_VIEW_MATRIX, VIEWPORT_SIZE.xy), 1.0);
|
||||
#endif
|
||||
|
||||
ALBEDO.rgb = outlineColor.rgb;
|
||||
ALPHA = max(depthEdges, normEdges) * outlineColor.a * fade_a;
|
||||
}
|
||||
1
common/vfx/materials/shaders/3d_outline.gdshader.uid
Normal file
1
common/vfx/materials/shaders/3d_outline.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b14e5ju3o3bvs
|
||||
Reference in New Issue
Block a user