@@ -23,8 +23,10 @@ mod physics;
2323mod websocket;
2424
2525use db:: { create_pool, save_all_entities, set_game_time_minutes} ;
26- use game:: GameState ;
26+ use game:: { Entity , EntityType , GameState , Position , Rotation } ;
2727use messages:: GameMessage ;
28+ use rand:: Rng ;
29+ use uuid:: Uuid ;
2830use websocket:: handle_websocket;
2931
3032/// Application state shared across all request handlers.
@@ -53,6 +55,7 @@ pub struct AppState {
5355/// - Entity persistence (every 60 seconds)
5456/// - Physics simulation (60 FPS)
5557/// - World state broadcasting (10 FPS)
58+ /// - Bouncy ball spawning (every 60 seconds)
5659/// 4. HTTP/WebSocket server
5760#[ tokio:: main]
5861async fn main ( ) -> anyhow:: Result < ( ) > {
@@ -155,6 +158,42 @@ async fn main() -> anyhow::Result<()> {
155158 }
156159 } ) ;
157160
161+ // Background task: Spawn a new bouncy ball at a random point on the ground every real-time minute
162+ // Ground is 10000x10000 units, so random positions are within ±5000 for x and z
163+ let game_state_for_ball_spawn = app_state. game . clone ( ) ;
164+ tokio:: spawn ( async move {
165+ let mut interval = tokio:: time:: interval ( tokio:: time:: Duration :: from_secs ( 60 ) ) ;
166+ loop {
167+ interval. tick ( ) . await ;
168+ // Generate random position on the ground
169+ // Create RNG inside loop to avoid Send issues
170+ let x = rand:: thread_rng ( ) . gen_range ( -5000.0 ..5000.0 ) ;
171+ let z = rand:: thread_rng ( ) . gen_range ( -5000.0 ..5000.0 ) ;
172+ // Ball starts at y=500 (5 meters) for visibility, physics will handle falling
173+ let y = 500.0 ;
174+
175+ // Create new ball entity
176+ let ball_id = format ! ( "ball_{}" , Uuid :: new_v4( ) ) ;
177+ let ball_entity = Entity {
178+ id : ball_id. clone ( ) ,
179+ entity_type : EntityType :: Ball ,
180+ position : Position { x, y, z } ,
181+ rotation : Rotation {
182+ x : 0.0 ,
183+ y : 0.0 ,
184+ z : 0.0 ,
185+ } ,
186+ } ;
187+
188+ // Add entity to game state (this will also create the physics body)
189+ let mut game = game_state_for_ball_spawn. write ( ) . await ;
190+ game. add_entity ( ball_entity) ;
191+ drop ( game) ;
192+
193+ tracing:: info!( "Spawned new bouncy ball at ({x}, {z})" ) ;
194+ }
195+ } ) ;
196+
158197 // Set up HTTP routes
159198 let app = Router :: new ( )
160199 // WebSocket endpoint for game client connections
0 commit comments