Arkadodge/ball.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})
}