diff --git a/src/entity_ball.odin b/src/entity_ball.odin index 7188da2..21b7161 100644 --- a/src/entity_ball.odin +++ b/src/entity_ball.odin @@ -1,31 +1,85 @@ package game +import "core:math/rand" +import "core:log" import rl "vendor:raylib" init_ball :: proc() -> Entity { - ball_radius: f32 = 25 - return Entity{ type = .Ball, active = true, - pos = rl.Vector2{(VIEWPORT_WIDTH / 2), (VIEWPORT_HEIGHT / 2) - (ball_radius / 2)}, - vel = rl.Vector2{400,0}, + pos = rl.Vector2{(VIEWPORT_W / 2), (VIEWPORT_H / 2)}, + speed = 500, + vel = rl.Vector2{0,0}, shape = .Circle, size = rl.Vector2{15, 15} } } -update_ball :: proc(ball: ^Entity, field_bounds: rl.Rectangle, dt: f32) { - ball.pos += ball.vel * dt +serve_ball :: proc(ball: ^Entity) { + // Randomize initial direction: -1.0 or 1.0 + dir_x := f32(rand.float32() > 0.5 ? 1 : -1) + dir_y := rand.choice([]f32{-0.1, 0.1}) // Slightly angled launch + ball.vel = rl.Vector2Normalize({dir_x, dir_y}) * ball.speed +} - if ball.pos.x >= (field_bounds.x + field_bounds.width) - ball.size.x { - ball.vel.x = -ball.vel.x - } +reset_ball :: proc(ball: ^Entity) { + ball.pos = rl.Vector2{(VIEWPORT_W / 2), (VIEWPORT_H / 2)} + ball.vel = rl.Vector2{0,0} +} - if ball.pos.x <= field_bounds.x + ball.size.x { - ball.vel.x = -ball.vel.x - } +update_ball :: proc(ball: ^Entity, level: ^Level, dt: f32) { + // first check the level timer are we waiting to serve? + if level.serve_timer > 0 { + level.serve_timer -= dt + if level.serve_timer <= 0 { + serve_ball(ball) + } + // return early if timer still ticking + return + } + + // serve_ball(ball) + 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.enemy) { + ball.vel.x = -abs(ball.vel.x) + ball.pos.x = level.enemy.pos.x - radius + } + + // bounds collision detection + if ball.pos.y >= (field_bounds.y + field_bounds.height) - ball.size.x { ball.vel.y = -ball.vel.y } + if ball.pos.y <= field_bounds.y + ball.size.x { ball.vel.y = -ball.vel.y } + + if ball.pos.x >= (field_bounds.x + field_bounds.width) - ball.size.x { + level.score_player += 1 + reset_ball(ball) + level.serve_timer = level.wait_time + } + + if ball.pos.x <= field_bounds.x + ball.size.x { + level.score_enemy += 1 + reset_ball(ball) + level.serve_timer = level.wait_time + } +} + +check_ball_paddle_collision :: proc(ball: Entity, paddle: Entity) -> bool { + paddle_rec := rl.Rectangle{ + x = paddle.pos.x, + y = paddle.pos.y, + width = paddle.size.x, + height = paddle.size.y, + } + return rl.CheckCollisionCircleRec(ball.pos, ball.size.x, paddle_rec) } render_ball :: proc(ball: Entity, field_bounds: rl.Rectangle) {