This commit is contained in:
E250429F
2026-09-17 23:19:43 +02:00
parent 025a866eef
commit 3e857fa9f3
281 changed files with 38006 additions and 970 deletions
+67
View File
@@ -0,0 +1,67 @@
extends CharacterBody3D
@onready var anim_player: AnimationPlayer = $cow/AnimationPlayer
@export var dest_array:Array[Marker3D]
@onready var navigation_agent: NavigationAgent3D = $NavigationAgent3D
@onready var idle_timer: Timer = $Timer
enum NPCSTATE {
IDLE,
WALKING
}
var cur_state : NPCSTATE
var cur_destination: Marker3D
var speed = 4
@onready var audio_moo: AudioStreamPlayer3D = $AudioMoo
@onready var moo_timer: Timer = $MooTimer
var one_time_each : bool = false
func _ready() -> void:
_set_state( NPCSTATE.IDLE )
func _on_timer_timeout() -> void:
decide_next_state()
func _set_state(new_state:NPCSTATE):
cur_state = new_state
match cur_state:
NPCSTATE.IDLE:
idle_timer.start( randf_range(3, 5) )
anim_player.play("metarig|metarig|walking", -1, .7 )
NPCSTATE.WALKING:
anim_player.play("metarig|metarig|walking", -1, 1.7 )
func _physics_process(delta: float) -> void:
match cur_state:
NPCSTATE.IDLE:
pass
NPCSTATE.WALKING:
var next_path_pos:Vector3 = navigation_agent.get_next_path_position()
var new_vel : Vector3 = global_position.direction_to( next_path_pos ) * speed
velocity = new_vel
var look_at_target : Vector3 = Vector3( next_path_pos.x, global_position.y, next_path_pos.z )
if not global_position.is_equal_approx( look_at_target ):
look_at( look_at_target )
move_and_slide()
func decide_next_state():
if cur_state == NPCSTATE.IDLE:
cur_destination = dest_array.pick_random()
navigation_agent.target_position = cur_destination.global_position
_set_state( NPCSTATE.WALKING )
func _on_navigation_agent_3d_navigation_finished() -> void:
_set_state( NPCSTATE.IDLE )
func _on_moo_timer_timeout() -> void:
moo_timer.wait_time = randf_range(40, 60)
audio_moo.pitch_scale = randf_range( .8, 1.2 )
audio_moo.play()
+1
View File
@@ -0,0 +1 @@
uid://xqjom65pdi52
+157
View File
@@ -0,0 +1,157 @@
extends CharacterBody3D
## --- Paramètres à régler dans l'inspecteur ---
@export var player: Node3D # Référence au joueur (à assigner dans l'inspecteur ou via groupe)
@export var flee_enabled: bool = false # Si false, l'animal ne fuit jamais, il se balade juste dans sa zone
@export var move_speed: float = 4.8
@export var acceleration: float = 12
@export var rotation_speed: float = 5
@export_group("Zone de confinement")
@export var zone_center: Vector3 = Vector3.ZERO # Centre de la zone (en coordonnées globales)
@export var zone_size: Vector2 = Vector2(30.0, 30.0) # Largeur (x) et profondeur (z) du rectangle
@export var zone_rotation_degrees: float = 0.0 # Rotation du rectangle autour de l'axe Y
@export var zone_margin: float = 1.5 # Marge de sécurité avant le bord
@export_group("Comportement idle")
@export var wander_enabled: bool = true
@export var wander_radius: float = 5.0
@export var wander_interval: float = 3.0
var _wander_target: Vector3
var _wander_timer: float = 0.0
var _state: String = "idle" # "idle" ou "flee"
# --- NOUVEAU : Variables pour gérer le déblocage sur les bords ---
var _stuck_timer: float = 0.0
var _sidestep_direction: float = 1.0 # 1.0 pour droite, -1.0 pour gauche
@onready var anim_player: AnimationPlayer = $foxes/AnimationPlayer
func _ready() -> void:
_wander_target = global_position
if player == null:
var players := get_tree().get_nodes_in_group("player")
if players.size() > 0:
player = players[0]
func _physics_process(delta: float) -> void:
if not player == null:
# --- Détermine l'état ---
if flee_enabled:
_state = "flee"
else:
_state = "idle"
var desired_direction: Vector3
if _state == "flee":
desired_direction = _get_flee_direction(delta)
else:
desired_direction = _get_wander_direction(delta)
_apply_movement(desired_direction, delta)
_update_animation()
func _get_flee_direction(delta: float) -> Vector3:
# Direction opposée au joueur (sur le plan horizontal)
var away := (global_position - player.global_position)
away.y = 0.0
away = away.normalized()
var target_pos := global_position + away * 5.0
var clamped_target = _clamp_to_zone(target_pos)
# Détection de blocage : si la cible calculée est quasiment la même que notre position
# ou si on est bloqué contre un bord (la cible clampée diffère fortement de la cible brute)
if target_pos.distance_to(clamped_target) > 0.5:
_stuck_timer += delta
if _stuck_timer > 0.3: # Si bloqué pendant plus de 0.3 secondes
# On choisit aléatoirement ou on alterne gauche/droite pour longer le bord
if randf() < 0.02:
_sidestep_direction *= -1.0
# On décale la fuite perpendiculairement (à gauche ou à droite de la fuite)
var perpendicular = Vector3(-away.z, 0.0, away.x) * _sidestep_target_sign()
away = (away + perpendicular).normalized()
clamped_target = _clamp_to_zone(global_position + away * 5.0)
else:
_stuck_timer = 0.0
return (clamped_target - global_position).normalized()
func _sidestep_target_sign() -> float:
return _sidestep_direction
func _get_wander_direction(delta: float) -> Vector3:
if not wander_enabled:
return Vector3.ZERO
_wander_timer -= delta
if _wander_timer <= 0.0 or global_position.distance_to(_wander_target) < 0.5:
_wander_timer = wander_interval
_wander_target = _pick_random_point_in_zone()
var dir := (_wander_target - global_position)
dir.y = 0.0
if dir.length() < 0.1:
return Vector3.ZERO
return dir.normalized()
func _pick_random_point_in_zone() -> Vector3:
var angle := randf() * TAU
var radius := randf() * wander_radius
var offset := Vector3(cos(angle), 0.0, sin(angle)) * radius
var point := global_position + offset
return _clamp_to_zone(point)
func _clamp_to_zone(point: Vector3) -> Vector3:
var half_width := (zone_size.x * 0.5) - zone_margin
var half_depth := (zone_size.y * 0.5) - zone_margin
var rot_rad := deg_to_rad(zone_rotation_degrees)
var local_point := (point - zone_center).rotated(Vector3.UP, -rot_rad)
local_point.x = clamp(local_point.x, -half_width, half_width)
local_point.z = clamp(local_point.z, -half_depth, half_depth)
return zone_center + local_point.rotated(Vector3.UP, rot_rad)
func _apply_movement(direction: Vector3, delta: float) -> void:
var speed := move_speed
if _state == "flee":
speed *= 1.6
var target_velocity := direction * speed
target_velocity.y = velocity.y
velocity.x = move_toward(velocity.x, target_velocity.x, acceleration * delta)
velocity.z = move_toward(velocity.z, target_velocity.z, acceleration * delta)
if not is_on_floor():
velocity.y -= 9.8 * delta
if direction.length() > 0.1:
var target_angle := atan2(direction.x, direction.z)
rotation.y = lerp_angle(rotation.y, target_angle, rotation_speed * delta)
move_and_slide()
func _update_animation() -> void:
if anim_player.current_animation != "dog_rig_Canter":
anim_player.play("dog_rig_Canter")
func _on_area_3d_body_entered(body: Node3D) -> void:
if body.is_in_group("player"):
#if body.can_run:
body.fox_grabbed += 1
queue_free()
+1
View File
@@ -0,0 +1 @@
uid://csjajikq0yq7g
+67
View File
@@ -0,0 +1,67 @@
@tool
extends MeshInstance3D
## Dessine un rectangle (contour) représentant une zone de confinement.
## À attacher sur un MeshInstance3D vide, placé n'importe où dans la scène.
## Utilise les mêmes valeurs (zone_center / zone_size) que FleeingAnimal.gd.
@export var zone_center: Vector3 = Vector3.ZERO:
set(value):
zone_center = value
_update_rectangle()
@export var zone_size: Vector2 = Vector2(30.0, 30.0): # largeur (x) et profondeur (z)
set(value):
zone_size = value
_update_rectangle()
@export var zone_rotation_degrees: float = 0.0: # rotation du rectangle autour de l'axe Y
set(value):
zone_rotation_degrees = value
_update_rectangle()
@export var line_color: Color = Color(1.0, 0.2, 0.2):
set(value):
line_color = value
_update_material()
@export var height_offset: float = 0.05 # légère élévation pour éviter le z-fighting avec le sol
func _ready() -> void:
_update_rectangle()
_update_material()
func _update_rectangle() -> void:
var immediate := ImmediateMesh.new()
immediate.surface_begin(Mesh.PRIMITIVE_LINE_STRIP)
var half_width := zone_size.x * 0.5
var half_depth := zone_size.y * 0.5
var rot_rad := deg_to_rad(zone_rotation_degrees)
var local_corners := [
Vector3(-half_width, 0.0, -half_depth),
Vector3(half_width, 0.0, -half_depth),
Vector3(half_width, 0.0, half_depth),
Vector3(-half_width, 0.0, half_depth),
Vector3(-half_width, 0.0, -half_depth),
]
for corner in local_corners:
var rotated_corner: Vector3 = corner.rotated(Vector3.UP, rot_rad)
var final_point := zone_center + rotated_corner
final_point.y += height_offset
immediate.surface_add_vertex(final_point)
immediate.surface_end()
mesh = immediate
func _update_material() -> void:
var mat := StandardMaterial3D.new()
mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
mat.albedo_color = line_color
mat.vertex_color_use_as_albedo = false
material_override = mat
+1
View File
@@ -0,0 +1 @@
uid://p0sr27jji18b
+9
View File
@@ -0,0 +1,9 @@
extends Node
@onready var audio_snort: AudioStreamPlayer3D = $AudioStreamPlayer3D
@onready var snort_timer: Timer = $SnortTimer
func _on_snort_timer_timeout() -> void:
snort_timer.wait_time = randf_range(25, 35)
audio_snort.pitch_scale = randf_range( .9, 1.1 )
audio_snort.play()
+1
View File
@@ -0,0 +1 @@
uid://mnf6fljk6624
+65
View File
@@ -0,0 +1,65 @@
extends Camera3D
## Fait légèrement trembler la caméra pour simuler les secousses d'une voiture.
## Attache ce script directement sur chaque Camera3D du groupe "cinematic_cams"
@export_group("Intensité")
@export var position_amplitude: float = 0.01 # amplitude du déplacement (en mètres)
@export var rotation_amplitude: float = 0.2 # amplitude de la rotation (en degrés)
@export var frequency: float = 0.5 # vitesse du tremblement (plus haut = plus nerveux)
var _noise: FastNoiseLite
var _time: float = 0.0
var _last_offset_pos: Vector3 = Vector3.ZERO
var _last_offset_rot: Vector3 = Vector3.ZERO
var _shaking: bool = false
func _ready() -> void:
_noise = FastNoiseLite.new()
_noise.seed = randi()
_noise.frequency = 1.0
start_shake()
func start_shake() -> void:
_shaking = true
func stop_shake() -> void:
_shaking = false
# retire proprement le dernier offset appliqué pour ne pas laisser la caméra décalée
position -= _last_offset_pos
rotation -= _last_offset_rot
_last_offset_pos = Vector3.ZERO
_last_offset_rot = Vector3.ZERO
func _process(delta: float) -> void:
if not _shaking:
return
_time += delta * frequency
# retire l'offset de la frame précédente avant d'en calculer un nouveau
position -= _last_offset_pos
rotation -= _last_offset_rot
var offset_pos := Vector3(
_noise.get_noise_2d(_time, 0.0),
_noise.get_noise_2d(0.0, _time),
_noise.get_noise_2d(_time, _time)
) * position_amplitude
var offset_rot := Vector3(
_noise.get_noise_2d(_time, 100.0),
_noise.get_noise_2d(100.0, _time),
_noise.get_noise_2d(_time, -_time)
) * deg_to_rad(rotation_amplitude)
position += offset_pos
rotation += offset_rot
_last_offset_pos = offset_pos
_last_offset_rot = offset_rot
+1
View File
@@ -0,0 +1 @@
uid://dpg4fpvcr5rnl
+6 -2
View File
@@ -3,18 +3,22 @@ extends Node3D
@onready var cinematic_camera: Node3D = $cinematic_camera
@onready var car_anim_player: AnimationPlayer = $cinematic_camera/car/AnimationPlayer
@onready var player_anim_player: AnimationPlayer = $cinematic_camera/player_driving/AnimationPlayer
@onready var audio_stream_player: AudioStreamPlayer3D = $cinematic_camera/AudioStreamPlayer3D
func _ready() -> void:
Dialogic.start("timeline")
Dialogic.timeline_ended.connect( change_scene )
func change_scene():
audio_stream_player.stream = load("res://assets/audio/sound-effects/car/door-open.mp3")
audio_stream_player.play()
Transition.change_scene("res://scenes/main.scn")
func _process(delta: float) -> void:
car_anim_player.play("driving")
player_anim_player.play("driving")
if cinematic_camera.global_position.x < 490:
cinematic_camera.global_position.x += 16 * delta
cinematic_camera.global_position.x += 13 * delta
else:
cinematic_camera.global_position.x += 10 * delta
cinematic_camera.global_position.x += 9 * delta
+25 -9
View File
@@ -1,11 +1,14 @@
extends CharacterBody3D
@export var have_dialog : bool = false
@export var dialog : String = ""
@export var alrdy_talking : bool = false
@export var can_wander : bool = false
@onready var sprite_label: Sprite3D = $Sprite3D
@onready var label: Label = $Sprite3D/SubViewport/Label
@onready var anim_player: AnimationPlayer = $character/AnimationPlayer
@onready var mesh: MeshInstance3D = $character/Root/Skeleton3D/characterMedium
# navigation
@export var dest_array:Array[Marker3D]
@@ -19,11 +22,21 @@ var cur_state : NPCSTATE
var cur_destination: Marker3D
var speed = 2
var first_time : bool = false
func _ready() -> void:
mesh.set_instance_shader_parameter("skin_index", randi_range(1, 16))
sprite_label.visible = false
if alrdy_talking:
await get_tree().create_timer( randf_range(1.0, 2.5) ).timeout
anim_player.play("RootAction")
if !first_time:
first_time = true
else:
await get_tree().create_timer( randf_range(1.0, 2.5) ).timeout
anim_player.play("talking")
if have_dialog:
anim_player.play("Idling")
if can_wander:
_set_state( NPCSTATE.IDLE )
@@ -35,10 +48,14 @@ func _set_state(new_state:NPCSTATE):
cur_state = new_state
match cur_state:
NPCSTATE.IDLE:
idle_timer.start( randf_range(1, 2) )
anim_player.play("RootAction", -1, 10)
if !first_time:
first_time = true
idle_timer.start( 0 )
else:
idle_timer.start( randf_range(10, 20) )
anim_player.play("Idling", -1, 1)
NPCSTATE.WALKING:
anim_player.play("RootAction_001", -1, 2.5)
anim_player.play("walking", -1, randf_range(2, 2.5) )
func _physics_process(delta: float) -> void:
@@ -66,12 +83,11 @@ func decide_next_state():
func _on_area_3d_body_entered(body: Node3D) -> void:
if have_dialog and body.is_in_group("player"):
sprite_label.visible = true
label.text = dialog
body.set_dialog_mode( global_position )
func _on_area_3d_body_exited(body: Node3D) -> void:
if have_dialog and body.is_in_group("player"):
await get_tree().create_timer( 3 ).timeout
body.set_dialog_mode( )
sprite_label.visible = false
body.set_dialog_mode()
func _on_navigation_agent_3d_navigation_finished() -> void:
+8 -1
View File
@@ -1,8 +1,15 @@
extends MultiMeshInstance3D
@onready var anim_player: AnimationPlayer = $"../AnimationPlayer"
func _ready() -> void:
anim_player.play("will_turning", -1, .5)
var characters_seating:Array = get_tree().get_nodes_in_group("char_seat")
for char in characters_seating:
char.get_node("AnimationPlayer").play("mixamo_com")
char.get_node("AnimationPlayer").play("talk_seating")
var mesh = char.get_node("Root").get_node("Skeleton3D").get_node("characterMedium")
mesh.set_instance_shader_parameter("skin_index", randi_range(1, 16))
await get_tree().create_timer( randf_range(0.1, 1.5) ).timeout
+30 -8
View File
@@ -3,22 +3,27 @@ extends CharacterBody3D
@onready var sprite_label: Sprite3D = $Sprite3D
@onready var label: Label = $Sprite3D/SubViewport/Label
@onready var area_3d: Area3D = $Area3D
@onready var collision_shape_3d: CollisionShape3D = $Area3D/CollisionShape3D
@onready var anim_player: AnimationPlayer = $character/AnimationPlayer
@onready var camera_zoom: Camera3D = $CameraZoom
@onready var player: CharacterBody3D = $"../../Player"
@onready var frog: CharacterBody3D = $"../../frog"
@onready var area_3d_zoom: Area3D = $Area3DZoom
@onready var indicateur_tarte: CSGTorus3D = $"../indicateur_tarte"
@onready var client_spawner: Node3D = $"../client_spawner"
@onready var fox: CharacterBody3D = $"../../Animals/Foxes/fox"
@onready var fox_2: CharacterBody3D = $"../../Animals/Foxes/fox2"
var zoom_active : bool = false
func zoom_dialog():
label.text = Sauvegarde.get_text("coco" + str( 0 ) )
camera_zoom.make_current()
zoom_active = true
anim_player.play("RootAction")
anim_player.play("talking")
func _process(delta: float) -> void:
if zoom_active:
@@ -29,22 +34,31 @@ func _process(delta: float) -> void:
player.camera.make_current()
player.can_play = true
anim_player.stop()
anim_player.play("Idling")
func dialog():
rotation.y = deg_to_rad( 180 )
anim_player.play("RootAction")
if !player.is_client_game_launched:
rotation.y = deg_to_rad( 180 )
anim_player.play("talking")
for i in range(1,3):
var p
if player.is_client_game_launched:
p = range(4, 8)
else:
p = range(1, 4)
for i in p:
label.text = Sauvegarde.get_text("coco" + str( i ) )
await get_tree().create_timer( 1 ).timeout
await get_tree().create_timer( 6 ).timeout
anim_player.play("Idling")
rotation.y = deg_to_rad( -90 )
if !player.is_client_game_launched:
rotation.y = deg_to_rad( -90 )
anim_player.stop()
sprite_label.visible = false
player.set_dialog_mode()
player.is_client_game_launched = true
indicateur_tarte.visible = true
client_spawner.start_timer()
@@ -57,7 +71,7 @@ func _on_area_3d_body_entered(body: Node3D) -> void:
sprite_label.visible = true
player.set_dialog_mode( global_position, 0)
dialog()
area_3d.queue_free()
collision_shape_3d.disabled = true
func _on_area_3d_zoom_body_entered(body: Node3D) -> void:
@@ -65,3 +79,11 @@ func _on_area_3d_zoom_body_entered(body: Node3D) -> void:
player.can_play = false
area_3d_zoom.queue_free()
zoom_dialog()
func reactivate_area3D():
collision_shape_3d.disabled = false
anim_player.stop()
fox.flee_enabled = true
fox_2.flee_enabled = true
player.can_run = true
+32
View File
@@ -0,0 +1,32 @@
#@tool
#extends EditorScript
#
#func _run():
#var paths = [
#"res://assets/img/textures/faces/face_bis1.png",
#"res://assets/img/textures/faces/face_bis2.png",
#"res://assets/img/textures/faces/face_bis3.png",
#"res://assets/img/textures/faces/face_bis4.png",
#"res://assets/img/textures/faces/face_bis5.png",
#"res://assets/img/textures/faces/face_bis6.png",
#"res://assets/img/textures/faces/face_bis7.png",
#"res://assets/img/textures/faces/face_bis8.png",
#"res://assets/img/textures/faces/face_bis9.png",
#"res://assets/img/textures/faces/face_bis10.png",
#"res://assets/img/textures/faces/face_bis11.png",
#"res://assets/img/textures/faces/face_bis12.png",
#"res://assets/img/textures/faces/face_bis13.png",
#"res://assets/img/textures/faces/face_bis14.png",
#"res://assets/img/textures/faces/face_bis15.png",
#"res://assets/img/textures/faces/face_bis16.png",
#]
#var images: Array[Image] = []
#for p in paths:
#print("p: ", p)
#images.append(load(p).get_image())
#
#var tex_array = Texture2DArray.new()
#tex_array.create_from_images(images)
#
#ResourceSaver.save(tex_array, "res://assets/img/textures/faces.tres")
#print("Saved skin_array.tres with ", images.size(), " layers")
+1
View File
@@ -0,0 +1 @@
uid://cy6xfc3foi1oy
+4 -3
View File
@@ -11,12 +11,13 @@ var player
func _ready() -> void:
doggo_anim_player.play("sleep")
anim_player.play("Idling")
func dialog():
anim_player.play("RootAction")
anim_player.play("talking")
for i in range(1, 7):
label.text = Sauvegarde.get_text("neige" + str( i ) )
await get_tree().create_timer( 7 ).timeout
await get_tree().create_timer( 5 ).timeout
anim_player.stop()
sprite_label.visible = false
@@ -27,7 +28,7 @@ func _on_area_3d_body_entered(body: Node3D) -> void:
if body.is_in_group("player"):
player = body
sprite_label.visible = true
player.set_dialog_mode( global_position, 0)
player.set_dialog_mode( global_position)
dialog()
area_3d.queue_free()
+44
View File
@@ -0,0 +1,44 @@
@tool
extends EditorScript
# Path to your new NPC scene
const NEW_NPC_SCENE := preload("res://scenes/character_seat_talking.tscn")
func _run():
var root := get_scene()
if root == null:
push_error("Open the scene in the editor before running this script.")
return
var seating := root.find_child("characters-seating", true, false)
if seating == null:
push_error("Could not find 'characters-seating' node.")
return
var replaced := 0
for grp in seating.get_children():
# Snapshot the children first, since we'll be modifying the group as we go
var old_npcs := grp.get_children()
for old_npc in old_npcs:
if not (old_npc is Node3D):
push_warning(old_npc.name + " in " + grp.name + " is not a Node3D, skipping.")
continue
var old_transform: Transform3D = old_npc.transform
var old_name := old_npc.name
var new_npc: Node3D = NEW_NPC_SCENE.instantiate()
grp.remove_child(old_npc)
old_npc.queue_free()
grp.add_child(new_npc)
new_npc.owner = root
new_npc.transform = old_transform
new_npc.name = old_name
replaced += 1
print("Replaced ", replaced, " NPC(s).")
+1
View File
@@ -0,0 +1 @@
uid://btaqj1ucp5j8n
+88 -29
View File
@@ -5,26 +5,21 @@ enum State { ENTERING, WAITING, LEAVING }
var current_state: State = State.ENTERING
# --- PARAMÈTRES ---
@export var speed: float = 12
@export var speed: float = 4
@export var entry_path: Array[Marker3D]
@export var exit_path: Array[Marker3D]
var current_path_index: int = 0
var possible_pies = [Sauvegarde.get_text("pie1"), Sauvegarde.get_text("pie2"), Sauvegarde.get_text("pie3")]
var possible_toppings = [Sauvegarde.get_text("topping1"), Sauvegarde.get_text("topping2"), "Aucun"]
var pie_icons = {
Sauvegarde.get_text("pie1"): "res://assets/img/ui/client/orange.png",
Sauvegarde.get_text("pie2"): "res://assets/img/ui/client/yellow.png",
Sauvegarde.get_text("pie3"): "res://assets/img/ui/client/purple.png",
}
var topping_icons = {
Sauvegarde.get_text("topping1"): "res://assets/img/ui/client/meringue.png",
Sauvegarde.get_text("topping2"): "res://assets/img/ui/client/croisillon.png",
}
var possible_pies = []
var possible_toppings = []
var possible_language = [ Sauvegarde.language, "jap", "all", "jap", "all" ]
var pie_icons = {}
var topping_icons = {}
var desired_pie: String = ""
var desired_topping: String = ""
var choosen_lang : String = Sauvegarde.language
var ready_to_take_pie : bool = false
@@ -32,23 +27,64 @@ var ready_to_take_pie : bool = false
@onready var sprite: Sprite3D = $Sprite3D
@onready var label: RichTextLabel = $Sprite3D/SubViewport/RichTextLabel
@onready var mesh: MeshInstance3D = $character/Root/Skeleton3D/characterMedium
@onready var anim_player: AnimationPlayer = $character/AnimationPlayer
@onready var sprite_e: Sprite3D = $Sprite3DE
var player # given by client_spwaner
var is_close_to_waiting = false
func _ready() -> void:
mesh.set_instance_shader_parameter("skin_index", randi_range(1, 16))
sprite.visible = false
if player.cpt_client > 1:
choosen_lang = possible_language.pick_random()
possible_pies = [Sauvegarde.get_text("pie1", choosen_lang), Sauvegarde.get_text("pie2", choosen_lang), Sauvegarde.get_text("pie3", choosen_lang)]
possible_toppings = [Sauvegarde.get_text("topping1", choosen_lang), Sauvegarde.get_text("topping2", choosen_lang), "Aucun"]
pie_icons = {
Sauvegarde.get_text("pie1", choosen_lang): "res://assets/img/ui/client/orange.png",
Sauvegarde.get_text("pie2", choosen_lang): "res://assets/img/ui/client/yellow.png",
Sauvegarde.get_text("pie3", choosen_lang): "res://assets/img/ui/client/purple.png",
}
topping_icons = {
Sauvegarde.get_text("topping1", choosen_lang): "res://assets/img/ui/client/meringue.png",
Sauvegarde.get_text("topping2", choosen_lang): "res://assets/img/ui/client/croisillon.png",
}
desired_pie = possible_pies.pick_random()
desired_topping = possible_toppings.pick_random()
var p_icon
var order_text
func _physics_process(delta: float) -> void:
if !player.one_time_cpt_feather:
queue_free()
if not is_on_floor():
velocity.y -= 9.8 * delta
match current_state:
State.ENTERING:
if is_close_to_waiting:
anim_player.play("talking")
else:
anim_player.play("walking")
move_along_path(entry_path, delta)
State.WAITING:
anim_player.play("talking")
velocity.x = move_toward(velocity.x, 0, speed)
velocity.z = move_toward(velocity.z, 0, speed)
State.LEAVING:
anim_player.play("walking")
move_along_path(exit_path, delta)
move_and_slide()
@@ -61,7 +97,17 @@ func move_along_path(path_array: Array[Marker3D], delta: float) -> void:
elif current_state == State.LEAVING:
queue_free()
return
# special pour l'attente
if current_path_index >= path_array.size()-1:
var targ = path_array[current_path_index].global_position
if global_position.distance_to(Vector3(targ.x, global_position.y, targ.z)) < 4:
is_close_to_waiting = true
else:
is_close_to_waiting = false
look_at( targ )
var target = path_array[current_path_index].global_position
var direction = global_position.direction_to(target)
direction.y = 0
@@ -81,14 +127,13 @@ func start_waiting() -> void:
current_state = State.WAITING
velocity = Vector3.ZERO
var p_icon = pie_icons[ desired_pie ]
var order_text = Sauvegarde.get_text("desire") + desired_pie
p_icon = pie_icons[ desired_pie ]
order_text = Sauvegarde.get_text("desire", choosen_lang) + desired_pie
order_text += " [img=60]" + p_icon + "[/img]"
if desired_topping != "Aucun":
var t_icon = topping_icons[ desired_topping ]
order_text += "\n+ " + desired_topping + " [img=80]" + t_icon + "[/img]"
set_dialogue(order_text)
sprite.visible = true
show_order()
# pour tests
#await get_tree().create_timer( 3 ).timeout
@@ -99,20 +144,25 @@ func give_item(pie_given: String, topping_given: String) -> void:
if current_state != State.WAITING:
return
#print("pie_given: ", pie_given, " | topping_given:", topping_given)
#print("desired_pie: ", desired_pie, " | desired_topping:", desired_topping)
sprite_e.visible = false
# On vérifie les deux conditions
if pie_given == desired_pie and topping_given == desired_topping:
set_dialogue( Sauvegarde.get_text("goodpie") )
set_dialogue( Sauvegarde.get_text("goodpie", choosen_lang) )
leave_store()
elif pie_given == desired_pie and topping_given != desired_topping:
set_dialogue( Sauvegarde.get_text("mixpie") )
set_dialogue( Sauvegarde.get_text("mixpie", choosen_lang) )
await get_tree().create_timer(4).timeout
show_order()
else:
set_dialogue( Sauvegarde.get_text("badpie") )
leave_store()
set_dialogue( Sauvegarde.get_text("badpie", choosen_lang) )
await get_tree().create_timer(4).timeout
show_order()
func leave_store() -> void:
player._end_action()
ready_to_take_pie = false
await get_tree().create_timer(2.0).timeout
sprite.visible = false
@@ -121,7 +171,16 @@ func leave_store() -> void:
func set_dialogue(text: String) -> void:
label.text = text
func show_order():
set_dialogue(order_text)
sprite.visible = true
func _on_area_3de_body_entered(body: Node3D) -> void:
if body.is_in_group("player"):
if current_state == State.WAITING:
sprite_e.visible = true
func _on_area_3de_body_exited(body: Node3D) -> void:
if body.is_in_group("player"):
sprite_e.visible = false
+15 -1
View File
@@ -8,18 +8,32 @@ extends Node3D
@onready var timer: Timer = $Timer
@onready var water_mill: MultiMeshInstance3D = $".."
@onready var player: CharacterBody3D = $"../../Player"
@onready var frog: CharacterBody3D = $"../../frog"
var x_seconds: float = 15:
set(value):
x_seconds = value
timer.wait_time = value
func _ready() -> void:
sprite_3d.visible = false
func _on_timer_timeout() -> void:
func _on_timer_timeout() -> void:
var new_client = client.instantiate()
new_client.player = player
water_mill.add_child(new_client)
new_client.global_position = global_position
new_client.entry_path = entry_path
new_client.exit_path = exit_path
player._start_action()
if !player.one_time_cpt_feather:
timer.stop()
func start_timer():
timer.start()
+35
View File
@@ -0,0 +1,35 @@
extends Control
@onready var all: Control = $ALL
@onready var musique: AudioStreamPlayer2D = $Musique
var can_scroll : bool = false
var one_time_menu : bool = true
func _ready() -> void:
AudioServer.set_bus_volume_db(2, 0) # reset car fade out durant cinematique
musique.play()
await get_tree().create_timer( 3 ).timeout
can_scroll = true
Sauvegarde.can_see_credit = true
await get_tree().create_timer( 33 ).timeout
musique.stream = load("res://assets/audio/music/menu.wav")
musique.play()
func _process(delta: float) -> void:
if can_scroll:
if all.position.y > -2900:
all.position.y -= delta * 1000
elif one_time_menu:
one_time_menu = false
await get_tree().create_timer( 5 ).timeout
Transition.change_scene("res://ui/menu.tscn")
func _input(event: InputEvent) -> void:
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
Transition.change_scene("res://ui/menu.tscn")
+1
View File
@@ -0,0 +1 @@
uid://wxjumpbfy7sr
+17
View File
@@ -0,0 +1,17 @@
extends CharacterBody3D
@export var texture : CompressedTexture2D
@onready var anim_player: AnimationPlayer = $character/AnimationPlayer
@onready var mesh_instance: MeshInstance3D = $character/Root/Skeleton3D/characterMedium
func _ready() -> void:
var mat = mesh_instance.mesh.surface_get_material(0)
var new_mat: StandardMaterial3D = mat.duplicate()
new_mat.albedo_texture = texture
mesh_instance.set_surface_override_material(0, new_mat)
await get_tree().create_timer( randf_range(1.0, 2.5) ).timeout
anim_player.play("talking")
+1
View File
@@ -0,0 +1 @@
uid://cv3koo5rdgsgv
+37 -10
View File
@@ -2,23 +2,32 @@ extends CanvasLayer
@onready var game_area: ColorRect = $BackGround/GameArea
@onready var target_rect: ColorRect = $BackGround/GameArea/TargetRect
@onready var feather: ColorRect = $BackGround/GameArea/Feather
@onready var feather: TextureRect = $BackGround/GameArea/Feather
@onready var player: CharacterBody3D = $".."
@onready var frog: CharacterBody3D = $"../../frog"
@onready var audio_player: AudioStreamPlayer2D = $AudioStreamPlayer2D
var cpt_col : int = -1
var is_playing : bool = false
var is_flashing : bool = false
var default_target_color : Color = Color(1.0, 1.0, 1.0, 0.6)
var tween : Tween
var one_time : bool = true
var first_time : bool = true
func _ready():
hide()
target_rect.color = default_target_color
func _input(event):
if Input.is_action_just_pressed("ui_accept") and player.can_play:
if one_time:
one_time = false
player.tuto.show_text( "tuto2", true)
toggle_minigame()
# Contrôle de la plume avec la souris (uniquement sur Y)
@@ -31,17 +40,30 @@ func toggle_minigame():
is_playing = !is_playing
if is_playing:
show()
AudioServer.set_bus_effect_enabled( 0, 0, true )
AudioServer.set_bus_volume_db( 2, AudioServer.get_bus_volume_db(2)-20 )
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
player.camera_pov.make_current()
target_rect.position.y = game_area.size.y - target_rect.size.y
await get_tree().create_timer( 2 ).timeout
if first_time:
await get_tree().create_timer( 15 ).timeout
first_time = false
else:
await get_tree().create_timer( 2 ).timeout
if is_playing:
player.can_play = false
get_tree().paused = true
start_pattern()
else:
AudioServer.set_bus_effect_enabled( 0, 0, false )
AudioServer.set_bus_volume_db( 2, AudioServer.get_bus_volume_db(2)+20 )
get_tree().paused = false
player.can_play = true
player.camera.make_current()
hide()
@@ -54,13 +76,15 @@ func toggle_minigame():
return
cpt_col/= 2
if cpt_col < 2:
frog.size = 1
frog.size = .5
elif cpt_col == 2 or cpt_col == 3:
if frog.size > 1.5:
frog.size = 1.5
if frog.size > .7:
frog.size = .7
else:
if frog.size > 2:
frog.size = 2
player.cpt_feather += 1
func start_pattern():
@@ -72,13 +96,15 @@ func start_pattern():
else:
return
audio_player.play()
var bottom_y = game_area.size.y - target_rect.size.y
var top_y = 0.0
tween.tween_property(target_rect, "position:y", top_y, 5)
tween.tween_interval(4.0)
tween.tween_property(target_rect, "position:y", bottom_y, 5)
tween.tween_interval(4.0)
tween.tween_property(target_rect, "position:y", top_y, 5) # 5
tween.tween_interval(4.0) # 4
tween.tween_property(target_rect, "position:y", bottom_y, 5) # 5
tween.tween_interval(4.0) # 4
await tween.finished
if cpt_col == -1:
@@ -88,6 +114,7 @@ func start_pattern():
func _process(delta):
if not is_playing:
return
+38 -4
View File
@@ -1,13 +1,13 @@
extends CharacterBody3D
@export var player: Node3D
@export var follow_speed: float = 4.0
@export var follow_speed: float = 5.6
@export var right_offset: float = 2.5
@export var forward_offset: float = 1
@export var car_cinematic : bool = false
@onready var anim_player: AnimationPlayer = $frog/AnimationPlayer
var size : float = 0.5
var size : float = .7
@onready var arms: MeshInstance3D = $frog/Armature/Skeleton3D/arms
@onready var body: MeshInstance3D = $frog/Armature/Skeleton3D/body
@@ -17,10 +17,18 @@ var size : float = 0.5
@onready var legs: MeshInstance3D = $frog/Armature/Skeleton3D/legs
@onready var mesh = [ arms, body, eyes, feet, hands, legs ]
@onready var audio_player: AudioStreamPlayer3D = $AudioStreamPlayer3D
@onready var frog_launch_step = load("res://assets/audio/sound-effects/frog/frog_launch_step.mp3")
@onready var frog_quiet_step = load("res://assets/audio/sound-effects/frog/frog_quiet_step.mp3")
@onready var frog_loud_step = load("res://assets/audio/sound-effects/frog/frog_loud_step.wav")
@onready var audio_croak: AudioStreamPlayer3D = $AudioCroak
@onready var croak_timer: Timer = $CroakTimer
# Variables pour la gravité
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
var can_scale : bool = false
func _ready() -> void:
if !car_cinematic:
scale = Vector3( size, size, size )
@@ -42,10 +50,18 @@ func _process(delta: float) -> void:
func _physics_process(delta):
if not player or car_cinematic:
return
if can_scale:
if player.is_client_game_launched:
size += 0.00025
else:
size += 0.00012
# Appliquer la gravité
if not is_on_floor():
velocity.y -= gravity * delta
var target_position = player.global_position + (player.global_transform.basis.x * right_offset) + (-player.global_transform.basis.z * forward_offset)
global_position.y = target_position.y
@@ -73,12 +89,13 @@ func _physics_process(delta):
var real_speed = Vector2(get_real_velocity().x, get_real_velocity().z).length()
# Si frog n'est pas bloquée par un mur
if real_speed > 0.1:
size += 0.0
if anim_player.current_animation != "walk":
anim_player.play("walk", 0.2)
_play_jump_sound()
else:
if anim_player.current_animation != "idle":
anim_player.play("idle", 0.2)
_play_land_sound()
move_and_slide()
@@ -87,3 +104,20 @@ func scale_frog():
var final_scale = Vector3(size, size, size)
tween.tween_property(self, "scale", final_scale, 2)
func _play_jump_sound() -> void:
audio_player.stream = frog_launch_step
audio_player.play()
func _play_land_sound() -> void:
if size < 2:
audio_player.stream = frog_quiet_step
else:
audio_player.stream = frog_loud_step
audio_player.play()
func _on_timer_timeout() -> void:
croak_timer.wait_time = randf_range(30, 45)
audio_croak.pitch_scale = randf_range( .9, 1.1 )
audio_croak.play()
+90 -5
View File
@@ -1,5 +1,11 @@
extends Node
var player
var corinne
var music_player # pour balavoine
# pour corinne-help
func _ready() -> void:
#Dialogic.timeline_ended.connect(set_player_cam)
pass
@@ -9,9 +15,88 @@ func change_cinematic_cam(camera_name:String):
for cam in all_cinematic_cams:
if cam.name == camera_name:
cam.make_current()
# car cinematic
if cam.name == "deathseat":
var audio = cam.get_parent().get_node("AudioStreamPlayer3D")
audio.stream = load("res://assets/audio/sound-effects/car/inside-car.mp3")
audio.play()
elif cam.name == "road_view":
var audio = cam.get_parent().get_node("AudioStreamPlayer3D")
audio.stream = load("res://assets/audio/sound-effects/car/outside-car.wav")
audio.play()
elif cam.name == "frog_view":
var audio = cam.get_parent().get_node("AudioStreamPlayer3D")
audio.stream = load("res://assets/audio/sound-effects/car/inside-car.mp3")
audio.play()
elif cam.name == "top_view":
var audio = cam.get_parent().get_node("AudioStreamPlayer3D")
audio.stream = load("res://assets/audio/sound-effects/car/outside-car.wav")
audio.play()
# other cinematics
elif cam.name == "croissants":
corinne = get_tree().get_first_node_in_group("corinne")
var marker_player = cam.get_node("MarkerPlayer")
var marker_corinne = cam.get_node("MarkerCorinne")
player.global_position = marker_player.global_position
player.global_rotation = marker_player.global_rotation
func set_player_cam():
return
var player = get_tree().get_first_node_in_group("player")
if player:
player.set_default_cam()
corinne.global_position = marker_corinne.global_position
corinne.global_rotation = marker_corinne.global_rotation
player.anim_player.play("Idling")
corinne.anim_player.play("Idling")
music_player.global_position = cam.global_position
elif cam.name == "stairs":
var path_follow = cam.get_node("Path3D").get_node("PathFollow3D")
corinne.reparent( path_follow )
corinne.position = Vector3.ZERO
corinne.rotation = Vector3.ZERO
var tween := create_tween()
tween.tween_property(path_follow, "progress_ratio", 1.0, 35)
tween.finished.connect( corinne.reactivate_area3D )
corinne.anim_player.play( "walking" )
music_player.global_position = cam.global_position
elif cam.name == "large":
var marker_player = cam.get_node("MarkerPlayer")
#player = get_tree().get_first_node_in_group("player")
#corinne = get_tree().get_first_node_in_group("corinne")
#music_player = player.musique
player.global_position = marker_player.global_position
player.global_rotation = marker_player.global_rotation
music_player.global_position = cam.global_position
elif cam.name == "watermill":
music_player.global_position = cam.global_position
elif cam.name == "city":
var marker_player = cam.get_node("MarkerPlayer")
var marker_corinne = cam.get_node("MarkerCorinne")
player.global_position = marker_player.global_position
player.global_rotation = marker_player.global_rotation
corinne.global_position = marker_corinne.global_position
corinne.global_rotation = marker_corinne.global_rotation
player.anim_player.play("Idling")
corinne.anim_player.play("Idling")
music_player.global_position = cam.global_position
return
func set_player_cam(pov:bool=true):
if !player:
player = get_tree().get_first_node_in_group("player")
if pov:
player.set_pov_cam()
else:
player.set_default_cam()
music_player = player.musique
player.reset_musique_position()
+44 -24
View File
@@ -3,20 +3,27 @@ extends Node3D
@onready var camera: Camera3D = $Camera3D
# BOUTONS
@onready var start: Button = $HBoxContainer/Start
@onready var quit: Button = $HBoxContainer/Quit
@onready var credit: Button = $HBoxContainer/Credit
@onready var start: Button = $MenuUI/HBoxContainer/Start
@onready var quit: Button = $MenuUI/HBoxContainer/Quit
@onready var credit: Button = $MenuUI/HBoxContainer/Credit
@onready var fr: TextureButton = $HBoxContainer/fr
@onready var en: TextureButton = $HBoxContainer/en
@onready var screen: Button = $HBoxContainer2/Screen
@onready var fr: TextureButton = $MenuUI/HBoxContainer/fr
@onready var en: TextureButton = $MenuUI/HBoxContainer/en
@onready var screen: Button = $MenuUI/HBoxContainer2/Screen
@onready var credit_label: Label = $Sprite3D/SubViewport/credit_label
@onready var credit_label: Label = $MenuUI/Sprite3D/SubViewport/credit_label
var but_credit_exist : bool = true
@onready var car: Node3D = $partie3D/car
@onready var anim_player_car: AnimationPlayer = $partie3D/car/AnimationPlayer
@onready var anim_player_char: AnimationPlayer = $partie3D/car/player_driving/AnimationPlayer
@onready var musique: AudioStreamPlayer3D = $Musique
# pour option
@onready var menu_ui: Control = $MenuUI
@onready var option: CanvasLayer = $Option
@onready var optionexit: Button = $Option/optionexit
var cible_rot_y
var cible_rot_x
func _ready() -> void:
Sauvegarde.is_in_menu = true
@@ -26,10 +33,18 @@ func _ready() -> void:
en.texture_normal = preload("uid://bdcehsogmfiv2")
fr.texture_normal = preload("uid://dusujvur4igj4")
screen.text = Sauvegarde.get_text("window_screen")
if Sauvegarde.can_see_credit:
credit.visible = true
else:
credit.visible = false
cible_rot_y = deg_to_rad( 147.8 )
cible_rot_x = deg_to_rad( -6.1 )
anim_player_car.play("driving")
anim_player_char.play("driving")
func _process(delta: float) -> void:
car.position.z += 16 * delta
func _on_start_pressed() -> void:
get_tree().change_scene_to_file( "res://scenes/main.scn" )
@@ -38,15 +53,8 @@ func _on_start_pressed() -> void:
func _on_quit_pressed() -> void:
get_tree().quit()
func _physics_process(delta: float) -> void:
camera.rotation.y = lerp_angle(camera.rotation.y, cible_rot_y, 3 * delta)
camera.rotation.x = lerp_angle(camera.rotation.x, cible_rot_x, 3 * delta)
func _on_credit_pressed() -> void:
cible_rot_y = deg_to_rad(100)
cible_rot_x = deg_to_rad(16)
credit.queue_free()
but_credit_exist = false
Transition.change_scene("res://ui/credit.tscn")
func _on_fr_pressed() -> void:
@@ -73,11 +81,23 @@ func load_lang(l):
Sauvegarde.language = l
start.text = Sauvegarde.get_text("start")
quit.text = Sauvegarde.get_text("quit")
if but_credit_exist :
credit.text = Sauvegarde.get_text("credit")
credit.text = Sauvegarde.get_text("credit")
optionexit.text = Sauvegarde.get_text("resume")
if get_window().mode == Window.MODE_FULLSCREEN:
screen.text = Sauvegarde.get_text("window_screen")
else:
screen.text = Sauvegarde.get_text("full_screen")
credit_label.text = Sauvegarde.get_text("credit_detail")
func _on_timer_timeout() -> void:
musique.play()
func _on_option_pressed() -> void:
option.visible = true
menu_ui.visible = false
func _on_optionexit_pressed() -> void:
option.visible = false
menu_ui.visible = true
+27
View File
@@ -0,0 +1,27 @@
extends CanvasLayer
@onready var h_slider_master: HSlider = $VBoxContainer/HSliderMaster
@onready var h_slider_music: HSlider = $VBoxContainer/HSliderMusic
@onready var h_slider_effects: HSlider = $VBoxContainer/HSliderEffects
@onready var label: Label = $VBoxContainer/Label
@onready var label_2: Label = $VBoxContainer/Label2
@onready var label_3: Label = $VBoxContainer/Label3
func _ready() -> void:
h_slider_master.value = db_to_linear( AudioServer.get_bus_volume_db(0) )
h_slider_music.value = db_to_linear( AudioServer.get_bus_volume_db(2) )
h_slider_effects.value = db_to_linear( AudioServer.get_bus_volume_db(1) )
label.text = Sauvegarde.get_text("option_master")
label_2.text = Sauvegarde.get_text("option_music")
label_3.text = Sauvegarde.get_text("option_effects")
func _on_h_slider_master_value_changed(value: float) -> void:
AudioServer.set_bus_volume_db( 0, linear_to_db( value ) )
func _on_h_slider_music_value_changed(value: float) -> void:
AudioServer.set_bus_volume_db( 2, linear_to_db( value ) )
func _on_h_slider_effects_value_changed(value: float) -> void:
AudioServer.set_bus_volume_db( 1, linear_to_db( value ) )
+1
View File
@@ -0,0 +1 @@
uid://b5tyf08t05tdo
+20 -10
View File
@@ -1,39 +1,49 @@
extends Control
extends CanvasLayer
# Buttons
@onready var resume_but: Button = $ColorRect/PanelContainer/VBoxContainer/Resume
@onready var restart: Button = $ColorRect/PanelContainer/VBoxContainer/Restart
@onready var menu: Button = $ColorRect/PanelContainer/VBoxContainer/Menu
@onready var continuer: Button = $Option/Continuer
@onready var color_rect: ColorRect = $ColorRect
@onready var option: CanvasLayer = $Option
func _ready() -> void:
hide()
$AnimationPlayer.play("RESET")
resume_but.text = Sauvegarde.get_text("resume")
restart.text = Sauvegarde.get_text("restart")
menu.text = Sauvegarde.get_text("menu")
continuer.text = Sauvegarde.get_text("resume")
func resume():
get_tree().paused = false
hide()
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
$AnimationPlayer.play_backwards("blur")
AudioServer.set_bus_effect_enabled( 1, 0, false )
func pause():
get_tree().paused = true
show()
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
$AnimationPlayer.play("blur")
AudioServer.set_bus_effect_enabled( 1, 0, true )
func _on_resume_pressed() -> void:
resume()
func _on_restart_pressed() -> void:
resume()
get_tree().reload_current_scene()
func _on_menu_pressed() -> void:
get_tree().paused = false
get_tree().change_scene_to_file( "res://scenes/menu.tscn" )
Transition.change_scene("res://ui/menu.tscn")
func _on_option_pressed() -> void:
color_rect.visible = false
option.visible = true
func _on_button_pressed() -> void:
color_rect.visible = true
option.visible = false
+128 -24
View File
@@ -1,10 +1,11 @@
extends CharacterBody3D
var SPEED = 7
var speed = 6
@onready var arm: Node3D = $arm
@onready var model: Node3D = $model
@onready var mesh_instance: MeshInstance3D = $character/Root/Skeleton3D/characterMedium
# GESTION CAMERA --------------------------
@onready var spring_arm: SpringArm3D = $arm/SpringArm3D
@@ -17,15 +18,16 @@ var third_person : bool = true
@onready var audio_footstep: AudioStreamPlayer3D = $Audio_Footstep
var footstep_sounds: Array[AudioStream] = [
preload("res://assets/audio/footsteps/dirt_step_1.wav"),
preload("res://assets/audio/footsteps/dirt_step_2.wav"),
preload("res://assets/audio/footsteps/dirt_step_3.wav"),
preload("res://assets/audio/footsteps/dirt_step_4.wav")
preload("res://assets/audio/sound-effects/footsteps/dirt_step_1.wav"),
preload("res://assets/audio/sound-effects/footsteps/dirt_step_2.wav"),
preload("res://assets/audio/sound-effects/footsteps/dirt_step_3.wav"),
preload("res://assets/audio/sound-effects/footsteps/dirt_step_4.wav")
]
var footstep_timer: float = 0.0
const FOOTSTEP_DELAY: float = 0.24
var FOOTSTEP_DELAY: float = 0.35
@onready var pause: Control = $pause
@onready var pause: CanvasLayer = $pause
@onready var tuto: CanvasLayer = $tuto
# animations
@onready var anim_player: AnimationPlayer = $character/AnimationPlayer
@@ -35,6 +37,36 @@ var item : int = 0 # 0 rien, 1 abricot, 2 citron, 3 mirtylle
var topping : int = 0 # 0 rien, 1 meringue, 2 croisillon
@onready var area_tarte: Area3D = $Area3DTarte
@onready var tarte_holded: StaticBody3D = $tarte
# tps pour servir un client
@onready var client_spawner: Node3D = $"../WaterMILL/client_spawner"
var action_start_time: int = 0
func _start_action() -> void:
action_start_time = Time.get_ticks_msec()
func _end_action() -> void:
var duration_ms := Time.get_ticks_msec() - action_start_time
var duration_sec := duration_ms / 1000.0
if duration_sec < 6:
duration_sec = 6
elif duration_sec > 35:
duration_sec = 34
client_spawner.x_seconds = duration_sec
var cpt_client : int = 0
var is_client_game_launched : bool = false
var one_time_client_game : bool = true
var one_time_cpt_feather : bool = true
var cpt_feather : int = 0
var one_time_fox_grabbed : bool = true
var fox_grabbed : int = 0
var can_run : bool = false
@onready var frog: CharacterBody3D = $"../frog"
@onready var area_3d_tuto_3: Area3D = $"../WaterMILL/Area3DTuto3"
@onready var musique: AudioStreamPlayer3D = $Musique
@onready var zip_effect: AudioStreamPlayer3D = $ZipEffect
var can_play : bool = true
@@ -48,6 +80,9 @@ func _ready():
camera_pov.make_current()
model.visible = false
await get_tree().create_timer( .5 ).timeout
tuto.show_text( "tuto1" )
func _input(_event):
if Input.is_action_just_pressed("ui_cancel"):
if !get_tree().paused:
@@ -66,6 +101,7 @@ func _process(delta: float) -> void:
if obj.get_parent().ready_to_take_pie:
var l = get_conversion_pie()
obj.get_parent().give_item( l[0], l[1] )
cpt_client += 1
reset_pie()
return
@@ -77,19 +113,42 @@ func _process(delta: float) -> void:
func _physics_process(delta: float) -> void:
#print("global position; ", global_position)
if can_run:
speed = 8
FOOTSTEP_DELAY = 0.25
if is_client_game_launched:
if one_time_client_game:
var mat = mesh_instance.mesh.surface_get_material(0)
mat.albedo_texture = load("res://assets/img/textures/faces/player_employe.png")
mesh_instance.set_surface_override_material(0, mat)
zip_effect.play()
cpt_feather = 0
one_time_client_game = false
if cpt_feather == 2:
if one_time_cpt_feather:
AudioServer.set_bus_volume_db( 1, -10.0)
musique.stream = load("res://assets/audio/music/Daniel Balavoine - Tous les cris les S.O.S.mp3")
musique.play()
set_dialog_mode( Vector3.ZERO, true )
Dialogic.start("corinne_help")
Dialogic.timeline_ended.connect( corinne_help_cinematic_end )
one_time_cpt_feather = false
if fox_grabbed == 2:
if one_time_fox_grabbed:
set_dialog_mode( Vector3.ZERO, true )
Dialogic.start("fin")
Dialogic.timeline_ended.connect( fin_cinematic_end )
one_time_fox_grabbed = false
fade_out_music()
if not is_on_floor():
velocity += get_gravity() * delta
# Get the input direction and handle the movement/deceleration.
var input_dir := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
#var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
#if direction:
#velocity.x = direction.x * SPEED
#velocity.z = direction.z * SPEED
#else:
#velocity.x = move_toward(velocity.x, 0, SPEED)
#velocity.z = move_toward(velocity.z, 0, SPEED)
if input_dir.length() < 0.1:
input_dir = Vector2.ZERO
@@ -98,9 +157,12 @@ func _physics_process(delta: float) -> void:
# On ne déplace et on ne tourne le joueur que si une vraie direction est donnée
if can_play:
if direction.length() > 0.1:
anim_player.play("RootAction_001", -1, 3)
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
if can_run:
anim_player.play("walking", -1, 2)
else:
anim_player.play("walking", -1, 1.5)
velocity.x = direction.x * speed
velocity.z = direction.z * speed
# 2. CORRECTION DE LA ROTATION INVERSÉE
# Si le joueur tourne toujours à l'envers, enlève les signes "-" devant velocity.x et velocity.z
@@ -109,10 +171,10 @@ func _physics_process(delta: float) -> void:
# Le 10.0 est bien, il permet au modèle 3D de se tourner vite sans faire de coup sec.
rotation.y = lerp_angle(rotation.y, target_angle, 10.0 * delta)
else:
anim_player.stop()
anim_player.play("Idling")
# Le joueur s'arrête doucement
velocity.x = move_toward(velocity.x, 0, SPEED)
velocity.z = move_toward(velocity.z, 0, SPEED)
velocity.x = move_toward(velocity.x, 0, speed)
velocity.z = move_toward(velocity.z, 0, speed)
else:
anim_player.stop()
@@ -128,7 +190,34 @@ func _physics_process(delta: float) -> void:
if can_play:
move_and_slide()
func corinne_help_cinematic_end():
set_dialog_mode( Vector3.ZERO, true )
set_default_cam()
frog.size = .5
frog.can_scale = false
func fade_out_music() -> void:
var fade_tween = create_tween()
if fade_tween and fade_tween.is_valid():
fade_tween.kill()
var start_db := AudioServer.get_bus_volume_db(2)
fade_tween = create_tween()
fade_tween.tween_method(
func(db: float): AudioServer.set_bus_volume_db(2, db),
start_db,
-20,
30
)
func fin_cinematic_end():
Sauvegarde.can_see_credit = true
Transition.change_scene("res://ui/credit.tscn")
# PARTIE BOULANGERIE MOULIN
func set_item_topping( new_item : int, new_topping : int, reset:bool ):
if reset:
@@ -169,12 +258,27 @@ func play_random_footstep( pitch=[0.85, 1.15] ) -> void:
audio_footstep.pitch_scale = randf_range( pitch[0], pitch[1] )
audio_footstep.play()
func set_dialog_mode( npc_pos=Vector3.ZERO, force_pos=-1):
func set_dialog_mode( npc_pos=Vector3.ZERO, is_cinematic=false):
can_play = !can_play
spring_arm.set_dialog_mode( npc_pos, force_pos )
if !is_cinematic:
spring_arm.set_dialog_mode( npc_pos)
anim_player.play("talking")
func set_default_cam():
if third_person:
camera.set_current(true)
else:
camera_pov.set_current(true)
func set_pov_cam():
camera_pov.set_current(true)
func reset_musique_position():
await get_tree().create_timer( .2 ).timeout
musique.global_position = global_position
musique.volume_db += 10
func _on_area_3d_tuto_3_body_entered(body: Node3D) -> void:
if body.is_in_group("player"):
tuto.show_text( "tuto3", true)
area_3d_tuto_3.queue_free()
+4 -2
View File
@@ -3,6 +3,8 @@ var is_in_menu : bool = false
var language = "fr"
var can_see_credit : bool = false
var trad
func _ready() -> void:
var file = FileAccess.open("res://lang.json", FileAccess.READ)
@@ -11,5 +13,5 @@ func _ready() -> void:
var error = json.parse(json_text)
trad = json.data
func get_text(key):
return trad[language][key]
func get_text(key, lang=language):
return trad[lang][key]
+34 -29
View File
@@ -3,15 +3,15 @@ extends SpringArm3D
@onready var player: CharacterBody3D = $"../.."
# --- Paramètres de mouvement ---
@export var max_follow_speed: float = 3.0
@export var speed_acceleration: float = 2.0
@export var max_follow_speed: float = 3
@export var speed_acceleration: float = 2.5
@export var height_offset: float = 2.5
@export var wait_time: float = 0.5
# --- Paramètres de Dialogue ---
@export var dialog_zoom_length: float = 2.0
@export var dialog_side_offset: float = 1.0
@export var transition_speed: float = 4.0 # Gère la vitesse du zoom, du décalage ET de la rotation en dialog
@export var dialog_zoom_length: float = 3.5
@export var dialog_side_offset: float = 2.0
@export var transition_speed: float = 4.0
@onready var normal_spring_length: float = spring_length
@@ -21,25 +21,26 @@ var current_side_offset: float = 0.0
var target_side_offset: float = 0.0
var is_in_dialog: bool = false
# Variables pour le dialogue
var dialog_target_position: Vector3 = Vector3.ZERO
var target_dialog_rotation_y: float = 0.0
var dialog_weight: float = 0.0 # Permet une transition ultra-fluide (0.0 = Exploration, 1.0 = Dialogue)
func _ready() -> void:
top_level = true
func set_dialog_mode(npc_position: Vector3 = Vector3.ZERO, force_pos=-1) -> void:
func set_dialog_mode(npc_position: Vector3 = Vector3.ZERO) -> void:
is_in_dialog = !is_in_dialog
if is_in_dialog:
var direction_to_npc = (npc_position - player.global_position).normalized()
var right_dot = global_transform.basis.x.dot(direction_to_npc)
dialog_target_position = npc_position
if right_dot >= 0 :
target_side_offset = dialog_side_offset
else:
target_side_offset = -dialog_side_offset
if force_pos == 0 :
target_side_offset = dialog_side_offset
elif force_pos == 1 :
target_side_offset = -dialog_side_offset
var dir_to_npc = (npc_position - player.global_position)
dir_to_npc.y = 0
dir_to_npc = dir_to_npc.normalized()
target_dialog_rotation_y = atan2(-dir_to_npc.x, -dir_to_npc.z)
target_side_offset = dialog_side_offset
else:
target_side_offset = 0.0
@@ -47,22 +48,23 @@ func _physics_process(delta: float) -> void:
if not is_instance_valid(player):
return
var target_rotation_y = player.global_rotation.y
# Mise à jour progressive du poids de transition du dialogue (de 0 à 1)
var target_weight = 1.0 if is_in_dialog else 0.0
dialog_weight = lerp(dialog_weight, target_weight, transition_speed * delta)
# ==========================================
# 1. GESTION DE LA ROTATION (Avant la position !)
# 1. GESTION DE LA ROTATION
# ==========================================
if is_in_dialog:
if is_in_dialog or dialog_weight > 0.01:
delay_timer = 0.3
current_follow_speed = 0.5
# La caméra tourne doucement pour se mettre dans le dos du joueur.
# On utilise transition_speed pour que ça se finisse en même temps que le zoom.
global_rotation.y = lerp_angle(global_rotation.y, target_rotation_y, transition_speed * delta)
# On interpole la rotation vers l'angle de dialogue en utilisant le poids
global_rotation.y = lerp_angle(global_rotation.y, target_dialog_rotation_y, transition_speed * delta)
else:
if not is_in_dialog and dialog_weight <= 0.01:
var target_rotation_y = player.global_rotation.y
if player.can_play:
# Comportement normal d'exploration (Le vieux Zelda)
var angle_diff = abs(angle_difference(global_rotation.y, target_rotation_y))
if angle_diff > 0.02 and player.velocity.length() > 0.1:
@@ -77,15 +79,18 @@ func _physics_process(delta: float) -> void:
# ==========================================
# 2. GESTION DU ZOOM ET DU DECALAGE
# 2. GESTION DU ZOOM, DU DECALAGE ET DE LA POSITION
# ==========================================
var target_length = dialog_zoom_length if is_in_dialog else normal_spring_length
spring_length = lerp(spring_length, target_length, transition_speed * delta)
current_side_offset = lerp(current_side_offset, target_side_offset, transition_speed * delta)
# On récupère le vecteur "Droite" MAINTENANT, car la rotation vient juste d'être mise à jour au-dessus.
var right_direction = global_transform.basis.x
# On applique la position finale (Joueur + Hauteur + Décalage latéral)
global_position = player.global_position + Vector3(0, height_offset, 0) + (right_direction * current_side_offset)
# Transition fluide du point de pivot (de la position du joueur vers le point intermédiaire du dialogue)
var normal_base = player.global_position
var dialog_base = player.global_position.lerp(dialog_target_position, 0.3)
var current_base = normal_base.lerp(dialog_base, dialog_weight)
global_position = current_base + Vector3(0, height_offset, 0) + (right_direction * current_side_offset)
+12
View File
@@ -12,6 +12,8 @@ extends StaticBody3D
@onready var label: Label = $Sprite3D/SubViewport/Label
@onready var sprite_e: Sprite3D = $Sprite3DE
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
setup_color_and_name()
@@ -53,3 +55,13 @@ func _reset():
creme_myrtille.visible = false
meringue.visible = false
croisillon.visible = false
func _on_area_3e_body_entered(body: Node3D) -> void:
if body.is_in_group("player"):
sprite_e.visible = true
func _on_area_3e_body_exited(body: Node3D) -> void:
if body.is_in_group("player"):
sprite_e.visible = false
+38
View File
@@ -0,0 +1,38 @@
extends CanvasLayer
@onready var label: Label = $VBoxContainer/Label
@onready var player: CharacterBody3D = $".."
@onready var continue_button: Button = $continue
@onready var frog: CharacterBody3D = $"../../frog"
var paused
func _ready() -> void:
continue_button.text = Sauvegarde.get_text("tuto_continue")
func show_text( text, pause=false ):
layer = 2
paused = pause
if paused:
get_tree().paused = true
else:
player.can_play = false
show()
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
label.text = Sauvegarde.get_text( text )
func _on_button_pressed() -> void:
if paused:
get_tree().paused = false
if label.text[0] == "E":
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
hide()
layer = 0
await get_tree().create_timer( 20 ).timeout
frog.can_scale = true
else:
player.can_play = true
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
hide()
layer = 0
+1
View File
@@ -0,0 +1 @@
uid://cvbdr64ea5ieu