109 lines
3.0 KiB
Odin
109 lines
3.0 KiB
Odin
package main
|
|
|
|
import "core:math"
|
|
import "core:math/linalg"
|
|
import rl "vendor:raylib"
|
|
|
|
|
|
Ball :: struct {
|
|
position: Vec2,
|
|
velocity: Vec2,
|
|
pad_offset: Vec2,
|
|
angular_velocity: f32,
|
|
radius: f32,
|
|
is_on_pad: bool,
|
|
}
|
|
|
|
|
|
ball_update :: proc(ball: ^Ball, game: ^Game, delta: f32) -> bool {
|
|
using game
|
|
if ball.is_on_pad {
|
|
ball.position = pad.position + ball.pad_offset
|
|
} else {
|
|
ball_position_prev := ball.position
|
|
ball.velocity = rl.Vector2Rotate(ball.velocity, ball.angular_velocity * delta)
|
|
if abs(ball.velocity.y) < 100 && ball.angular_velocity == 0 {
|
|
ball.velocity.y += math.sign(ball.velocity.y) * 100 * delta
|
|
}
|
|
ball.position += ball.velocity * delta
|
|
if ball.position.y < GameField.y {
|
|
if ball.position.x < ball.radius {
|
|
ball.position.x = ball.radius
|
|
ball.velocity.x = -ball.velocity.x
|
|
ball.angular_velocity = 0
|
|
}
|
|
if ball.position.x > GameField.x - ball.radius {
|
|
ball.position.x = GameField.x - ball.radius
|
|
ball.velocity.x = -ball.velocity.x
|
|
ball.angular_velocity = 0
|
|
}
|
|
} else {
|
|
return false
|
|
}
|
|
|
|
if ball.position.y < ball.radius {
|
|
ball.position.y = ball.radius
|
|
ball.velocity.y = -ball.velocity.y
|
|
ball.angular_velocity = 0
|
|
}
|
|
|
|
if ball.position.y + ball.radius > pad.position.y - pad.size.y / 2 &&
|
|
ball_position_prev.y + ball.radius < pad.position.y - pad.size.y / 2 &&
|
|
ball.position.x + ball.radius > pad.position.x - pad.size.x / 2 &&
|
|
ball.position.x - ball.radius < pad.position.x + pad.size.x / 2 {
|
|
dir := Vec2{0, -1}
|
|
offset_x := ball.position.x - pad.position.x
|
|
dir.x = offset_x / (pad.size.x / 2)
|
|
ball.velocity = rl.Vector2Normalize(dir) * rl.Vector2Length(ball.velocity)
|
|
ball.angular_velocity = -pad.velocity.x / PAD_MAX_SPEED * math.PI / 3
|
|
}
|
|
|
|
for &brick, i in bricks {
|
|
if brick.is_flying {
|
|
continue
|
|
}
|
|
clamped := Vec2 {
|
|
clamp(
|
|
ball.position.x,
|
|
brick.position.x - brick.size.x / 2,
|
|
brick.position.x + brick.size.x / 2,
|
|
),
|
|
clamp(
|
|
ball.position.y,
|
|
brick.position.y - brick.size.y / 2,
|
|
brick.position.y + brick.size.y / 2,
|
|
),
|
|
}
|
|
diff := clamped - ball.position
|
|
normal := rl.Vector2Normalize(-diff)
|
|
if rl.Vector2LengthSqr(diff) < ball.radius * ball.radius {
|
|
if brick.type != .SOLID{
|
|
brick.hits -= 1
|
|
}
|
|
if brick.hits <= 0 && !brick.is_flying {
|
|
brick.is_flying = true
|
|
brick.velocity = ball.velocity / 2
|
|
brick.angular_velocity = brick.velocity.x
|
|
game.score += brick.score
|
|
}
|
|
if brick.hit_callback != nil {
|
|
brick.hit_callback(&brick, game)
|
|
}
|
|
ball.position = clamped + normal * ball.radius
|
|
ball.velocity = linalg.reflect(ball.velocity, normal)
|
|
ball.angular_velocity = 0
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
ball_draw :: proc(ball: ^Ball) {
|
|
draw_ball_virtual(ball.position, ball.radius)
|
|
}
|
|
|
|
draw_ball_virtual :: proc(position: Vec2, radius: f32) {
|
|
rl.DrawCircleV(position, radius, rl.Color{80, 120, 255, 255})
|
|
rl.DrawCircleV(position - radius / 3, radius / 5, rl.Color{80, 160, 255, 255})
|
|
}
|