diff --git a/src/entity_ball.odin b/src/entity_ball.odin index 1c31574..73bd040 100644 --- a/src/entity_ball.odin +++ b/src/entity_ball.odin @@ -9,6 +9,7 @@ init_ball :: proc() -> Entity { active = true, pos = rl.Vector2{(VIEWPORT_W / 2), (VIEWPORT_H / 2)}, speed = 500, + max_speed = 800, vel = rl.Vector2{0,0}, shape = .Circle, size = rl.Vector2{15, 15} @@ -25,6 +26,7 @@ serve_ball :: proc(ball: ^Entity) { reset_ball :: proc(ball: ^Entity) { ball.pos = rl.Vector2{(VIEWPORT_W / 2), (VIEWPORT_H / 2)} ball.vel = rl.Vector2{0,0} + ball.speed = 500 } update_ball :: proc(ball: ^Entity, level: ^Level, dt: f32) { @@ -39,18 +41,14 @@ update_ball :: proc(ball: ^Entity, level: ^Level, dt: f32) { return } - ball.pos += ball.vel * dt radius := ball.size.x field_bounds := level.field_bounds // paddle collisions detection (player then enemy) - if check_ball_paddle_collision(ball^, level.player) { - ball.vel.x = abs(ball.vel.x) - // stp stickiness - ball.pos.x = level.player.pos.x + level.player.size.x + radius - } else if check_ball_paddle_collision(ball^, level.opponent) { - ball.vel.x = -abs(ball.vel.x) - ball.pos.x = level.opponent.pos.x - radius + if check_ball_paddle_collision(ball, level.player) { + resolve_collision(ball, level.player, true) + } else if check_ball_paddle_collision(ball, level.opponent) { + resolve_collision(ball, level.opponent, false) } // bounds collision detection @@ -68,9 +66,11 @@ update_ball :: proc(ball: ^Entity, level: ^Level, dt: f32) { reset_ball(ball) level.serve_timer = level.wait_time } + + ball.pos += ball.vel * dt } -check_ball_paddle_collision :: proc(ball: Entity, paddle: Entity) -> bool { +check_ball_paddle_collision :: proc(ball: ^Entity, paddle: Entity) -> bool { paddle_rec := rl.Rectangle{ x = paddle.pos.x, y = paddle.pos.y, @@ -78,14 +78,47 @@ check_ball_paddle_collision :: proc(ball: Entity, paddle: Entity) -> bool { height = paddle.size.y, } collided := rl.CheckCollisionCircleRec(ball.pos, ball.size.x, paddle_rec) - if collided do emit_event(Event{ type = .Ball_Collision }) + if collided do emit_event(.Ball_Collision) return collided } increment_score :: proc(score_side: ^int, max_score: int, player: bool) { score_side^ += 1 + if score_side^ == max_score do emit_event(Game_Over_Data{player}) +} - if score_side^ == max_score do emit_event(Event{ .Game_Over, player }) +increment_speed :: proc(ball: ^Entity) { + if ball.speed <= ball.max_speed { + ball.speed += 100 + ball.vel = rl.Vector2Normalize({ball.vel.x, ball.vel.y}) * ball.speed + } +} + +resolve_collision :: proc(ball: ^Entity, paddle: Entity, is_player: bool) { + ball_center_y := ball.pos.y + paddle_center_y := paddle.pos.y + (paddle.size.y / 2.0) + local_y := ball_center_y - paddle_center_y + half_height := paddle.size.y / 2.0 + + // check if we are in top or bottom half of paddle + hit_t := clamp(local_y / half_height, -1.0, 1.0) + + // direction is dependant of if its the player + dir_x: f32 = is_player ? 1.0 : -1.0 + + // steer the angle by a value using its hit t value + dir_y := hit_t * 1.3 + new_dir := rl.Vector2Normalize({dir_x, dir_y}) + + ball.vel = new_dir * ball.speed + increment_speed(ball) + + // Resolve overlap + if is_player { + ball.pos.x = paddle.pos.x + paddle.size.x + ball.size.x + } else { + ball.pos.x = paddle.pos.x - ball.size.x + } } render_ball :: proc(ball: Entity, field_bounds: rl.Rectangle) {