@@ -115,13 +115,24 @@ impl Default for AquariumEnvironment {
115
115
}
116
116
}
117
117
118
+ /// How a fish should behave within the aquarium.
119
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
120
+ pub enum FishBehavior {
121
+ /// Normal aquarium fish: bounces on edges and persists.
122
+ Normal ,
123
+ /// Transit fish: swims straight across and despawns once fully off-screen.
124
+ Transit ,
125
+ }
126
+
118
127
/// The aquarium state that the parent application owns and updates.
119
128
#[ derive( Debug , Default ) ]
120
129
pub struct AquariumState {
121
130
/// Bounds of the aquarium in character cells (width, height).
122
131
pub size : ( usize , usize ) ,
123
132
/// All fish currently in the aquarium.
124
133
pub fishes : Vec < FishInstance > ,
134
+ /// Behavior associated with each fish (parallel to `fishes`). Defaults to Normal.
135
+ pub fish_behaviors : Vec < FishBehavior > ,
125
136
/// Rising bubbles.
126
137
pub bubbles : Vec < Bubble > ,
127
138
/// Background/props animation state.
@@ -379,6 +390,15 @@ pub fn update_aquarium(state: &mut AquariumState, assets: &[FishArt]) {
379
390
// Ensure environment exists.
380
391
ensure_environment_initialized ( state) ;
381
392
393
+ // Keep `fish_behaviors` in sync with `fishes` (pad with Normal, or truncate).
394
+ if state. fish_behaviors . len ( ) < state. fishes . len ( ) {
395
+ state
396
+ . fish_behaviors
397
+ . resize ( state. fishes . len ( ) , FishBehavior :: Normal ) ;
398
+ } else if state. fish_behaviors . len ( ) > state. fishes . len ( ) {
399
+ state. fish_behaviors . truncate ( state. fishes . len ( ) ) ;
400
+ }
401
+
382
402
// Integrate fish and handle bounce.
383
403
384
404
// Spawn entities deterministically when none present and past next spawn tick.
@@ -453,10 +473,17 @@ pub fn update_aquarium(state: &mut AquariumState, assets: &[FishArt]) {
453
473
position : ( xi, y as f32 ) ,
454
474
velocity : ( speed, 0.0 ) ,
455
475
} ) ;
476
+ state. fish_behaviors . push ( FishBehavior :: Transit ) ;
456
477
}
457
478
state. env . next_school_spawn = state. tick + 1800 ; // ~60s at 30 fps
458
479
}
459
- for fish in & mut state. fishes {
480
+ // Update fish with behavior-aware logic (Transit vs Normal).
481
+ let mut kept_fishes: Vec < FishInstance > = Vec :: with_capacity ( state. fishes . len ( ) ) ;
482
+ let mut kept_behaviors: Vec < FishBehavior > = Vec :: with_capacity ( state. fish_behaviors . len ( ) ) ;
483
+ for i in 0 ..state. fishes . len ( ) {
484
+ let mut fish = state. fishes [ i] . clone ( ) ;
485
+ let behavior = * state. fish_behaviors . get ( i) . unwrap_or ( & FishBehavior :: Normal ) ;
486
+
460
487
fish. position . 0 += fish. velocity . 0 * dt * fish_speed_mult;
461
488
fish. position . 1 += fish. velocity . 1 * dt * fish_speed_mult;
462
489
// Subtle deterministic horizontal jitter (does not mutate velocity)
@@ -470,7 +497,20 @@ pub fn update_aquarium(state: &mut AquariumState, assets: &[FishArt]) {
470
497
. map ( |a| ( a. width as f32 , a. height as f32 ) )
471
498
. unwrap_or ( ( 1.0 , 1.0 ) ) ;
472
499
473
- // Bounce on X.
500
+ if behavior == FishBehavior :: Transit {
501
+ // Despawn transit fish once fully off-screen.
502
+ let off_right = fish. position . 0 > aw;
503
+ let off_left = fish. position . 0 + fw <= 0.0 ;
504
+ if off_right || off_left {
505
+ // drop (do not keep)
506
+ } else {
507
+ kept_fishes. push ( fish) ;
508
+ kept_behaviors. push ( behavior) ;
509
+ }
510
+ continue ;
511
+ }
512
+
513
+ // Normal bounce behavior.
474
514
if fish. position . 0 < 0.0 {
475
515
fish. position . 0 = 0.0 ;
476
516
fish. velocity . 0 = fish. velocity . 0 . abs ( ) ;
@@ -493,7 +533,6 @@ pub fn update_aquarium(state: &mut AquariumState, assets: &[FishArt]) {
493
533
}
494
534
}
495
535
496
- // Bounce on Y.
497
536
if fish. position . 1 < 0.0 {
498
537
fish. position . 1 = 0.0 ;
499
538
fish. velocity . 1 = fish. velocity . 1 . abs ( ) ;
@@ -515,7 +554,12 @@ pub fn update_aquarium(state: &mut AquariumState, assets: &[FishArt]) {
515
554
fish. velocity . 0 = -fish. velocity . 0 ;
516
555
}
517
556
}
557
+
558
+ kept_fishes. push ( fish) ;
559
+ kept_behaviors. push ( behavior) ;
518
560
}
561
+ state. fishes = kept_fishes;
562
+ state. fish_behaviors = kept_behaviors;
519
563
520
564
// Occasionally emit bubbles from fish mouths, deterministically based on tick.
521
565
// Emit every 24 ticks per fish to avoid randomness in the core crate.
0 commit comments