Skip to content

Commit 09f4821

Browse files
committed
fixing animation
1 parent 2e05a8c commit 09f4821

1 file changed

Lines changed: 141 additions & 12 deletions

File tree

scripts/fish.gd

Lines changed: 141 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ extends CharacterBody3D
1111
@export var is_shiny = false
1212
@export var shiny_particles: GPUParticles3D
1313

14+
# Debug flag - set to true to enable detailed orientation debugging
15+
@export var debug_orientation = false
16+
# Debug flag for shader animation - set to true to track animation rate issues
17+
@export var debug_shader_animation = false
18+
1419
@export var mesh_instance_path: NodePath
1520
var mesh_instance: MeshInstance3D
1621

@@ -19,6 +24,9 @@ var speed = 0
1924
var home: int
2025
var type: int
2126
var accumulated_shader_time: float = 0.0 # Custom time accumulator for shader
27+
var debug_birth_time: float = 0.0 # Track when this fish was created for debugging
28+
var debug_last_accum_time: float = 0.0 # Track previous accumulated time for rate calculation
29+
var debug_last_real_time: float = 0.0 # Track real time for rate calculation
2230

2331
# --- Shader Animation Speed Control (names describe rate of accumulation) ---
2432
@export var base_anim_rate: float = 0.5 # Base rate for accumulated_shader_time
@@ -49,6 +57,9 @@ func _ready():
4957
printerr(" ERROR: mesh_instance_path is not set for node: ", name)
5058

5159
accumulated_shader_time = randf() * 2.0 * PI
60+
debug_birth_time = Time.get_time_dict_from_system()["second"] + Time.get_time_dict_from_system()["minute"] * 60 + Time.get_time_dict_from_system()["hour"] * 3600
61+
debug_last_accum_time = accumulated_shader_time
62+
debug_last_real_time = debug_birth_time
5263

5364
# Disable shiny particles on WebGL for performance
5465
if is_webgl_build and shiny_particles:
@@ -77,9 +88,15 @@ func _physics_process(delta: float) -> void:
7788

7889
if get_slide_collision_count() > 0 && rotation_cooldown_left <= 0:
7990
rotation_cooldown_left = rotation_cooldown
91+
# Flip direction first
8092
rotate_y(deg_to_rad(180))
93+
# Normalize rotation to prevent accumulation errors
94+
normalize_y_rotation()
95+
# Then set new velocity with random angle
8196
var deg = randf_range(min_angle, max_angle)
8297
set_z_rotation_and_velocity(deg)
98+
# Extra validation after collision handling
99+
validate_orientation_velocity_match()
83100

84101
if global_position.y >= -0.5:
85102
record_surface_achievement()
@@ -97,12 +114,15 @@ func _physics_process(delta: float) -> void:
97114
set_z_rotation_and_velocity(randf_range(min_angle, max_angle))
98115

99116
move_and_slide()
100-
# Update shader animation with timer-based optimization
117+
118+
# Validate orientation matches velocity (only check occasionally for performance)
119+
if randf() < 0.005: # Check ~0.5% of frames to reduce spam
120+
validate_orientation_velocity_match()
121+
122+
# Update shader animation every frame (removed timer optimization)
123+
# The timer-based optimization was causing inconsistent animation rates
101124
if type == 0 or type == 1: # Only update animation for fish_a (0) and fish_b (1)
102-
shader_update_timer += delta
103-
if shader_update_timer >= shader_update_interval:
104-
update_shader_animation(shader_update_timer)
105-
shader_update_timer = 0.0
125+
update_shader_animation(delta)
106126

107127
func update_shader_animation(delta_time: float):
108128
if !mesh_instance: return
@@ -123,9 +143,40 @@ func update_shader_animation(delta_time: float):
123143
var effective_anim_rate = base_anim_rate + (current_speed * speed_to_anim_rate_factor)
124144
effective_anim_rate = clamp(effective_anim_rate, min_effective_anim_rate, max_effective_anim_rate)
125145

146+
# Add the accumulated time since last update, scaled by animation rate
126147
accumulated_shader_time += delta_time * effective_anim_rate
127148

