developpement d'écran de chargement et d'écran de sélection de niveau

* modification de certains assets
* optimisation de chunks
* ajout d'un SceneManager
* ajout d'un premier dialogue avec Demeter
* changement des jour en charge
* mise en place d'un système de run
* etc...
This commit is contained in:
2026-01-10 13:04:33 +01:00
parent c130c47042
commit 9c449b234f
136 changed files with 3464 additions and 1147 deletions

View File

@@ -10,10 +10,10 @@ func _init():
@export var settings : SettingsData = SettingsData.new()
@export var current_planet_data : PlanetData = PlanetData.new() :
set(v):
current_planet_data = v
current_planet_data_updated.emit(v)
@export var current_run : RunData = RunData.new()
@export var current_planet_data : PlanetData : get = get_current_planet_data
@export var player_data : PlayerData = PlayerData.new()
@export var unlocked_plant_types : Array[PlantType] = []
@@ -22,12 +22,19 @@ func _init():
@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_planet():
current_planet_data = PlanetData.new()
func reset_run():
current_run = RunData.new()
current_planet_data_updated.emit()
func reset_player():
player_data = PlayerData.new()
@@ -36,7 +43,7 @@ func reset_truck():
truck_data = TruckData.new()
func reset_all():
reset_planet()
reset_run()
reset_player()
reset_truck()
@@ -55,6 +62,9 @@ func get_locked_plant_types() -> Array[PlantType]:
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

View File

@@ -0,0 +1,108 @@
extends Resource
class_name RunData
const RUN_POINT_POSITION_DERIVATION = 70
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
var run_seed = randi()
@export var next_run_points : Array[RunPoint] = [generate_first_run_point()]
@export var current_run_point : RunPoint = null
@export var visited_run_points : Array[RunPoint] = []
#region ------------------ Generation ------------------
func generate_first_run_point() -> RunPoint:
return RunPoint.new(0, PlanetParameter.new())
func generate_next_run_points(run_point : RunPoint) -> Array[RunPoint]:
var nb_next_run_points = RUN_POINTS_NEXT_NUMBER.pick_random()
if run_point.level == RUN_POINT_MAX_LEVEL - 1 or run_point.level == -1:
nb_next_run_points = 1
elif run_point.level == RUN_POINT_MAX_LEVEL:
nb_next_run_points = 0
next_run_points = []
for i in range(nb_next_run_points):
next_run_points.append(
generate_next_run_point(run_point)
)
return next_run_points
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),
(run_point.position + randi_range(-RUN_POINT_POSITION_DERIVATION, RUN_POINT_POSITION_DERIVATION)) % 360
)
func generate_difficulty_increased_planet_parameter(
planet_parameter : PlanetParameter,
difficulty : int = 1
) -> PlanetParameter:
var i_diff := difficulty
var new_planet_parameter = PlanetParameter.new(
planet_parameter.charges,
planet_parameter.objective
)
while i_diff > 0:
var available_difficulty_modifier = [
DifficultyDecreaseCharge.new(),
DifficultyIncreaseObjective.new()
].filter(
func (mod : DifficultyModifier):
return mod.get_difficulty_cost() <= i_diff and mod.can_modifiy(new_planet_parameter)
)
var selected_difficulty_modifier = available_difficulty_modifier.pick_random()
selected_difficulty_modifier.modify(new_planet_parameter)
i_diff -= max(1,selected_difficulty_modifier.get_difficulty_cost())
return new_planet_parameter
#endregion
func get_next_run_points() -> Array[RunPoint]:
return next_run_points
func get_current_planet_data() -> PlanetData:
if current_run_point:
return current_run_point.planet_data
else:
return null
func choose_next_run_point(run_point : RunPoint) -> RunPoint:
if current_run_point:
visited_run_points.append(current_run_point)
current_run_point = run_point
next_run_points = generate_next_run_points(current_run_point)
return current_run_point
class DifficultyModifier:
func modify(_planet_parameter : PlanetParameter):
pass
func can_modifiy(_planet_parameter : PlanetParameter) -> bool:
return true
func get_difficulty_cost() -> int:
return 1
class DifficultyIncreaseObjective extends DifficultyModifier:
func modify(planet_parameter : PlanetParameter):
planet_parameter.objective += 1
class DifficultyDecreaseCharge extends DifficultyModifier:
func modify(planet_parameter : PlanetParameter):
planet_parameter.charges -= 1
func can_modifiy(planet_parameter : PlanetParameter) -> bool:
return planet_parameter.charges >= 3

