2024-09-09 00:18:35 +03:00
|
|
|
package main
|
|
|
|
|
|
|
|
import rl "vendor:raylib"
|
2024-09-09 23:41:16 +03:00
|
|
|
import "core:fmt"
|
|
|
|
|
|
|
|
Brick_Type :: enum {
|
|
|
|
NORMAL,
|
|
|
|
EXPLOSIVE,
|
|
|
|
BONUS,
|
|
|
|
HARD,
|
|
|
|
SOLID
|
|
|
|
}
|
|
|
|
|
|
|
|
brick_names := [Brick_Type]cstring {
|
|
|
|
.NORMAL = "обычный",
|
|
|
|
.EXPLOSIVE = "взрывной",
|
|
|
|
.BONUS = "восстанавливает здоровье",
|
|
|
|
.HARD = "крепкий",
|
|
|
|
.SOLID = "нерушимый"
|
|
|
|
}
|
|
|
|
|
|
|
|
brick_colors := [Brick_Type]rl.Color {
|
|
|
|
.NORMAL = rl.Color{190, 190, 190, 255},
|
|
|
|
.EXPLOSIVE = rl.Color{250, 30, 30, 255},
|
|
|
|
.BONUS = rl.Color{30, 250, 30, 255},
|
|
|
|
.HARD = rl.Color{190, 190, 255, 255},
|
|
|
|
.SOLID = rl.Color{80, 80, 100, 255}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
brick_scores := [Brick_Type]u32 {
|
|
|
|
.NORMAL = 100,
|
|
|
|
.HARD = 500,
|
|
|
|
.BONUS = 1000,
|
|
|
|
.EXPLOSIVE = 1000,
|
|
|
|
.SOLID = 0,
|
|
|
|
}
|
|
|
|
|
|
|
|
brick_hits := [Brick_Type]i32 {
|
|
|
|
.NORMAL = 1,
|
|
|
|
.EXPLOSIVE = 1,
|
|
|
|
.BONUS = 1,
|
|
|
|
.HARD = 2,
|
|
|
|
.SOLID = 10000000
|
|
|
|
}
|
|
|
|
|
|
|
|
BrickHitCallback :: proc(brick: ^Brick, game: ^Game)
|
|
|
|
|
|
|
|
brick_callbacks := [Brick_Type]BrickHitCallback {
|
|
|
|
.NORMAL = nil,
|
|
|
|
.EXPLOSIVE = brick_explode,
|
|
|
|
.BONUS = nil,
|
|
|
|
.HARD = nil,
|
|
|
|
.SOLID = nil
|
|
|
|
}
|
2024-09-09 00:18:35 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Brick :: struct {
|
|
|
|
position: Vec2,
|
|
|
|
velocity: Vec2,
|
|
|
|
size: Vec2,
|
|
|
|
angle: f32,
|
|
|
|
angular_velocity: f32,
|
|
|
|
is_flying: bool,
|
|
|
|
is_fixed: bool,
|
|
|
|
color: rl.Color,
|
2024-09-09 23:41:16 +03:00
|
|
|
hits: i32,
|
2024-09-09 00:18:35 +03:00
|
|
|
is_to_free: bool,
|
2024-09-09 23:41:16 +03:00
|
|
|
type: Brick_Type,
|
|
|
|
score: u32,
|
|
|
|
hit_callback: proc(brick: ^Brick, game: ^Game)
|
2024-09-09 00:18:35 +03:00
|
|
|
}
|
|
|
|
|
2024-09-09 23:41:16 +03:00
|
|
|
spawn_brick :: proc(position: Vec2, size: Vec2, type: Brick_Type = Brick_Type.NORMAL) -> Brick {
|
2024-09-09 00:18:35 +03:00
|
|
|
return Brick {
|
|
|
|
position = position,
|
|
|
|
velocity = Vec2{},
|
2024-09-09 23:41:16 +03:00
|
|
|
size = size,
|
2024-09-09 00:18:35 +03:00
|
|
|
is_flying = false,
|
2024-09-09 23:41:16 +03:00
|
|
|
is_fixed = true,
|
|
|
|
type = type,
|
|
|
|
color = brick_colors[type],
|
|
|
|
hits = brick_hits[type],
|
|
|
|
score = brick_scores[type],
|
|
|
|
hit_callback = brick_callbacks[type],
|
2024-09-09 00:18:35 +03:00
|
|
|
angle = 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-09 23:41:16 +03:00
|
|
|
brick_update :: proc(brick: ^Brick, game: ^Game, delta: f32) {
|
2024-09-09 00:18:35 +03:00
|
|
|
if !brick.is_flying { return }
|
|
|
|
brick.velocity.y += 500 * delta
|
|
|
|
brick.position += brick.velocity * delta
|
|
|
|
brick.angle += brick.angular_velocity * delta
|
2024-09-09 23:41:16 +03:00
|
|
|
screen_pos := rl.GetWorldToScreen2D(brick.position, game.camera)
|
|
|
|
|
|
|
|
if brick.position.x < brick.size.x / 2 {
|
|
|
|
brick.position.x = brick.size.x / 2
|
|
|
|
brick.velocity.x = -brick.velocity.x
|
|
|
|
}
|
|
|
|
if brick.position.x > GameField.x - brick.size.x / 2 {
|
|
|
|
brick.position.x = GameField.x - brick.size.x / 2
|
|
|
|
brick.velocity.x = -brick.velocity.x
|
|
|
|
}
|
|
|
|
|
|
|
|
if rl.CheckCollisionCircleRec(brick.position, brick.size.x / 2, rl.Rectangle{
|
|
|
|
game.pad.position.x - game.pad.size.x / 2,
|
|
|
|
game.pad.position.y - game.pad.size.y / 2,
|
|
|
|
game.pad.size.x,
|
|
|
|
game.pad.size.y
|
|
|
|
}) {
|
|
|
|
if brick.type != .BONUS {
|
|
|
|
game.pad.health -= 30
|
|
|
|
} else {
|
|
|
|
game.pad.health = min(game.pad.health + 30, 100)
|
|
|
|
}
|
|
|
|
brick.is_to_free = true
|
|
|
|
}
|
2024-09-09 00:18:35 +03:00
|
|
|
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}
|
|
|
|
) {
|
|
|
|
brick.is_to_free = true
|
|
|
|
}
|
|
|
|
}
|
2024-09-09 23:41:16 +03:00
|
|
|
|
|
|
|
brick_draw :: proc(brick: ^Brick) {
|
|
|
|
rl.DrawRectanglePro(
|
|
|
|
rl.Rectangle{brick.position.x, brick.position.y, brick.size.x, brick.size.y},
|
|
|
|
brick.size / 2,
|
|
|
|
brick.angle,
|
|
|
|
brick.color
|
|
|
|
)
|
|
|
|
if brick.type == .HARD && brick.hits <= 1 {
|
|
|
|
rl.DrawRectanglePro(
|
|
|
|
rl.Rectangle{brick.position.x, brick.position.y, brick.size.x / 1.5, brick.size.y / 1.5},
|
|
|
|
brick.size / 3,
|
|
|
|
brick.angle,
|
|
|
|
rl.ColorTint(brick.color, rl.Color{180, 180, 180, 255})
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
brick_explode :: proc(brick: ^Brick, game: ^Game) {
|
|
|
|
radius := brick.size.x * 2
|
|
|
|
brick.is_to_free = true
|
|
|
|
|
|
|
|
explode(brick.position, radius, 0.4)
|
|
|
|
for &other, i in game.bricks {
|
|
|
|
if other.is_to_free {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if &other == brick {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
diff := other.position - brick.position
|
|
|
|
dir := rl.Vector2Normalize(diff)
|
|
|
|
dis := rl.Vector2Length(diff)
|
|
|
|
if dis > radius {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
switch other.type {
|
|
|
|
case .NORMAL, .HARD, .SOLID:
|
|
|
|
other.hits = 0
|
|
|
|
other.is_flying = true
|
|
|
|
other.velocity += dir * (radius - dis + 50) * 3
|
|
|
|
other.angular_velocity = other.velocity.x * 2
|
|
|
|
game.score += other.score
|
|
|
|
case .EXPLOSIVE, .BONUS:
|
|
|
|
if other.hit_callback != nil {
|
|
|
|
other.hit_callback(&other, game)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|