package main import rl "vendor:raylib" import "vendor:raylib/rlgl" import "core:fmt" import "core:math" import "core:math/ease" import "core:math/rand" import "core:strings" import "core:strconv" // Virtual game field dimensions GameField := vec2{400, 200} Game :: struct { using state: GameState, health: u8, player: Player, camera: rl.Camera3D, camera_offset: vec3, score: u32, background: rl.Texture, plane: rl.Model, bullets: [dynamic]Bullet, snake_max_health: int, snake_health: int } game_init :: proc(prev: ^GameState = nil) -> ^GameState { state := new(Game) state.previous = prev state.variant = state state.draw = game_draw state.update = game_update state.free = game_free rlgl.DisableBackfaceCulling() img := rl.GenImageChecked(1024, 1024, 128, 128, rl.Color{60, 255, 255, 255}, rl.Color{30, 220, 220, 255}) state.background = rl.LoadTextureFromImage(img) state.plane = rl.LoadModel(".\\assets\\models\\background.obj") rl.UnloadImage(img) game_setup(state) return state } game_setup :: proc(game: ^Game) { clear(&game.bullets) game.player = player_spawn({GameField.x / 2 + 50, 20, 0}) game.health = 100 snake_spawn({10, 10, 0}, math.PI, 70) for segment in Segments { game.snake_max_health += int(segment.health) } game.camera = rl.Camera3D{ target = game.player.pos, position = game.player.pos + vec3backward * 50, fovy = 60, //offset = WSize/2, projection = rl.CameraProjection.PERSPECTIVE, up = vec3up } game.camera.target.x = clamp(game.camera.target.x, -GameField.x/2, GameField.x/2) game.camera.target.y = clamp(game.camera.target.y, 0, GameField.y) game.camera.position = game.camera.target + vec3backward * 50 } game_gen_level :: proc(game: ^Game) { } game_update :: proc(state: ^GameState, delta: f32) { game := transmute(^Game)state using game player_update(&player, game, delta) #reverse for &bullet, i in bullets { bullet_process(&bullet, game, delta) if !bullet.alive { unordered_remove(&bullets, i) } } snake_process(game, delta) target_offset := player.vel / 5 camera_offset = rl.Vector3MoveTowards(camera_offset, target_offset, rl.Vector3Length(target_offset - camera_offset) * 10 * delta) camera.target = player.pos + camera_offset camera.target.x = clamp(camera.target.x, -GameField.x/2, GameField.x/2) camera.target.y = clamp(camera.target.y, 0, GameField.y) camera.position = camera.target + vec3backward * 50 } game_draw :: proc(state: ^GameState) { game := transmute(^Game)state using game rl.BeginMode3D(camera) rl.DrawModel(game.plane, {0, 0, 500}, 1000, rl.WHITE) yy : i32 = 0 snake_draw(game) player_draw(&player) for bullet in bullets { bullet_draw(bullet) } rl.EndMode3D() rl.DrawText(rl.TextFormat("HEALTH: %d", snake_health), 0, 0, 20, rl.BLACK) rl.DrawText(rl.TextFormat("STATE: %s", Head.state), 0, 20, 20, rl.BLACK) hb_text : cstring = "Jörmungandr" height := 30 * (WSize.y / 480) hb_health : f32 = f32(snake_health) / f32(snake_max_health) if snake_health == 0 { hb_health = f32(Head.health) / f32(Head.max_health) hb_text = "Jörmungandr's head" } rl.DrawRectangleV({0, WSize.y - height - 10}, {WSize.x, height + 10}, rl.WHITE) hb_width := hb_health * WSize.x rl.DrawRectangleV({WSize.x / 2 - hb_width / 2, WSize.y - height - 7}, {hb_width, height + 4}, rl.RED) draw_text_centered(FontTitle, hb_text, {WSize.x / 2, WSize.y - height / 2}, height) } game_free :: proc(state: ^GameState) { game := transmute(^Game)state rl.UnloadTexture(game.background) free(state) }