128-
# print("Fish ", name, ": current_speed: ", current_speed, ", effective_anim_rate: ", effective_anim_rate, ", new_accum_time: ", accumulated_shader_time) # Uncomment for verbose logging
149+
# Keep the accumulated time in a reasonable range to prevent floating point precision issues
150+
# Wrap around every ~6.28 seconds (2π) since most shader animations are cyclical
151+
var old_accum_time = accumulated_shader_time
152+
var two_pi = 2.0 * PI
153+
accumulated_shader_time = fmod(accumulated_shader_time, two_pi)
154+
155+
# Debug: Track animation rate changes if enabled
156+
if debug_shader_animation and randf() < 0.05: # Increased sampling rate for better accuracy
157+
var current_time = Time.get_time_dict_from_system()["second"] + Time.get_time_dict_from_system()["minute"] * 60 + Time.get_time_dict_from_system()["hour"] * 3600
158+
var fish_age = current_time - debug_birth_time
159+
var time_increment = delta_time * effective_anim_rate
160+
161+
# Calculate actual animation rate
162+
var real_time_elapsed = current_time - debug_last_real_time
163+
var accum_time_change = accumulated_shader_time - debug_last_accum_time
164+
# Handle wrapping
165+
if accum_time_change < -3.0: # Wrapped backwards
166+
accum_time_change += 2 * PI
167+
elif accum_time_change > 3.0: # Wrapped forwards
168+
accum_time_change -= 2 * PI
169+
var actual_rate = accum_time_change / real_time_elapsed if real_time_elapsed > 0 else 0
170+
171+
print("Fish ", name, ": age=", fish_age, "s anim_rate=", effective_anim_rate, " actual_rate=", actual_rate, " accum_time=", accumulated_shader_time, " delta=", delta_time)
172+
173+
debug_last_accum_time = accumulated_shader_time
174+
debug_last_real_time = current_time
175+
176+
if delta_time > 0.05: # Flag unusually large delta times
177+
print(" -> WARNING: Large delta_time: ", delta_time)
178+
if abs(old_accum_time - accumulated_shader_time) > 0.1:
179+
print(" -> Wrapped from ", old_accum_time, " to ", accumulated_shader_time)
129180
material.set_shader_parameter("animation_time_input", accumulated_shader_time)
130181

