refonte du système de chunk et correction de bug/traduction

This commit is contained in:
2026-03-01 18:24:46 +01:00
parent d25d614c06
commit 37cd8a54dd
25 changed files with 470 additions and 375 deletions

View File

@@ -37,6 +37,7 @@ func generate_next_run_point(level = 0) -> RunPoint:
region_parameter.level = level
region_parameter.region_flags = get_region_flags(region_parameter)
return RunPoint.new(
level,
region_parameter
@@ -72,24 +73,3 @@ func get_region_flags(region_parameter : RegionParameter) -> Array[String]:
flags.append("borea")
return flags
class DifficultyModifier:
func modify(_region_parameter : RegionParameter):
pass
func can_modifiy(_region_parameter : RegionParameter) -> bool:
return true
func get_difficulty_cost() -> int:
return 1
class DifficultyIncreaseObjective extends DifficultyModifier:
func modify(region_parameter : RegionParameter):
region_parameter.objective += 1
class DifficultyDecreaseCharge extends DifficultyModifier:
func modify(region_parameter : RegionParameter):
region_parameter.charges -= 1
func can_modifiy(region_parameter : RegionParameter) -> bool:
return region_parameter.charges >= 3

View File

@@ -17,6 +17,7 @@ var settings_data : SettingsData
func load_game_data() -> GameData:
if ResourceLoader.exists(SAVE_GAME_LOCATION):
game_loaded = true
game_data = ResourceLoader.load(SAVE_GAME_LOCATION).duplicate_deep()
else :
game_data = GameData.new()

View File

@@ -0,0 +1,8 @@
shader_type canvas_item;
uniform sampler2D screen_texture: hint_screen_texture;
void fragment() {
COLOR = texture(screen_texture, SCREEN_UV);
}

View File

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

View File

@@ -59,6 +59,7 @@ shape = SubResource("CapsuleShape3D_mwti2")
[node name="AudioStreamPlayer3D" type="AudioStreamPlayer3D" parent="." unique_id=73991663]
stream = ExtResource("2_w00q2")
bus = &"Sfx"
[node name="Model" parent="." unique_id=178278867 instance=ExtResource("3_lp5jo")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.000101934645, 0)

View File

@@ -88,13 +88,8 @@ func can_use(player : Player, zone : Player.ActionZone) -> bool:
for area in zone.get_affected_areas():
if area is Plant:
is_there_a_plant_here = true
var is_there_contamination_in_zone = false
for tile in zone.get_tiles():
if not player.region.decontamination_layer.is_decontamined(tile):
is_there_contamination_in_zone = true
return not is_there_a_plant_here and not is_there_contamination_in_zone
return not is_there_a_plant_here and player.region.is_coords_decontaminated(zone.get_tiles())
func use(player : Player, zone : Player.ActionZone) -> bool:
if player.region == null:

View File

@@ -41,12 +41,9 @@ func use(player : Player, zone : Player.ActionZone) -> bool:
await player.get_tree().create_timer(USE_INTERVAL).timeout
var bodies = zone.area.get_overlapping_bodies()
var rock_layer_id = bodies.find_custom(func (b) : return b is RockLayer)
if rock_layer_id != -1:
var rock_layer : RockLayer = bodies[rock_layer_id]
rock_layer.dig_rocks(zone.get_tiles())
var rock_layers = bodies.filter(func (b) : return b is RockLayer)
for rock_layer in rock_layers:
player.region.dig_rocks(zone.get_tiles())
var particles := (DIG_PARTICLES.instantiate() as DigParticleEmmitter)
player.region.add_child(particles)

View File

@@ -165,7 +165,7 @@ func update_card():
func update_inspector():
if player and not get_tree().paused:
if player and (get_tree() and not get_tree().paused):
if can_interact and current_inspect and current_inspect is Interactable:
%Action.visible = true
%ActionText.text = current_inspect.interact_text()

View File

@@ -2,6 +2,8 @@ extends Node3D
const DIALOG_PATH = "res://dialogs/timelines/story/demeter_ship_presentation.dtl"
var jingle_played := false
# Cheat Code
func _input(_e):
if (
@@ -26,5 +28,6 @@ func _ready():
func _on_jingle_area_body_entered(body: Node3D):
if body is Player3D:
if body is Player3D and not jingle_played:
AudioManager.play_sfx("Ship_reveal")
jingle_played = true

View File

@@ -82,7 +82,102 @@ unique_name_in_owner = true
transform = Transform3D(0.70710677, 0, 0.70710677, 0, 1, 0, -0.70710677, 0, 0.70710677, 31.365097, -1.8906436, 31.188667)
speed = 5.0
[node name="ship_garage" parent="." unique_id=1509517206 instance=ExtResource("4_g14ji")]
[node name="ship_garage" parent="." unique_id=1531736402 instance=ExtResource("4_g14ji")]
[node name="ContourLight" type="Node3D" parent="ship_garage" unique_id=550025035]
[node name="OmniLight3D10" type="OmniLight3D" parent="ship_garage/ContourLight" unique_id=829875236]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -16.591785, 0.35355997, 8.740698)
light_color = Color(0.8780363, 0.49553913, 0.4937222, 1)
light_energy = 7.245
shadow_enabled = true
omni_range = 21.258795
[node name="OmniLight3D11" type="OmniLight3D" parent="ship_garage/ContourLight" unique_id=2048991137]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -7.7106285, 0.35355997, 16.913948)
light_color = Color(0.8780363, 0.49553913, 0.4937222, 1)
light_energy = 7.245
shadow_enabled = true
omni_range = 21.258795
[node name="OmniLight3D12" type="OmniLight3D" parent="ship_garage/ContourLight" unique_id=65773175]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -13.056013, 0.35355997, 13.631781)
light_color = Color(0.8780363, 0.49553913, 0.4937222, 1)
light_energy = 7.245
shadow_enabled = true
omni_range = 21.258795
[node name="ContourLight2" type="Node3D" parent="ship_garage" unique_id=1796913469]
transform = Transform3D(0.02940453, 0, 0.99956757, 0, 1, 0, -0.99956757, 0, 0.02940453, 0, 0, 0)
[node name="OmniLight3D10" type="OmniLight3D" parent="ship_garage/ContourLight2" unique_id=752809093]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -16.591785, 0.35355997, 8.740698)
light_color = Color(0.8780363, 0.49553913, 0.4937222, 1)
light_energy = 7.245
shadow_enabled = true
omni_range = 21.258795
[node name="OmniLight3D11" type="OmniLight3D" parent="ship_garage/ContourLight2" unique_id=670102541]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -7.7106285, 0.35355997, 16.913948)
light_color = Color(0.8780363, 0.49553913, 0.4937222, 1)
light_energy = 7.245
shadow_enabled = true
omni_range = 21.258795
[node name="OmniLight3D12" type="OmniLight3D" parent="ship_garage/ContourLight2" unique_id=1890812582]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -13.056013, 0.35355997, 13.631781)
light_color = Color(0.8780363, 0.49553913, 0.4937222, 1)
light_energy = 7.245
shadow_enabled = true
omni_range = 21.258795
[node name="ContourLight3" type="Node3D" parent="ship_garage" unique_id=1350477936]
transform = Transform3D(-0.9973743, 0, -0.07242006, 0, 1, 0, 0.07242006, 0, -0.9973743, 0, 0, 0)
[node name="OmniLight3D10" type="OmniLight3D" parent="ship_garage/ContourLight3" unique_id=455622633]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -16.591785, 0.35355997, 8.740698)
light_color = Color(0.8780363, 0.49553913, 0.4937222, 1)
light_energy = 7.245
shadow_enabled = true
omni_range = 21.258795
[node name="OmniLight3D11" type="OmniLight3D" parent="ship_garage/ContourLight3" unique_id=1267181375]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -7.7106285, 0.35355997, 16.913948)
light_color = Color(0.8780363, 0.49553913, 0.4937222, 1)
light_energy = 7.245
shadow_enabled = true
omni_range = 21.258795
[node name="OmniLight3D12" type="OmniLight3D" parent="ship_garage/ContourLight3" unique_id=1105689331]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -13.056013, 0.35355997, 13.631781)
light_color = Color(0.8780363, 0.49553913, 0.4937222, 1)
light_energy = 7.245
shadow_enabled = true
omni_range = 21.258795
[node name="ContourLight4" type="Node3D" parent="ship_garage" unique_id=1659332102]
transform = Transform3D(-0.09118883, 0, -0.99583364, 0, 1, 0, 0.99583364, 0, -0.09118883, 0, 0, 0)
[node name="OmniLight3D10" type="OmniLight3D" parent="ship_garage/ContourLight4" unique_id=1763252326]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -16.591785, 0.35355997, 8.740698)
light_color = Color(0.8780363, 0.49553913, 0.4937222, 1)
light_energy = 7.245
shadow_enabled = true
omni_range = 21.258795
[node name="OmniLight3D11" type="OmniLight3D" parent="ship_garage/ContourLight4" unique_id=683595114]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -7.7106285, 0.35355997, 16.913948)
light_color = Color(0.8780363, 0.49553913, 0.4937222, 1)
light_energy = 7.245
shadow_enabled = true
omni_range = 21.258795
[node name="OmniLight3D12" type="OmniLight3D" parent="ship_garage/ContourLight4" unique_id=919630929]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -13.056013, 0.35355997, 13.631781)
light_color = Color(0.8780363, 0.49553913, 0.4937222, 1)
light_energy = 7.245
shadow_enabled = true
omni_range = 21.258795
[node name="OmniLight3D" type="OmniLight3D" parent="ship_garage" unique_id=1914600869]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.37195766, 0.5465579, -0.44411802)

