Arkadodge/brick.odin

179 lines
3.9 KiB
Odin

package main
import rl "vendor:raylib"
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
}
Brick :: struct {
position: Vec2,
velocity: Vec2,
size: Vec2,
angle: f32,
angular_velocity: f32,
is_flying: bool,
is_fixed: bool,
color: rl.Color,
hits: i32,
is_to_free: bool,
type: Brick_Type,
score: u32,
hit_callback: proc(brick: ^Brick, game: ^Game)
}
spawn_brick :: proc(position: Vec2, size: Vec2, type: Brick_Type = Brick_Type.NORMAL) -> Brick {
return Brick {
position = position,
velocity = Vec2{},
size = size,
is_flying = false,
is_fixed = true,
type = type,
color = brick_colors[type],
hits = brick_hits[type],
score = brick_scores[type],
hit_callback = brick_callbacks[type],
angle = 0
}
}
brick_update :: proc(brick: ^Brick, game: ^Game, delta: f32) {
if !brick.is_flying { return }
brick.velocity.y += 500 * delta
brick.position += brick.velocity * delta
brick.angle += brick.angular_velocity * delta
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
}
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
}
}
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)
}
}
}
}