166 lines
3.8 KiB
Odin
166 lines
3.8 KiB
Odin
package main
|
|
|
|
import rl "vendor:raylib"
|
|
import "vendor:raylib/rlgl"
|
|
import "core:fmt"
|
|
import "core:math"
|
|
|
|
// Virtual game field dimensions
|
|
GameField := Vec2{800, 600}
|
|
|
|
|
|
Brick :: struct {
|
|
position: Vec2,
|
|
velocity: Vec2,
|
|
size: Vec2,
|
|
angle: f32,
|
|
angular_velocity: f32,
|
|
is_flying: bool,
|
|
is_fixed: bool,
|
|
color: rl.Color,
|
|
hits: u8,
|
|
}
|
|
|
|
spawn_brick :: proc(position: Vec2, size: Vec2, is_fixed: bool = true, color: rl.Color = rl.RED, hits : u8 = 1) -> Brick {
|
|
return Brick {
|
|
position = position,
|
|
velocity = Vec2{},
|
|
size = Vec2{30,20},
|
|
is_flying = false,
|
|
is_fixed = is_fixed,
|
|
color = color,
|
|
hits = hits,
|
|
angle = 0
|
|
}
|
|
}
|
|
|
|
|
|
Game :: struct {
|
|
using state: GameState,
|
|
lives: u8,
|
|
pad: Pad,
|
|
balls: [dynamic]Ball,
|
|
bricks: [dynamic]Brick,
|
|
camera: rl.Camera2D
|
|
}
|
|
|
|
|
|
game_init :: proc() -> ^GameState {
|
|
state := new(Game)
|
|
state.variant = state
|
|
state.draw = game_draw
|
|
state.update = game_update
|
|
state.lives = 3
|
|
state.camera = rl.Camera2D{
|
|
zoom = 1,
|
|
target = GameField / 2,
|
|
}
|
|
state.pad = Pad{
|
|
position = Vec2{GameField.x / 2, GameField.y - 40},
|
|
size = {80, 10},
|
|
}
|
|
append(&state.balls, Ball{
|
|
radius = 8,
|
|
position = Vec2{GameField.x / 2, GameField.y - 40 - 8},
|
|
is_on_pad = true,
|
|
pad_offset = Vec2{0, -16},
|
|
})
|
|
|
|
|
|
offset : f32 = 0
|
|
for y : f32 = 40; y < GameField.y / 2; y += 35 {
|
|
for x : f32 = 40 + offset; x < GameField.x - 40; x += 40 {
|
|
append(&state.bricks, spawn_brick(Vec2{x, y}, Vec2{30, 20}, color = rl.YELLOW))
|
|
}
|
|
if offset == 0 { offset = 20 } else { offset = 0 }
|
|
}
|
|
return state
|
|
}
|
|
|
|
game_update :: proc(state: ^GameState, delta: f32) {
|
|
game := transmute(^Game)state
|
|
|
|
using game
|
|
|
|
pad_update(&game.pad, delta)
|
|
if rl.IsKeyPressed(rl.KeyboardKey.SPACE) {
|
|
for &ball, i in balls {
|
|
if !ball.is_on_pad { continue }
|
|
|
|
direction := Vec2{pad.velocity.x / PAD_MAX_SPEED, -1}
|
|
ball.is_on_pad = false
|
|
ball.velocity = rl.Vector2Normalize(direction) * 400
|
|
}
|
|
}
|
|
|
|
all_balls_outside := true
|
|
|
|
#reverse for &ball, i in balls {
|
|
is_inside := ball_update(&ball, game, delta)
|
|
if is_inside { all_balls_outside = false }
|
|
|
|
if ball.position.y > GameField.y + 200 {
|
|
unordered_remove(&balls, i)
|
|
}
|
|
}
|
|
|
|
if all_balls_outside {
|
|
lives -= 1
|
|
append(&balls, Ball{
|
|
radius = 8,
|
|
position = Vec2{GameField.x / 2, GameField.y - 40 - 8},
|
|
is_on_pad = true,
|
|
pad_offset = Vec2{0, -16},
|
|
})
|
|
}
|
|
|
|
#reverse for &brick, i in bricks {
|
|
if !brick.is_flying { continue }
|
|
brick.velocity.y += 500 * delta
|
|
brick.position += brick.velocity * delta
|
|
brick.angle += brick.angular_velocity * delta
|
|
screen_pos := rl.GetWorldToScreen2D(brick.position, camera)
|
|
fmt.println(screen_pos)
|
|
if !rl.CheckCollisionRecs(rl.Rectangle{screen_pos.x - brick.size.x / 2, screen_pos.y - brick.size.y / 2, brick.size.x, brick.size.y},
|
|
rl.Rectangle{0, 0, WINDOWF.x, WINDOWF.y}
|
|
) {
|
|
unordered_remove(&bricks, i)
|
|
}
|
|
}
|
|
|
|
camera.offset = WINDOWF / 2
|
|
camera.zoom = (WINDOWF.y / GameField.y) / 1.1
|
|
}
|
|
|
|
game_draw :: proc(state: ^GameState) {
|
|
game := transmute(^Game)state
|
|
using game
|
|
|
|
rl.BeginMode2D(camera)
|
|
|
|
rl.ClearBackground(rl.RAYWHITE)
|
|
|
|
|
|
rl.DrawRectangleGradientV(0, 0, i32(GameField.x), i32(GameField.y), rl.RED, rl.RAYWHITE)
|
|
rl.DrawRectanglePro(rl.Rectangle{pad.position.x, pad.position.y, pad.size.x, pad.size.y}, pad.size / 2, 0, rl.GREEN)
|
|
|
|
for ball, i in balls {
|
|
rl.DrawCircleV(ball.position, ball.radius, rl.BLUE)
|
|
}
|
|
|
|
|
|
for brick, i in bricks {
|
|
rl.DrawRectanglePro(rl.Rectangle{brick.position.x, brick.position.y, brick.size.x, brick.size.y}, brick.size / 2, brick.angle, brick.color)
|
|
}
|
|
|
|
//rl.DrawText(rl.TextFormat("%f\n%f\n%f\n%f", pad.position.x, pad.position.y, pad.velocity.x, pad.velocity.y), 0, 0, 20, rl.BLACK)
|
|
rl.DrawText(rl.TextFormat("%d", len(bricks)), 0, 0, 20, rl.BLACK)
|
|
|
|
rl.EndMode2D()
|
|
|
|
for i : u8 = 0; i < lives; i += 1 {
|
|
rl.DrawCircleV(Vec2{20 + 20 * f32(i), 20}, 10, rl.BLUE)
|
|
}
|
|
|
|
}
|