View File

@@ -2,20 +2,6 @@
extends Node2D
class_name Chunk
signal generated
var region : Region
var region_seed : int
var rock_noise_image : Noise = null
var decontamination_noise_image : Noise = null
var is_generated : bool = false :
set(v):
is_generated = true
if is_generated:
generated.emit()
var generation_finished : Array[String] = []
const GENERATION_NUMBER = 4
const NOISE_IMAGE_SIZE := 150
@@ -25,41 +11,83 @@ const MAX_DECONTAMINATION_DISTANCE=2
const ROCK_NOISE_FREQUENCY := 0.01
const DECONTAMINATION_NOISE_FREQUENCY := 0.01
@export var region_data : RegionData
@export var chunk_coord : Vector2i
var is_generated : bool = false
var rock_noise_image : Noise = null
var cristal_noise_image : Noise = null
var decontamination_noise_image : Noise = null
var rock_layer : RockLayer
var ground_layer : GroundLayer
var decontamination_layer : DecontaminationLayer
var generation_thread : Thread
var generation_semaphore : Semaphore
@export_tool_button("Update", "Callable") var update_action = func():
region_seed = randi()
generation_semaphore.post()
for c in get_children():
c.queue_free()
setup_position()
generate()
var data : ChunkData
func _init(
_data : ChunkData,
_region : Region = null,
_chunk_coord : Vector2i = Vector2i.ZERO,
_region_data : RegionData = RegionData.new(),
_generation_semaphore = Semaphore.new()
):
region = _region
if region:
region_seed = region.data.region_seed
data = _data
chunk_coord = _chunk_coord
region_data = _region_data
generation_semaphore = _generation_semaphore
func _ready():
setup_position()
async_generate()
func async_generate():
generation_thread = Thread.new()
generation_thread.start(generate)
func setup_position():
global_position = chunk_coord * (Region.CHUNK_TILE_SIZE * Region.TILE_SIZE)
func generate():
rock_noise_image = generate_noise(region_seed + 1, ROCK_NOISE_FREQUENCY)
decontamination_noise_image = generate_noise(region_seed + 2, DECONTAMINATION_NOISE_FREQUENCY)
global_position = data.chunk_coord * (Region.CHUNK_TILE_SIZE * Region.TILE_SIZE)
generate_rocks()
generate_ground()
generate_decontamination()
rock_noise_image = generate_noise(region_data.region_seed + 1, ROCK_NOISE_FREQUENCY)
decontamination_noise_image = generate_noise(region_data.region_seed + 2, DECONTAMINATION_NOISE_FREQUENCY)
cristal_noise_image = generate_noise(region_data.region_seed + 3, ROCK_NOISE_FREQUENCY)
rock_layer = RockLayer.new(region_data)
ground_layer = GroundLayer.new(region_data)
decontamination_layer = DecontaminationLayer.new(region_data)
func finish_one_generation(generation_name : String):
generation_finished.append(generation_name)
if len(generation_finished) >= GENERATION_NUMBER:
is_generated = true
generation_semaphore.wait()
func unload():
for x in range(Region.CHUNK_TILE_SIZE):
for y in range(Region.CHUNK_TILE_SIZE):
var global_coord = Vector2i(x, y) + Region.CHUNK_TILE_SIZE * data.chunk_coord
region.rock_layer.erase_cell(global_coord)
region.ground_layer.erase_cell(global_coord)
region.decontamination_layer.erase_cell(global_coord)
generate_rocks(rock_layer)
generate_ground(ground_layer)
generate_decontamination(decontamination_layer)
generation_semaphore.post()
# clear_padding_cells(rock_layer)
add_child.call_deferred(rock_layer)
add_child.call_deferred(ground_layer)
add_child.call_deferred(decontamination_layer)
is_generated = true
# func unload():
# for x in range(Region.CHUNK_TILE_SIZE):
# for y in range(Region.CHUNK_TILE_SIZE):
# var global_coord = Vector2i(x, y) + Region.CHUNK_TILE_SIZE * chunk_coord
# region.rock_layer.erase_cell(global_coord)
# region.ground_layer.erase_cell(global_coord)
# region.decontamination_layer.erase_cell(global_coord)
# Debug
# func _draw():
@@ -94,8 +122,8 @@ func generate_noise(
noise.fractal_type = FastNoiseLite.FRACTAL_NONE
noise.fractal_weighted_strength = 1.0
noise.offset = Vector3(
noise_image_size.x * data.chunk_coord.x,
noise_image_size.y * data.chunk_coord.y,
noise_image_size.x * chunk_coord.x,
noise_image_size.y * chunk_coord.y,
1
)
@@ -108,62 +136,80 @@ func get_tile_value_from_noise(tile_position : Vector2i, noise : Noise) -> float
)
return (val + 1)/2
func generate_rocks():
func generate_rocks(layer : RockLayer):
var cristals : Array[Vector2i] = []
var rocks : Array[Vector2i] = []
for x in range(Region.CHUNK_TILE_SIZE):
for y in range(Region.CHUNK_TILE_SIZE):
for x in range(0, Region.CHUNK_TILE_SIZE):
for y in range(0, Region.CHUNK_TILE_SIZE):
var tile_type := get_generated_rock_type(Vector2i(x, y))
var global_coord = Vector2i(x, y) + Region.CHUNK_TILE_SIZE * data.chunk_coord
var coord = Vector2i(x, y)
if tile_type == RockLayer.TileType.CRISTAL:
cristals.append(global_coord)
cristals.append(coord)
elif tile_type == RockLayer.TileType.ROCK:
rocks.append(global_coord)
rocks.append(coord)
region.rock_layer.place_rocks(cristals, RockLayer.TileType.CRISTAL, func(): finish_one_generation("rock"))
region.rock_layer.place_rocks(rocks, RockLayer.TileType.ROCK, func(): finish_one_generation("cristal"))
layer.place_rocks(cristals, RockLayer.TileType.CRISTAL)
layer.place_rocks(rocks, RockLayer.TileType.ROCK)
func get_generated_rock_type(coord : Vector2i) -> RockLayer.TileType:
var tile_value : float = get_tile_value_from_noise(coord, rock_noise_image)
var saved_diff := data.get_rock_tile_diff(coord)
var rock_tile_value : float = get_tile_value_from_noise(coord, rock_noise_image)
var cristal_tile_value : float = get_tile_value_from_noise(coord, cristal_noise_image)
var saved_diff := region_data.rock_tiles_data.get_tile_diff_for_local_coord(coord, chunk_coord)
if (
(saved_diff == ChunkData.TileDiff.PRESENT or tile_value < region.data.rock_threshold)
and saved_diff != ChunkData.TileDiff.ABSENT
if saved_diff == TilesDiffData.TileDiff.ABSENT:
return RockLayer.TileType.EMPTY
elif saved_diff == TilesDiffData.TileDiff.PRESENT:
return RockLayer.TileType.ROCK
elif (
rock_tile_value < region_data.rock_threshold
):
return RockLayer.TileType.CRISTAL if tile_value < region.data.cristal_threshold else RockLayer.TileType.ROCK
return RockLayer.TileType.EMPTY
return RockLayer.TileType.CRISTAL if cristal_tile_value < region_data.cristal_threshold else RockLayer.TileType.ROCK
else :
return RockLayer.TileType.EMPTY
func generate_ground():
func generate_ground(layer : GroundLayer):
var coords : Array[Vector2i] = []
for x in range(Region.CHUNK_TILE_SIZE):
for y in range(Region.CHUNK_TILE_SIZE):
coords.append(Vector2i(x,y) + Region.CHUNK_TILE_SIZE * data.chunk_coord)
for x in range(0, Region.CHUNK_TILE_SIZE):
for y in range(0,Region.CHUNK_TILE_SIZE):
coords.append(Vector2i(x,y))
region.ground_layer.place_ground(coords, func(): finish_one_generation("ground"))
layer.place_ground(coords)
func generate_decontamination():
func generate_decontamination(layer : DecontaminationLayer):
var decontamination_tiles : Array[Vector2i] = []
for x in range(Region.CHUNK_TILE_SIZE):
for y in range(Region.CHUNK_TILE_SIZE):
for x in range(0, Region.CHUNK_TILE_SIZE):
for y in range(0, Region.CHUNK_TILE_SIZE):
var coord = Vector2i(x,y)
var tile_value : float = (
1. if data.chunk_coord.distance_to(Vector2i.ZERO) > MAX_DECONTAMINATION_DISTANCE
1. if chunk_coord.distance_to(Vector2i.ZERO) > MAX_DECONTAMINATION_DISTANCE
else get_tile_value_from_noise(coord, decontamination_noise_image)
)
var saved_diff := data.get_decontamination_tile_diff(coord)
var saved_diff : TilesDiffData.TileDiff = region_data.decontamination_tiles_data.get_tile_diff_for_local_coord(coord, chunk_coord)
if (
(
saved_diff == ChunkData.TileDiff.PRESENT
or (tile_value < region.data.decontamination_threshold)
(tile_value < region_data.decontamination_threshold)
or saved_diff == TilesDiffData.TileDiff.PRESENT
)
and saved_diff != ChunkData.TileDiff.ABSENT
and saved_diff != TilesDiffData.TileDiff.ABSENT
):
decontamination_tiles.append(Vector2i(x,y) + Region.CHUNK_TILE_SIZE * data.chunk_coord)
decontamination_tiles.append(Vector2i(x,y))
region.decontamination_layer.place_decontaminations(
layer.place_decontaminations(
decontamination_tiles,
false,
func():
finish_one_generation("decontamination")
)
func clear_padding_cells(layer : RegionLayer):
var coords : Array[Vector2i] = []
for x in [-1, Region.CHUNK_TILE_SIZE + 1]:
for y in range(-1, Region.CHUNK_TILE_SIZE + 1):
coords.append(Vector2i(x,y))
for y in [-1, Region.CHUNK_TILE_SIZE + 1]:
for x in range(0, Region.CHUNK_TILE_SIZE + 1):
coords.append(Vector2i(x,y))
layer.set_cells_terrain_connect(coords, 0, -1)
func _exit_tree():
generation_thread.wait_to_finish()

View File

@@ -1,62 +0,0 @@
extends Resource
class_name ChunkData
enum TileDiff { NO_DIFF,PRESENT,ABSENT }
@export var chunk_coord : Vector2i
@export var rock_tiles_diff : Dictionary[String, TileDiff]
@export var decontamination_tiles_diff : Dictionary[String, TileDiff]
func _init(
_chunk_coord : Vector2i = Vector2i.ZERO
):
chunk_coord = _chunk_coord
#region ------------------ Generic Tile ------------------
func get_coord_key(coord : Vector2i) -> String:
return "%d:%d" % [coord.x, coord.y]
func get_tile_diff(
coord : Vector2i,
tiles_diff : Dictionary[String, TileDiff]
) -> TileDiff:
if not has_diff(coord, tiles_diff):
return TileDiff.NO_DIFF
return tiles_diff[get_coord_key(coord)]
func update_tile_diff(
coord : Vector2i,
diff : TileDiff,
tiles_diff : Dictionary[String, TileDiff]
):
tiles_diff[get_coord_key(coord)] = diff
func has_diff(
coord : Vector2i,
tiles_diff : Dictionary[String, TileDiff]
):
return tiles_diff.has(get_coord_key(coord))
#region ------------------ Rock ------------------
func get_rock_tile_diff(coord : Vector2i) -> TileDiff:
return get_tile_diff(coord, rock_tiles_diff)
func update_rock_tile_diff(coord : Vector2i, diff : TileDiff):
update_tile_diff(coord, diff, rock_tiles_diff)
func has_rock_tile_diff(coord : Vector2i):
return has_diff(coord, rock_tiles_diff)
#region ------------------ Decontamination ------------------
func get_decontamination_tile_diff(coord : Vector2i) -> TileDiff:
return get_tile_diff(coord, decontamination_tiles_diff)
func update_decontamination_tile_diff(coord : Vector2i, diff : TileDiff):
update_tile_diff(coord, diff, decontamination_tiles_diff)
func has_decontamination_tile_diff(coord : Vector2i):
return has_diff(coord, decontamination_tiles_diff)

View File

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

View File

@@ -8,8 +8,6 @@ const TUTORIAL_SCENE : PackedScene = preload("res://gui/game/tutorial/tutorial.t
const TILE_SET : TileSet = preload("res://stages/terrain/region/resources/moss_biome.tres")
const TILE_SCALE = 1
const TILE_SIZE : int = roundi(TILE_SET.tile_size.x * TILE_SCALE)
const START_ROCK_HOLE_RADIUS = 5
const PLAYER_ROCK_HOLE_RADIUS = 5
const SPAWN_OBJECT_RANDOM_MOVEMENT = 200
const CHUNK_TILE_SIZE : int = 20
@@ -17,6 +15,8 @@ const CHUNK_SIZE = CHUNK_TILE_SIZE * TILE_SIZE
const CHUNK_LOAD_DISTANCE : int = 1
const CHUNK_UNLOAD_DISTANCE : int = 2
const MAX_GENERATION_THREAD = 1 # Crash when superior to 1
@export var first_loot_number : int = 3
@export var loot_item_number : Array[int] = [1,2]
@@ -28,23 +28,20 @@ var data : RegionData
var in_passing_day_animation = false
var contamination_texture : ImageTexture
var rock_layer : RockLayer
var ground_layer : GroundLayer
var decontamination_layer : DecontaminationLayer
var creating_new_layer_pack = false
var score_by_plant : Dictionary[PlantData, int] = {}
var tile_set = Region.TILE_SET
var generated_chunks : Dictionary[String,Chunk] = {}
var generation_semaphore: Semaphore
var generated_chunks : Array[Chunk] = []
var generation_semaphore : Semaphore
# Cheat Code
func _input(_e):
if (
Input.is_action_pressed("drop")
and Input.is_action_pressed("move_right")
and Input.is_action_pressed("move_left")
and Input.is_action_pressed("move_left")
and Input.is_action_just_pressed("action")
):
%Tutorial.finish_tutorial()
@@ -55,7 +52,7 @@ func _input(_e):
if (
Input.is_action_pressed("drop")
and Input.is_action_pressed("move_right")
and Input.is_action_pressed("move_left")
and Input.is_action_pressed("move_left")
and Input.is_action_just_pressed("move_pointer")
):
data.charges = 0
@@ -66,7 +63,7 @@ func _init():
func _ready():
generation_semaphore = Semaphore.new()
generation_semaphore.post()
generation_semaphore.post(MAX_GENERATION_THREAD)
entity_container.position = TILE_SIZE * CHUNK_TILE_SIZE * Vector2.ONE / 2
load_entities(data.entities_saved_data)
@@ -75,16 +72,6 @@ func _ready():
if e is Plant:
data.add_plant_data(e.data, false)
ground_layer = GroundLayer.new(self)
ground_layer.name = "GroundLayer"
add_child(ground_layer)
rock_layer = RockLayer.new(self)
rock_layer.name = "RockLayer"
add_child(rock_layer)
decontamination_layer = DecontaminationLayer.new(self)
decontamination_layer.name = "DecontaminationLayer"
add_child(decontamination_layer)
%AstraDoor.global_position = data.player_spawn
player.global_position = data.player_position
@@ -92,8 +79,6 @@ func _ready():
generate_near_chunks(player)
edit_map_origin()
spawn_object_random_move(%RechargeStation)
%RechargeStation.update()
spawn_object_random_move(%BoreaDoor)
@@ -108,94 +93,60 @@ func _process(_d):
func get_chunk_key(coord) -> String:
return "%d:%d" % [coord.x, coord.y]
func generate_near_chunks(p : Player):
func generate_near_chunks(p : Player) -> bool:
var new_chunk_created = false
var player_chunk_coord = Math.get_chunk_from_pos(p.global_position)
for x in range(-CHUNK_LOAD_DISTANCE, CHUNK_LOAD_DISTANCE+1):
for y in range(-CHUNK_LOAD_DISTANCE, CHUNK_LOAD_DISTANCE+1):
var coord : Vector2i = Vector2i(x,y) + player_chunk_coord
if not generated_chunks.has(get_chunk_key(coord)):
if (not is_chunk_generated(coord)):
generate_chunk(coord)
new_chunk_created = true
return new_chunk_created
func remove_far_chunks(p : Player):
func remove_far_chunks(p : Player) -> bool:
var chunk_deleted = false
var player_chunk_coord = Vector2i(
floor(p.global_position.x / (CHUNK_TILE_SIZE * TILE_SIZE)),
floor(p.global_position.y / (CHUNK_TILE_SIZE * TILE_SIZE))
)
for chunk in generated_chunks.values():
var chunk_coord = chunk.data.chunk_coord
for chunk in generated_chunks:
var chunk_coord = chunk.chunk_coord
if player_chunk_coord.distance_to(chunk_coord) > CHUNK_UNLOAD_DISTANCE:
remove_chunk(chunk)
chunk_deleted = true
return chunk_deleted
func generate_chunk(coord : Vector2i):
var chunk_data := data.get_or_create_chunk_data(coord)
var chunk_key = get_chunk_key(coord)
if not generated_chunks.has(chunk_key):
if not is_chunk_generated(coord):
var new_chunk = Chunk.new(
chunk_data,
self
coord,
data,
generation_semaphore
)
generated_chunks[chunk_key] = new_chunk
add_child(new_chunk)
data.generated_chunk_entities.append(coord)
new_chunk.generate()
func edit_map_origin():
# Dig a hole in map origin
var chunk_center = Vector2i.ONE * floori(CHUNK_TILE_SIZE/2.)
var hole_tiles : Array[Vector2i] = []
var decontamination_tiles : Array[Vector2i] = []
for x in range(CHUNK_TILE_SIZE):
for y in range(CHUNK_TILE_SIZE):
var coord = Vector2i(x,y)
if coord.distance_to(chunk_center) < START_ROCK_HOLE_RADIUS:
hole_tiles.append(coord)
if coord.distance_to(chunk_center) < data.start_decontamination_hole_radius:
decontamination_tiles.append(coord)
rock_layer.remove_rocks(hole_tiles, true)
decontamination_layer.place_decontaminations(decontamination_tiles, true)
# Dig a hole in player spawn
var player_hole_tiles : Array[Vector2i] = []
var player_tile_position := Vector2i(
roundi(data.player_spawn.x/float(TILE_SIZE)),
roundi(data.player_spawn.y/float(TILE_SIZE))
)
for x in range(-PLAYER_ROCK_HOLE_RADIUS, PLAYER_ROCK_HOLE_RADIUS):
for y in range(-PLAYER_ROCK_HOLE_RADIUS, PLAYER_ROCK_HOLE_RADIUS):
var coord = Vector2i(x,y)
if coord.distance_to(Vector2.ZERO) < PLAYER_ROCK_HOLE_RADIUS:
player_hole_tiles.append(coord + player_tile_position)
rock_layer.remove_rocks(player_hole_tiles, true)
generated_chunks.append(new_chunk)
func remove_chunk(chunk : Chunk):
generated_chunks.erase(get_chunk_key(chunk.data.chunk_coord))
chunk.unload()
generated_chunks.erase(chunk)
chunk.queue_free()
func check_is_generated() -> bool:
if len(generated_chunks.keys()) == 0:
return false
return get_chunk_generation_count() == float(get_full_chunk_generation_count())
var ret = true
for c in generated_chunks:
if not c.is_generated:
ret = false
return ret
func get_generated_value():
return get_chunk_generation_count() / float(get_full_chunk_generation_count())
func get_full_chunk_generation_count() -> int:
return len(generated_chunks.keys()) * Chunk.GENERATION_NUMBER
func get_chunk_generation_count() -> int:
var generation_count = 0
for key in generated_chunks.keys():
generation_count += len(generated_chunks[key].generation_finished)
return generation_count
func get_generated_value() -> float:
# if layer_pack:
# return layer_pack.generated_value
return 1.
func save():
data.entities_saved_data = save_entities()
@@ -232,6 +183,10 @@ func setup_flagged_properties():
%BoreaDoor.visible = true
%RechargeStation.visible = false
func is_chunk_generated(coord : Vector2i):
return generated_chunks.find_custom(
func (c: Chunk) : return get_chunk_key(c.chunk_coord) == get_chunk_key(coord)
) != -1
#endregion
#region ------------------ Usage ------------------
@@ -269,4 +224,51 @@ func pass_day():
data.end_pass_day()
save()
func get_chunk_for_coord(tiles_coord : Vector2i) -> Chunk:
var chunk_coord = Vector2i(
floori(float(tiles_coord.x)/Region.CHUNK_TILE_SIZE),
floori(float(tiles_coord.y)/Region.CHUNK_TILE_SIZE),
)
var id = generated_chunks.find_custom(
func (c: Chunk): return c.chunk_coord.x == chunk_coord.x and c.chunk_coord.y == chunk_coord.y
)
if id == -1 or not generated_chunks[id].is_generated:
return null
return generated_chunks[id]
func is_coords_decontaminated(tiles_coords : Array[Vector2i]):
for coord in tiles_coords:
var chunk : Chunk = get_chunk_for_coord(coord)
if chunk:
var local_coord := TilesDiffData.get_local_coord(coord, chunk.chunk_coord)
if not chunk.decontamination_layer.is_decontamined(local_coord):
return false
return true
func dig_rocks(tiles_coords : Array[Vector2i], save_tiles_diff := true, loot := true):
if save_tiles_diff :
data.rock_tiles_data.update_tiles_diff(tiles_coords, TilesDiffData.TileDiff.ABSENT)
for coord in tiles_coords:
var chunk : Chunk = get_chunk_for_coord(coord)
if chunk:
var local_coord := TilesDiffData.get_local_coord(coord, chunk.chunk_coord)
if loot and chunk.rock_layer.get_tile_type(local_coord) == RockLayer.TileType.CRISTAL:
loot_talion(coord)
chunk.rock_layer.remove_rocks([local_coord])
func loot_talion(coord : Vector2i):
var new_seed = Seed.generate_random()
drop_item(
new_seed,
coord * TILE_SIZE,
10
)
#endregion

View File

@@ -14,6 +14,8 @@ signal pass_day_ended(region_data : RegionData)
const DEFAULT_START_CHARGE := 10
const DEFAULT_OBJECTIVE := 10
const MAX_RANDOM_SPAWN_DISTANCE = 3000
const START_ROCK_HOLE_RADIUS = 5
const PLAYER_ROCK_HOLE_RADIUS = 5
@export var region_seed : int
@export var region_name : String
@@ -26,14 +28,11 @@ const MAX_RANDOM_SPAWN_DISTANCE = 3000
@export var day : int = 1
@export var entities_saved_data : Array[EntityData] = []
@export var generated_chunk_entities : Array[Vector2i]
@export var flags : Array[String] = []
@export var plants : Array[PlantData]
@export var state : State = State.IN_PROGRESS
@export var chunks_data : Dictionary[String, ChunkData]
@export var player_position : Vector2
@export var player_spawn : Vector2
@@ -47,6 +46,8 @@ const MAX_RANDOM_SPAWN_DISTANCE = 3000
objective = v
update()
@export var rock_tiles_data : TilesDiffData
@export var decontamination_tiles_data : TilesDiffData
var in_passing_day_animation := false
@@ -67,6 +68,11 @@ func _init(
player_spawn = get_random_spawn_position()
player_position = player_spawn
rock_tiles_data = TilesDiffData.new()
decontamination_tiles_data = TilesDiffData.new()
edit_map_origin()
func update():
if objective > 0 and get_score() >= objective and not "tutorial" in flags:
if state != State.SUCCEEDED:
@@ -78,30 +84,6 @@ func update():
state = State.FAILED
updated.emit(self)
#region ------------------ Chunks ------------------
func get_coord_id(coord):
return "%d:%d" % [coord.x, coord.y]
func has_chunk_data(coord : Vector2i) -> bool:
return chunks_data.has(get_coord_id(coord))
func add_chunk_data(coord : Vector2i, data : ChunkData):
chunks_data[get_coord_id(coord)] = data
func get_chunk_data(coord : Vector2i) -> ChunkData:
if get_coord_id(coord) in chunks_data:
return chunks_data[get_coord_id(coord)]
return null
func get_or_create_chunk_data(coord : Vector2i) -> ChunkData:
if has_chunk_data(coord):
return get_chunk_data(coord)
else:
var new_chunk_data = ChunkData.new(coord)
add_chunk_data(coord, new_chunk_data)
return new_chunk_data
#endregion
#region ------------------ Score ------------------
@@ -159,3 +141,36 @@ func get_random_spawn_position():
return rand_pos
#endregion
#region ------------------ Tiles ------------------
func edit_map_origin():
# Dig a hole in map origin
var chunk_center = Vector2i.ONE * floori(Region.CHUNK_TILE_SIZE/2.)
var hole_tiles : Array[Vector2i] = []
var decontamination_tiles : Array[Vector2i] = []
for x in range(Region.CHUNK_TILE_SIZE):
for y in range(Region.CHUNK_TILE_SIZE):
var coord = Vector2i(x,y)
if coord.distance_to(chunk_center) < START_ROCK_HOLE_RADIUS:
hole_tiles.append(coord)
if coord.distance_to(chunk_center) < start_decontamination_hole_radius:
decontamination_tiles.append(coord)
rock_tiles_data.update_tiles_diff(hole_tiles, TilesDiffData.TileDiff.ABSENT)
# Dig a hole in player spawn
var player_hole_tiles : Array[Vector2i] = []
var player_tile_position := Vector2i(
roundi(player_spawn.x/float(Region.TILE_SIZE)),
roundi(player_spawn.y/float(Region.TILE_SIZE))
)
for x in range(-PLAYER_ROCK_HOLE_RADIUS, PLAYER_ROCK_HOLE_RADIUS):
for y in range(-PLAYER_ROCK_HOLE_RADIUS, PLAYER_ROCK_HOLE_RADIUS):
var coord = Vector2i(x,y)
if coord.distance_to(Vector2.ZERO) < PLAYER_ROCK_HOLE_RADIUS:
player_hole_tiles.append(coord + player_tile_position)
rock_tiles_data.update_tiles_diff(player_hole_tiles, TilesDiffData.TileDiff.ABSENT)
#endregion

View File

@@ -11,22 +11,12 @@ func setup():
func place_decontamination(coord : Vector2i, save = false):
place_decontaminations([coord], save)
func place_decontaminations(coords : Array[Vector2i], save := false, on_finished : Callable = (func(): pass)):
async_place_terrain_cells(
func place_decontaminations(coords : Array[Vector2i], save := false):
place_terrain_cells(
coords,
DECONTAMINATION_TILE_TERRAIN_SET,
DECONTAMINATION_TILE_TERRAIN,
on_finished
)
if save:
for coord in coords:
var chunk_coord = Vector2i(
floori(coord.x / float(Region.CHUNK_TILE_SIZE)),
floori(coord.y / float(Region.CHUNK_TILE_SIZE)),
)
(region.data
.get_or_create_chunk_data(chunk_coord)
.update_decontamination_tile_diff(coord, ChunkData.TileDiff.PRESENT))
func is_decontamined(coord : Vector2i) -> bool:
return has_cell(coord)

View File

@@ -10,10 +10,9 @@ func setup():
material = MATERIAL
z_index = -100
func place_ground(coords : Array[Vector2i], on_finished : Callable = (func(): pass)):
async_place_terrain_cells(
func place_ground(coords : Array[Vector2i]):
place_terrain_cells(
coords,
GROUND_TILE_TERRAIN_SET,
GROUND_TILE_TERRAIN,
on_finished
)

View File

@@ -1,20 +1,22 @@
@tool
@abstract
extends TileMapLayer
class_name RegionLayer
var threads : Array[Thread] = []
var is_generated = false
var region : Region
@export var region_data : RegionData
func _init(
_planet : Region = null
_region_data : RegionData
):
region = _planet
func _ready():
tile_set = region.tile_set
set_physics_quadrant_size(Region.CHUNK_TILE_SIZE)
set_rendering_quadrant_size(Region.CHUNK_TILE_SIZE)
tile_set = Region.TILE_SET
scale = Vector2.ONE * Region.TILE_SCALE
navigation_enabled = false
region_data = _region_data
# collision_visibility_mode = DebugVisibilityMode.DEBUG_VISIBILITY_MODE_FORCE_SHOW
func _ready():
setup()
func setup():
@@ -35,37 +37,22 @@ func get_all_neighbors_cell(coord : Vector2i) -> Array[Vector2i]:
func has_cell(tile_position : Vector2i) -> bool:
return get_cell_source_id(tile_position) != -1
func async_place_terrain_cells(
coords : Array[Vector2i],
tile_terrain_set : int = 0,
tile_terrain : int = 0,
on_finished : Callable = (func(): pass)
):
var thread = Thread.new()
threads.append(thread)
thread.start(
func ():
place_terrain_cells(
coords,
tile_terrain_set,
tile_terrain
)
on_finished.call_deferred()
)
func place_terrain_cells(
coords : Array[Vector2i],
tile_terrain_set : int = 0,
tile_terrain : int = 0
):
region.generation_semaphore.wait()
var valid_coords : Array[Vector2i] = coords.filter(is_coord_valid)
set_cells_terrain_connect(
coords,
valid_coords,
tile_terrain_set,
tile_terrain
)
region.generation_semaphore.post()
func _exit_tree():
for t in threads:
t.wait_to_finish()
func is_coord_valid(coord : Vector2i) -> bool:
return (
coord.x >= 0
and coord.y >= 0
and coord.x < Region.CHUNK_TILE_SIZE
and coord.y < Region.CHUNK_TILE_SIZE
)

View File

@@ -6,61 +6,26 @@ const ROCK_TILE_TERRAIN_SET : int = 0
const ROCK_TILE_TERRAIN : int = 1
const CRISTAL_TILE_TERRAIN : int = 2
const CRISTAL_LOOT_CHANCE : float = 1
enum TileType { EMPTY,ROCK,CRISTAL }
func setup():
z_index = -1
func place_rocks(coords : Array[Vector2i], type := TileType.ROCK,on_finished : Callable = (func(): pass)):
func place_rocks(coords : Array[Vector2i], type := TileType.ROCK):
if type != TileType.EMPTY:
async_place_terrain_cells(
place_terrain_cells(
coords,
ROCK_TILE_TERRAIN_SET,
ROCK_TILE_TERRAIN if type == TileType.ROCK else CRISTAL_TILE_TERRAIN,
on_finished
)
func remove_rocks(coords : Array[Vector2i], save = false,on_finished : Callable = (func(): pass)):
async_place_terrain_cells(
func remove_rocks(coords : Array[Vector2i], save = false):
place_terrain_cells(
coords,
ROCK_TILE_TERRAIN_SET,
-1,
on_finished
-1
)
if save:
for coord in coords:
var chunk_coord = Vector2i(
floori(coord.x / float(Region.CHUNK_TILE_SIZE)),
floori(coord.y / float(Region.CHUNK_TILE_SIZE)),
)
var chunk_tile_coord : Vector2i = coord - chunk_coord * Region.CHUNK_TILE_SIZE
(region.data
.get_or_create_chunk_data(chunk_coord)
.update_rock_tile_diff(chunk_tile_coord, ChunkData.TileDiff.ABSENT))
func dig_rocks(coords : Array[Vector2i]) -> bool:
var has_rock = false
for coord in coords:
if has_tile(coord):
has_rock = true
loot_rock(coord)
if has_rock:
remove_rocks(coords, true)
return has_rock
func loot_rock(coord : Vector2i):
if get_tile_type(coord) == TileType.CRISTAL and randf() < CRISTAL_LOOT_CHANCE:
var loot = Seed.generate_random()
region.drop_item(
loot,
coord * Region.TILE_SIZE + Vector2i.ONE * floori(Region.TILE_SIZE/2.),
floor(Region.TILE_SIZE/2.)
)
func has_tile(coord : Vector2i) -> bool:
return has_cell(coord)

View File

@@ -0,0 +1,46 @@
extends Resource
class_name TilesDiffData
enum TileDiff { NO_DIFF,PRESENT,ABSENT }
@export var tiles_diff : Dictionary[String, TileDiff]
static func get_coord_key(coord : Vector2i) -> String:
return "%d:%d" % [coord.x, coord.y]
static func get_global_coord(local_coord : Vector2i, chunk_coord : Vector2i, ) -> Vector2i:
return local_coord + (Vector2i.ONE * Region.CHUNK_TILE_SIZE * chunk_coord)
static func get_local_coord(coord : Vector2i, chunk_coord : Vector2i, ) -> Vector2i:
return coord - (Vector2i.ONE * Region.CHUNK_TILE_SIZE * chunk_coord)
func get_tile_diff(
coord : Vector2i,
) -> TileDiff:
if not has_diff(coord):
return TileDiff.NO_DIFF
return tiles_diff[get_coord_key(coord)]
func get_tile_diff_for_local_coord(
local_coord : Vector2i,
chunk_coord : Vector2i
) -> TileDiff:
return get_tile_diff(get_global_coord(local_coord, chunk_coord))
func update_tile_diff(
coord : Vector2i,
diff : TileDiff,
):
tiles_diff[get_coord_key(coord)] = diff
func update_tiles_diff(
coords : Array[Vector2i],
diff : TileDiff,
):
for coord in coords:
tiles_diff[get_coord_key(coord)] = diff
func has_diff(
coord : Vector2i,
):
return tiles_diff.has(get_coord_key(coord))

View File

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

View File

@@ -0,0 +1,26 @@
[gd_scene format=3 uid="uid://dtfuxosn6s0cr"]
[ext_resource type="Script" uid="uid://d2ixbaa2uqlv4" path="res://stages/terrain/region/scripts/chunk.gd" id="1_mhr83"]
[ext_resource type="Script" uid="uid://bgbbce45hjv3d" path="res://entities/scripts/entity_data.gd" id="2_tiw8g"]
[ext_resource type="Script" uid="uid://da6j333qs7wse" path="res://entities/plants/scripts/plant_data.gd" id="3_ct7cr"]
[ext_resource type="Script" uid="uid://cx30nvq8b34lj" path="res://stages/terrain/region/scripts/region_data.gd" id="4_0rtv3"]
[sub_resource type="Resource" id="Resource_tiw8g"]
script = ExtResource("4_0rtv3")
rock_threshold = 0.5
decontamination_threshold = 0.5
metadata/_custom_type_script = "uid://cx30nvq8b34lj"
[node name="TestChunk" type="Node2D" unique_id=990498648]
[node name="Chunk" type="Node2D" parent="." unique_id=709095052]
script = ExtResource("1_mhr83")
region_data = SubResource("Resource_tiw8g")
metadata/_custom_type_script = "uid://d2ixbaa2uqlv4"
[node name="Chunk2" type="Node2D" parent="." unique_id=509661921]
position = Vector2(1280, 0)
script = ExtResource("1_mhr83")
region_data = SubResource("Resource_tiw8g")
chunk_coord = Vector2i(1, 0)
metadata/_custom_type_script = "uid://d2ixbaa2uqlv4"

View File

@@ -10,7 +10,7 @@ PLANT_INFO_TEXT,"[b]1[/b] Name
[b]2[/b] Archétype
[b]3[/b] Score
[b]4[/b] Age
[b]5[/b] Durée de pousse
[b]5[/b] Temps de croissance
[b]6[/b] Durée de vie"
TERRAINS,Terrains,Terrains
FERTILE_LAND_TEXT,[b]Fertile Land[/b] Seeds can only be planted on this zone,[b]Terre fertile[/b] Des graines peuvent être plantées dans cette zone
@@ -143,7 +143,7 @@ CHOOSE_A_LANGUAGE,Choose a language,Choisissez une langue
NO_ENERGY_LEFT," (no energy left)", " (pas d'énergie restante)"
%d_GARDEN_SCORE_LEFT,"%d garden score left","%d score de jardin restant"
SETTINGS,Settings,Paramètres
LANGUAGE,Language,Language
LANGUAGE,Language,Langage
SOUND,Sound,Son
MUSIC_VOLUME,Music volume,Volume de la musique
ENVIRONMENT_VOLUME,Environment Volume,Volume de l'environnement
1 keys en fr
10 GARDEN Garden Jardin
11 COMMA , ,
12 OR or ou
13 PAUSE Pause Pause
14 CONTROLS Controls Contrôles
15 RESUME_GAME Resume Reprendre
16 RESTART Restart Recommencer
143 CONTROLS Controls Contrôles
144 MOVE_RIGHT Move right Déplacement à droite
145 MOVE_LEFT Move left Déplacement à gauche
146 MOVE_UP Move up Déplacement en haut
147 MOVE_DOWN Move down Déplacement en bas
148 ACTION Action Action
149 DROP Drop Lacher