131182
func initialize(mStart_position, mHome, mMin_speed, mMax_speed,
@@ -167,8 +218,12 @@ mDifficulty, mMin_weight, mMax_weight, price_weight_multiplier, mType, weight_mu
167218
func set_z_rotation_and_velocity(deg: float) -> void:
168219
rotation[2] = 0
169220
var rad = deg_to_rad(deg)
221+
var facing_left = is_facing_left()
222+
223+
# Debug: Uncomment to track direction changes
224+
# print("Fish ", name, ": set_z_rotation_and_velocity deg=", deg, " facing_left=", facing_left, " rotation.y=", rotation.y)
170225

171-
if is_facing_left():
226+
if facing_left:
172227
rotate_z(-rad)
173228
velocity = Vector3.MODEL_RIGHT * speed
174229
velocity = velocity.rotated(Vector3.FORWARD, rotation.z)
@@ -177,23 +232,98 @@ func set_z_rotation_and_velocity(deg: float) -> void:
177232
velocity = Vector3.MODEL_LEFT * speed
178233
velocity = velocity.rotated(Vector3.BACK, rotation.z)
179234

235+
# Validate that orientation matches velocity direction
236+
validate_orientation_velocity_match()
237+
238+
239+
# Validate that the fish's visual orientation matches its velocity direction
240+
func validate_orientation_velocity_match():
241+
if velocity.length() < 0.1: # Skip validation if fish is barely moving
242+
return
243+
244+
var facing_left = is_facing_left()
245+
var moving_left = velocity.x < 0
246+
var moving_right = velocity.x > 0
247+
248+
# CORRECT coordinate system based on debug output:
249+
# - Vector3.MODEL_RIGHT = (-1, 0, 0) → negative X direction
250+
# - Vector3.MODEL_LEFT = (1, 0, 0) → positive X direction
251+
# Therefore:
252+
# - facing_left = true → velocity = Vector3.MODEL_RIGHT → moves LEFT (negative X)
253+
# - facing_left = false → velocity = Vector3.MODEL_LEFT → moves RIGHT (positive X)
254+
255+
var orientation_matches = (facing_left && moving_left) || (!facing_left && moving_right)
256+
257+
if !orientation_matches:
258+
print("WARNING: Fish ", name, " orientation mismatch!")
259+
print(" - facing_left: ", facing_left)
260+
print(" - rotation.y: ", rotation.y)
261+
print(" - velocity.x: ", velocity.x)
262+
print(" - Expected: facing_left=", facing_left, " should move ", "LEFT" if facing_left else "RIGHT")
263+
print(" - Actual: moving ", "LEFT" if moving_left else "RIGHT")
264+
265+
# Fix the mismatch by flipping the fish to match velocity direction
266+
print(" - Attempting to fix orientation...")
267+
var old_facing_left = facing_left
268+
rotate_y(deg_to_rad(180))
269+
normalize_y_rotation()
270+
var new_facing_left = is_facing_left()
271+
print(" - Fixed. New rotation.y: ", rotation.y, " facing_left: ", old_facing_left, " → ", new_facing_left)
272+
273+
# Verify the fix worked
274+
var new_moving_left = velocity.x < 0
275+
var new_moving_right = velocity.x > 0
276+
var fixed_orientation_matches = (new_facing_left && new_moving_left) || (!new_facing_left && new_moving_right)
277+
if !fixed_orientation_matches:
278+
print(" - ERROR: Fix failed! Still mismatched after rotation.")
279+
elif debug_orientation:
280+
# Optional detailed logging when debug mode is enabled
281+
print("Fish ", name, " orientation OK: facing_left=", facing_left,
282+
" moving=", "LEFT" if moving_left else "RIGHT")
283+
284+
# Helper function to normalize Y rotation and prevent accumulation errors
285+
func normalize_y_rotation():
286+
var old_rotation = rotation.y
287+
rotation.y = fmod(rotation.y, 2 * PI)
288+
if rotation.y > PI:
289+
rotation.y -= 2 * PI
290+
elif rotation.y < -PI:
291+
rotation.y += 2 * PI
180292

293+
# Debug: Uncomment to track rotation normalization
294+
# if abs(old_rotation - rotation.y) > 0.1:
295+
# print("Fish ", name, ": Normalized rotation.y from ", old_rotation, " to ", rotation.y)
296+
181297
func is_facing_left() -> bool:
182-
return rotation[1] < 0
298+
# Normalize rotation.y to handle edge cases and floating point precision
299+
var normalized_y = fmod(rotation.y, 2 * PI)
300+
if normalized_y > PI:
301+
normalized_y -= 2 * PI
302+
elif normalized_y < -PI:
303+
normalized_y += 2 * PI
304+
305+
# Fish faces left when rotated around 180° (π radians)
306+
# This includes both positive π and negative π values
307+
# Range: roughly between π/2 and 3π/2, or in normalized form: |normalized_y| > π/2
308+
return abs(normalized_y) > (PI / 2 + 0.01) # Small epsilon to avoid floating point issues
183309

184310
func is_looking_up() -> bool:
185311
return rotation[2] > 0
186312

187313
func scatter(body: Node3D) -> void:
188314
if (body.global_position.x < global_position.x && is_facing_left() or
189-
body.global_position.x > global_position.x && !is_facing_left()):
315+
body.global_position.x > global_position.x && !is_facing_left()):
190316
rotate_y(deg_to_rad(180))
317+
# Normalize rotation to prevent accumulation errors
318+
normalize_y_rotation()
191319
if (body.global_position.y < global_position.y):
192320
set_z_rotation_and_velocity(randf_range(35, 55))
193321
else:
194322
set_z_rotation_and_velocity(randf_range(-35, -55))
195323

196-
324+
# Extra validation after scattering
325+
validate_orientation_velocity_match()
326+
197327
pass
198328

199329
func get_scale_for_weight(max_weight, min_weight, mWeight) -> Vector3:
@@ -210,5 +340,4 @@ func record_surface_achievement():
210340
var achievement_manager = get_node_or_null("/root/AchievementManager")
211341
if achievement_manager and achievement_manager.has_method("get_achievement_system"):
212342
var achievement_system = achievement_manager.get_achievement_system()
213-
if achievement_system:
214-
achievement_system.record_fish_surface(self.type)
343+
achievement_system.record_fish_surface(self.type)

0 commit comments

Comments
 (0)