View File

@@ -0,0 +1 @@
uid://dhci2ut27wdef

View File

@@ -0,0 +1,60 @@
@tool
extends Resource
class_name RunPoint
const DANGER_ICON = preload("res://common/icons/skull.svg")
const TYPE_ICON = preload("res://common/icons/map-pin.svg")
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() :
set(v):
planet_parameter = v
planet_data = PlanetData.new(planet_parameter)
@export var region_name : String = generate_region_name()
@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(),
_position : int = randi_range(0,360),
_region_name : String = generate_region_name()
):
level = _level
planet_parameter = _planet_parameter
position = _position
region_name = _region_name
planet_data = PlanetData.new(planet_parameter)
func card_info() -> CardInfo:
var info = CardInfo.new(region_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),
])
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()

View File

@@ -0,0 +1 @@
uid://b4eimt3v08jhc

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#ffffff" class="icon icon-tabler icons-tabler-filled icon-tabler-alert-triangle"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 1.67c.955 0 1.845 .467 2.39 1.247l.105 .16l8.114 13.548a2.914 2.914 0 0 1 -2.307 4.363l-.195 .008h-16.225a2.914 2.914 0 0 1 -2.582 -4.2l.099 -.185l8.11 -13.538a2.914 2.914 0 0 1 2.491 -1.403zm.01 13.33l-.127 .007a1 1 0 0 0 0 1.986l.117 .007l.127 -.007a1 1 0 0 0 0 -1.986l-.117 -.007zm-.01 -7a1 1 0 0 0 -.993 .883l-.007 .117v4l.007 .117a1 1 0 0 0 1.986 0l.007 -.117v-4l-.007 -.117a1 1 0 0 0 -.993 -.883z" /></svg>

After

Width:  |  Height:  |  Size: 646 B

View File

