55
66#define ARENA_HALF_SIZE 500.0f
77#define MAX_HP 100.0f
8- #define PLAYER_SPEED_PER_TICK 25.0f
8+ #define EPSILON 1e-6f
9+
910#define PLAYER_SIZE 30.0f
10- #define BOSS_SIZE 50 .0f
11+ #define PLAYER_SPEED_PER_TICK 25 .0f
1112#define PLAYER_ATTACK_RADIUS 40.0f
1213#define PLAYER_ATTACK_TICKS 3
14+ #define PLAYER_ATTACK_DMG 5.0f
1315#define PLAYER_DODGE_TICKS 4
1416#define PLAYER_IFRAME_TICKS 2
1517#define PLAYER_DODGE_COOLDOWN 15
1618#define PLAYER_DODGE_SPEED_PER_TICK 35.0f
17- #define PLAYER_ATTACK_DMG 5.0f
19+
20+ #define BOSS_SIZE 50.0f
1821#define BOSS_ATTACK_DMG 15.0f
1922#define BOSS_AOE_ATTACK_RADIUS 80.0f
2023#define BOSS_IDLE_TICKS 7
2124#define BOSS_WINDUP_TICKS 5
2225#define BOSS_ACTIVE_TICKS 5
2326#define BOSS_RECOVERY_TICKS 5
2427
25- #define HP_BAR_WIDTH 40
26- #define HP_BAR_HEIGHT 5
27-
2828#define REWARD_APPROACH 0.7f
2929#define REWARD_HIT_WALL -0.05f
3030#define REWARD_PLAYER_HIT_BOSS 0.07f
3636#define REWARD_TICK -0.01f
3737#define EPISODE_LENGTH 600
3838
39- const Color PLAYER_COLOR = (Color ){50 , 100 , 255 , 255 };
40- const Color BOSS_COLOR = (Color ){0 , 187 , 187 , 255 };
41- const Color TEXT_COLOR = (Color ){241 , 241 , 241 , 255 };
42- const Color HITBOX_COLOR = (Color ){241 , 241 , 241 , 50 };
43- const Color BACKGROUND_COLOR = (Color ){6 , 24 , 24 , 255 };
44- const Color HP_COLOR = (Color ){0 , 255 , 0 , 255 };
39+ #define WINDOW_SIZE 720
40+ #define TARGET_FPS 30
41+ #define HP_BAR_WIDTH 40
42+ #define HP_BAR_HEIGHT 5
43+ #define UI_MARGIN 20
44+ #define UI_RIGHT_X 580
45+ #define UI_BOTTOM_Y 680
46+ #define UI_HP_BAR_Y 700
47+ #define UI_FONT_SIZE 20
48+ #define UI_FONT_SIZE_SMALL 16
49+
50+ static const Color PLAYER_COLOR = (Color ){50 , 100 , 255 , 255 };
51+ static const Color BOSS_COLOR = (Color ){0 , 187 , 187 , 255 };
52+ static const Color TEXT_COLOR = (Color ){241 , 241 , 241 , 255 };
53+ static const Color HITBOX_COLOR = (Color ){241 , 241 , 241 , 50 };
54+ static const Color BACKGROUND_COLOR = (Color ){6 , 24 , 24 , 255 };
55+ static const Color HP_COLOR = (Color ){0 , 255 , 0 , 255 };
4556
4657typedef enum { PLAYER_IDLING , PLAYER_DODGING , PLAYER_ATTACKING } PlayerState ;
4758
@@ -220,6 +231,7 @@ void c_step(BossFight *env) {
220231 else
221232 action = 0 ;
222233 }
234+
223235 float dx = 0 ;
224236 float dy = 0 ;
225237
@@ -260,12 +272,12 @@ void c_step(BossFight *env) {
260272 env -> player_state = PLAYER_DODGING ;
261273 }
262274
263- // Dodge = multi-tick movement out of the AOE (no i-frames)
275+ // Dodge: multi-tick movement away from boss, with i-frames at start
264276 if (env -> player_state == PLAYER_DODGING ) {
265277 float away_x = env -> player_x - env -> boss_x ;
266278 float away_y = env -> player_y - env -> boss_y ;
267279 float away_norm = sqrtf (away_x * away_x + away_y * away_y );
268- if (away_norm > 1e-6f ) {
280+ if (away_norm > EPSILON ) {
269281 env -> player_x += (away_x / away_norm ) * PLAYER_DODGE_SPEED_PER_TICK ;
270282 env -> player_y += (away_y / away_norm ) * PLAYER_DODGE_SPEED_PER_TICK ;
271283 }
@@ -290,7 +302,7 @@ void c_step(BossFight *env) {
290302 env -> dist_to_boss = dist ;
291303
292304 // Push player out if clipping into boss
293- if (dist < BOSS_SIZE + PLAYER_SIZE && dist > 1e-6f ) {
305+ if (dist < BOSS_SIZE + PLAYER_SIZE && dist > EPSILON ) {
294306 float overlap = BOSS_SIZE + PLAYER_SIZE - dist ;
295307 float dx = env -> player_x - env -> boss_x ;
296308 float dy = env -> player_y - env -> boss_y ;
@@ -313,8 +325,7 @@ void c_step(BossFight *env) {
313325 env -> player_state == PLAYER_DODGING &&
314326 env -> player_state_ticks > (PLAYER_DODGE_TICKS - PLAYER_IFRAME_TICKS );
315327
316- // AOE persists longer than the i-frame window
317- // If player is still in the hitbox after i-frames, you get hit.
328+ // Boss deals damage every tick while player in AOE (unless i-framed)
318329 bool boss_can_hit = in_aoe_attack && !player_iframed ;
319330 bool boss_can_damage = env -> boss_state == BOSS_ATTACKING && boss_can_hit ;
320331 if (boss_can_damage ) {
@@ -399,17 +410,17 @@ void c_step(BossFight *env) {
399410
400411int world_to_screen (float world_coord ) {
401412 return (int )((world_coord + ARENA_HALF_SIZE ) / (2 * ARENA_HALF_SIZE ) *
402- 720.0f );
413+ ( float ) WINDOW_SIZE );
403414}
404415
405416float radius_to_screen (float world_radius ) {
406- return world_radius / (2 * ARENA_HALF_SIZE ) * 720.0f ;
417+ return world_radius / (2 * ARENA_HALF_SIZE ) * ( float ) WINDOW_SIZE ;
407418}
408419
409420void c_render (BossFight * env ) {
410421 if (!IsWindowReady ()) {
411- InitWindow (720 , 720 , "BossFight" );
412- SetTargetFPS (30 );
422+ InitWindow (WINDOW_SIZE , WINDOW_SIZE , "BossFight" );
423+ SetTargetFPS (TARGET_FPS );
413424 }
414425
415426 if (IsKeyDown (KEY_ESCAPE )) {
@@ -419,19 +430,19 @@ void c_render(BossFight *env) {
419430 BeginDrawing ();
420431
421432 ClearBackground (BACKGROUND_COLOR );
422- DrawText ("Beat the boss!" , 20 , 20 , 20 , TEXT_COLOR );
433+ DrawText ("Beat the boss!" , UI_MARGIN , UI_MARGIN , UI_FONT_SIZE , TEXT_COLOR );
423434
424435 // Stats top-right
425436 char stats [64 ];
426437 snprintf (stats , sizeof (stats ), "W:%d L:%d T:%d" , env -> player_wins ,
427438 env -> boss_wins , env -> timeouts );
428- DrawText (stats , 580 , 20 , 20 , TEXT_COLOR );
439+ DrawText (stats , UI_RIGHT_X , UI_MARGIN , UI_FONT_SIZE , TEXT_COLOR );
429440
430441 // Player
431442 int player_sx = world_to_screen (env -> player_x );
432443 int player_sy = world_to_screen (env -> player_y );
433- int player_hp_bar_y = player_sy + ( int ) radius_to_screen ( PLAYER_SIZE ) + 5 ;
434- int player_hp_width = (int )(( float ) env -> player_hp / MAX_HP * HP_BAR_WIDTH );
444+ float player_hp_ratio = fmaxf ( 0.0f , fminf ( 1.0f , env -> player_hp / MAX_HP )) ;
445+ int player_hp_width = (int )(player_hp_ratio * HP_BAR_WIDTH );
435446
436447 Color player_color = env -> player_hp <= 0 ? RED : PLAYER_COLOR ;
437448 DrawCircle (player_sx , player_sy ,
@@ -442,8 +453,8 @@ void c_render(BossFight *env) {
442453 // Boss
443454 int boss_sx = world_to_screen (env -> boss_x );
444455 int boss_sy = world_to_screen (env -> boss_y );
445- int boss_hp_bar_y = boss_sy + ( int ) radius_to_screen ( BOSS_SIZE ) + 5 ;
446- int boss_hp_width = (int )(( float ) env -> boss_hp / MAX_HP * HP_BAR_WIDTH );
456+ float boss_hp_ratio = fmaxf ( 0.0f , fminf ( 1.0f , env -> boss_hp / MAX_HP )) ;
457+ int boss_hp_width = (int )(boss_hp_ratio * HP_BAR_WIDTH );
447458
448459 Color boss_color = env -> boss_hp <= 0 ? RED : BOSS_COLOR ;
449460 DrawCircle (boss_sx , boss_sy ,
@@ -452,14 +463,18 @@ void c_render(BossFight *env) {
452463 DrawCircle (boss_sx , boss_sy , radius_to_screen (BOSS_SIZE ), boss_color );
453464
454465 // Player HP bar - bottom left
455- DrawText ("Player" , 20 , 680 , 16 , TEXT_COLOR );
456- DrawRectangle (20 , 700 , HP_BAR_WIDTH * 3 , HP_BAR_HEIGHT , DARKGRAY );
457- DrawRectangle (20 , 700 , player_hp_width * 3 , HP_BAR_HEIGHT , HP_COLOR );
466+ DrawText ("Player" , UI_MARGIN , UI_BOTTOM_Y , UI_FONT_SIZE_SMALL , TEXT_COLOR );
467+ DrawRectangle (UI_MARGIN , UI_HP_BAR_Y , HP_BAR_WIDTH * 3 , HP_BAR_HEIGHT ,
468+ DARKGRAY );
469+ DrawRectangle (UI_MARGIN , UI_HP_BAR_Y , player_hp_width * 3 , HP_BAR_HEIGHT ,
470+ HP_COLOR );
458471
459472 // Boss HP bar - bottom right
460- DrawText ("Boss" , 580 , 680 , 16 , TEXT_COLOR );
461- DrawRectangle (580 , 700 , HP_BAR_WIDTH * 3 , HP_BAR_HEIGHT , DARKGRAY );
462- DrawRectangle (580 , 700 , boss_hp_width * 3 , HP_BAR_HEIGHT , HP_COLOR );
473+ DrawText ("Boss" , UI_RIGHT_X , UI_BOTTOM_Y , UI_FONT_SIZE_SMALL , TEXT_COLOR );
474+ DrawRectangle (UI_RIGHT_X , UI_HP_BAR_Y , HP_BAR_WIDTH * 3 , HP_BAR_HEIGHT ,
475+ DARKGRAY );
476+ DrawRectangle (UI_RIGHT_X , UI_HP_BAR_Y , boss_hp_width * 3 , HP_BAR_HEIGHT ,
477+ HP_COLOR );
463478
464479 EndDrawing ();
465480}
0 commit comments