@@ -130,6 +130,125 @@ impl Default for JumpConfig {
130130 }
131131}
132132
133+ /// Marker component for obstacle entities
134+ #[ derive( Component , Debug , Default ) ]
135+ pub struct Obstacle ;
136+
137+ /// Auto-movement component for entities that move automatically
138+ #[ derive( Component , Debug , Clone ) ]
139+ pub struct AutoMove {
140+ /// Direction of movement (normalized)
141+ pub direction : Vec2 ,
142+ /// Movement speed
143+ pub speed : f32 ,
144+ }
145+
146+ impl Default for AutoMove {
147+ fn default ( ) -> Self {
148+ Self {
149+ direction : Vec2 :: new ( -1.0 , 0.0 ) , // Move left by default
150+ speed : 150.0 ,
151+ }
152+ }
153+ }
154+
155+ impl AutoMove {
156+ pub fn new ( direction : Vec2 , speed : f32 ) -> Self {
157+ Self {
158+ direction : direction. normalize_or_zero ( ) ,
159+ speed,
160+ }
161+ }
162+
163+ /// Creates a left-moving auto-move component
164+ pub fn left ( speed : f32 ) -> Self {
165+ Self :: new ( Vec2 :: new ( -1.0 , 0.0 ) , speed)
166+ }
167+
168+ /// Creates a right-moving auto-move component
169+ pub fn right ( speed : f32 ) -> Self {
170+ Self :: new ( Vec2 :: new ( 1.0 , 0.0 ) , speed)
171+ }
172+ }
173+
174+ /// Marker component for the main camera that follows the player
175+ #[ derive( Component , Debug , Default ) ]
176+ pub struct MainCamera ;
177+
178+ /// Camera follow configuration component
179+ #[ derive( Component , Debug , Clone ) ]
180+ pub struct CameraFollow {
181+ /// Target entity to follow (usually the player)
182+ pub target : Option < Entity > ,
183+ /// Offset from the target position
184+ pub offset : Vec3 ,
185+ /// Smoothing factor (0.0 = instant, 1.0 = very smooth/slow)
186+ pub smoothing : f32 ,
187+ }
188+
189+ impl Default for CameraFollow {
190+ fn default ( ) -> Self {
191+ Self {
192+ target : None ,
193+ offset : Vec3 :: ZERO ,
194+ smoothing : 0.1 ,
195+ }
196+ }
197+ }
198+
199+ impl CameraFollow {
200+ pub fn new ( target : Entity ) -> Self {
201+ Self {
202+ target : Some ( target) ,
203+ ..Default :: default ( )
204+ }
205+ }
206+
207+ pub fn with_offset ( mut self , offset : Vec3 ) -> Self {
208+ self . offset = offset;
209+ self
210+ }
211+
212+ pub fn with_smoothing ( mut self , smoothing : f32 ) -> Self {
213+ self . smoothing = smoothing. clamp ( 0.01 , 1.0 ) ;
214+ self
215+ }
216+ }
217+
218+ /// Marker component for UI root node
219+ #[ derive( Component , Debug , Default ) ]
220+ pub struct GameUI ;
221+
222+ /// Marker component for score display UI
223+ #[ derive( Component , Debug , Default ) ]
224+ pub struct ScoreDisplay ;
225+
226+ /// Marker component for health bar UI
227+ #[ derive( Component , Debug , Default ) ]
228+ pub struct HealthBar ;
229+
230+ /// Marker component for health bar fill (the colored part)
231+ #[ derive( Component , Debug , Default ) ]
232+ pub struct HealthBarFill ;
233+
234+ /// Damage value component for obstacles
235+ #[ derive( Component , Debug , Clone ) ]
236+ pub struct DamageOnContact {
237+ pub damage : f32 ,
238+ }
239+
240+ impl Default for DamageOnContact {
241+ fn default ( ) -> Self {
242+ Self { damage : 10.0 }
243+ }
244+ }
245+
246+ impl DamageOnContact {
247+ pub fn new ( damage : f32 ) -> Self {
248+ Self { damage }
249+ }
250+ }
251+
133252#[ cfg( test) ]
134253mod tests {
135254 use super :: * ;
@@ -211,4 +330,52 @@ mod tests {
211330 assert_eq ! ( config. jump_velocity, 450.0 ) ;
212331 assert_eq ! ( config. jump_cut_multiplier, 0.5 ) ;
213332 }
333+
334+ #[ test]
335+ fn test_auto_move_default ( ) {
336+ let auto_move = AutoMove :: default ( ) ;
337+ assert_eq ! ( auto_move. direction, Vec2 :: new( -1.0 , 0.0 ) ) ;
338+ assert_eq ! ( auto_move. speed, 150.0 ) ;
339+ }
340+
341+ #[ test]
342+ fn test_auto_move_new ( ) {
343+ let auto_move = AutoMove :: new ( Vec2 :: new ( 2.0 , 0.0 ) , 200.0 ) ;
344+ assert ! ( ( auto_move. direction. x - 1.0 ) . abs( ) < f32 :: EPSILON ) ;
345+ assert_eq ! ( auto_move. speed, 200.0 ) ;
346+ }
347+
348+ #[ test]
349+ fn test_auto_move_left ( ) {
350+ let auto_move = AutoMove :: left ( 100.0 ) ;
351+ assert_eq ! ( auto_move. direction, Vec2 :: new( -1.0 , 0.0 ) ) ;
352+ assert_eq ! ( auto_move. speed, 100.0 ) ;
353+ }
354+
355+ #[ test]
356+ fn test_auto_move_right ( ) {
357+ let auto_move = AutoMove :: right ( 100.0 ) ;
358+ assert_eq ! ( auto_move. direction, Vec2 :: new( 1.0 , 0.0 ) ) ;
359+ assert_eq ! ( auto_move. speed, 100.0 ) ;
360+ }
361+
362+ #[ test]
363+ fn test_camera_follow_default ( ) {
364+ let follow = CameraFollow :: default ( ) ;
365+ assert ! ( follow. target. is_none( ) ) ;
366+ assert_eq ! ( follow. offset, Vec3 :: ZERO ) ;
367+ assert ! ( ( follow. smoothing - 0.1 ) . abs( ) < f32 :: EPSILON ) ;
368+ }
369+
370+ #[ test]
371+ fn test_damage_on_contact_default ( ) {
372+ let damage = DamageOnContact :: default ( ) ;
373+ assert_eq ! ( damage. damage, 10.0 ) ;
374+ }
375+
376+ #[ test]
377+ fn test_damage_on_contact_new ( ) {
378+ let damage = DamageOnContact :: new ( 25.0 ) ;
379+ assert_eq ! ( damage. damage, 25.0 ) ;
380+ }
214381}
0 commit comments