@@ -0,0 +1,43 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dnx175gw62h48"
path="res://.godot/imported/alert-triangle.svg-359e9c577845507bfe8a84da1c84a056.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://common/icons/alert-triangle.svg"
dest_files=["res://.godot/imported/alert-triangle.svg-359e9c577845507bfe8a84da1c84a056.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

View 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-map-pin-check"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M9 11a3 3 0 1 0 6 0a3 3 0 0 0 -6 0" /><path d="M11.87 21.48a1.992 1.992 0 0 1 -1.283 -.58l-4.244 -4.243a8 8 0 1 1 13.355 -3.474" /><path d="M15 19l2 2l4 -4" /></svg>

After

Width:  |  Height:  |  Size: 473 B

View File

@@ -0,0 +1,44 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dqsx56wc73wry"
path.s3tc="res://.godot/imported/map-pin-check.svg-80b3d57601b28013f127ae39434b14ab.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://common/icons/map-pin-check.svg"
dest_files=["res://.godot/imported/map-pin-check.svg-80b3d57601b28013f127ae39434b14ab.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0
svg/scale=2.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View 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-map-pin"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M9 11a3 3 0 1 0 6 0a3 3 0 0 0 -6 0" /><path d="M17.657 16.657l-4.243 4.243a2 2 0 0 1 -2.827 0l-4.244 -4.243a8 8 0 1 1 11.314 0z" /></svg>

After

Width:  |  Height:  |  Size: 439 B

View File

@@ -0,0 +1,44 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://be7ietbjlmgtt"
path.s3tc="res://.godot/imported/map-pin-empty.svg-9c3a4164fa6b64ef865d54ff2290c882.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://common/icons/map-pin-empty.svg"
dest_files=["res://.godot/imported/map-pin-empty.svg-9c3a4164fa6b64ef865d54ff2290c882.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0
svg/scale=2.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

1
common/icons/map-pin.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#ffffff" class="icon icon-tabler icons-tabler-filled icon-tabler-map-pin"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M18.364 4.636a9 9 0 0 1 .203 12.519l-.203 .21l-4.243 4.242a3 3 0 0 1 -4.097 .135l-.144 -.135l-4.244 -4.243a9 9 0 0 1 12.728 -12.728zm-6.364 3.364a3 3 0 1 0 0 6a3 3 0 0 0 0 -6z" /></svg>

After

Width:  |  Height:  |  Size: 408 B

View File

@@ -0,0 +1,44 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://l2xplg72hs6j"
path.s3tc="res://.godot/imported/map-pin.svg-59634f848c96fb898d5c3996812816f3.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://common/icons/map-pin.svg"
dest_files=["res://.godot/imported/map-pin.svg-59634f848c96fb898d5c3996812816f3.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0
svg/scale=2.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View File

@@ -0,0 +1,69 @@
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 REGION_SELECTION_SCREEN = "res://stages/region_selection/region_selection.tscn"
signal scene_loaded
signal scene_node_ready
var loading_scene = false
var generating_node = false
var scene_to_load := ""
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):
loading_scene = true
scene_to_load = scene_path
ResourceLoader.load_threaded_request(scene_to_load)
LoadingScreen.loading_text = "LOADING_SCENE"
var scene_to_hide = current_scene_node
if with_loading:
await LoadingScreen.show_loading_screen()
if scene_to_hide != null and scene_to_hide.has_method("hide"):
scene_to_hide.hide()
if loading_scene:
await scene_loaded
next_scene_node = ResourceLoader.load_threaded_get(scene_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:
LoadingScreen.loading_text = "GENERATING_TERRAIN"
if generating_node:
await scene_node_ready
if current_scene_node:
current_scene_node.queue_free()
current_scene_node = next_scene_node
if current_scene_node.has_method("show"):
current_scene_node.show()
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)
LoadingScreen.loading_value = progress[0]
if load_status == ResourceLoader.THREAD_LOAD_LOADED:
loading_scene = false
scene_loaded.emit()
elif generating_node:
if next_scene_node is Planet:
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()

View File

@@ -0,0 +1 @@
uid://bb44144ckt2w7

View File

@@ -0,0 +1,44 @@
shader_type canvas_item;
uniform sampler2D SCREEN_TEXTURE: hint_screen_texture,repeat_disable, filter_nearest;
/**
* How blurry the result should be.
* Limited to 20 because of performance, if you want feel free to break it.
*/
uniform float strength : hint_range(0.1, 20.0) = 3.3;
/**
* How dark the blur will be
*/
uniform float mix_percentage: hint_range(0.0, 1.0) = 0.3;
float gaussianDistribution(float x, float STD){ // STD stands for standard deviation
return exp(-(x*x)/(2.*STD*STD))/(sqrt(2.*PI)*STD);
}
vec3 gaussianblur(sampler2D sampler, vec2 pos, vec2 pixel_size, float sigmaUsed, int radius){
vec3 blurredPixel = vec3(0.0);
float total_weight = 0.0;
// Loop over the radius (tecnically its a square)
for(int i = -radius ; i <= radius; i++){
for(int j = -radius; j <= radius; j++){
// Calculate the offset from the current pixel
vec2 offset = vec2(float(i), float(j))*pixel_size;
vec2 changedPos = pos + offset;
// Calculate the weight based on the Gaussian distribution multiplying both dimentions (how far are X and Y form the center (pos))
float weight = gaussianDistribution(float(i), sigmaUsed)*gaussianDistribution(float(j), sigmaUsed);
// Add the weighted color value to the blurred pixel
blurredPixel += texture(SCREEN_TEXTURE, changedPos).rgb * weight;
total_weight += weight;
}
}
// Normalize the blurred pixel color by the total weight
blurredPixel/=total_weight;
return blurredPixel;
}
void fragment() {
vec3 PixelBlurred = gaussianblur(SCREEN_TEXTURE, SCREEN_UV, SCREEN_PIXEL_SIZE, strength, int(round(3.0 * strength)));
vec3 color = mix(PixelBlurred, vec3(0.0), mix_percentage);
// The radius is 3*strength because it is the point where the Gaussian weight is near zero.
COLOR = vec4(color, 1.);
}

View File

@@ -0,0 +1 @@
uid://cuni3ggtw2uuy