fnm/game.odin

144 lines
3.5 KiB
Odin

package game
import rl "vendor:raylib"
import "core:math"
import "core:math/rand"
import "core:fmt"
Vec2 :: [2]f32
Rect :: rl.Rectangle
Img :: rl.Image
Tex :: rl.Texture
Key :: rl.KeyboardKey
Color :: rl.Color
SCREEN_WIDTH : i32 = 1600
SCREEN_HEIGHT : i32 = 1000
BW := f32(SCREEN_WIDTH)
BH := f32(SCREEN_HEIGHT)
BULLET_SPEED : f32 = 30.5
BULLET_RADIUS: f32 = 2
WEAPON_ROF: f32 = 0.08
ANGULAR_SPEED: f32 = 0.045
THRUST_SPEED: f32 = 2.3
Player :: struct {
pos: Vec2,
angle: f32,
vel: Vec2
}
Bullet :: struct {
pos: Vec2,
vel: Vec2,
}
GameState :: struct {
dt: f32,
keymap: map[string]Key,
player: Player,
bullets: [dynamic]Bullet,
weapon: f32,
}
init_state :: proc() -> ^GameState {
keymap := make(map[string]Key)
keymap["Left"] = .A
keymap["Right"] = .D
keymap["Up"] = .W
keymap["Down"] = .S
state := GameState {
keymap = keymap,
player = Player {
pos = Vec2{BW / 2, BH / 2},
},
}
cloned := new_clone(state)
return cloned
}
get_rand_angle :: proc(min: i32, max: i32) -> f32 { return f32(rl.GetRandomValue(min, max)) * rl.DEG2RAD }
player_input :: proc(using s: ^GameState) {
horizontal: f32
vertical: f32
if rl.IsKeyDown(.D) { horizontal = 1 }
if rl.IsKeyDown(.A) { horizontal = -1 }
if rl.IsKeyDown(.W) { vertical = -1 }
if rl.IsKeyDown(.S) { vertical = 1 }
speed :f32 = 600
player.vel += rl.Vector2Normalize(Vec2{horizontal, vertical}) * (speed * dt)
if rl.IsMouseButtonDown(rl.MouseButton.LEFT) && weapon >= WEAPON_ROF {
angle := player.angle - get_rand_angle(0, 10) + (5 * rl.DEG2RAD)
b_vel := Vec2{ math.cos(angle) , math.sin(angle) } * BULLET_SPEED
append(&s.bullets, Bullet{player.pos, b_vel})
weapon = 0
}
}
update :: proc(using s: ^GameState) {
player.vel *= 0.9
player.pos += player.vel * (THRUST_SPEED * s.dt)
m_pos, p_pos := rl.GetMousePosition(), player.pos
player.angle = math.atan2(m_pos.y - p_pos.y, m_pos.x - p_pos.x)
for i := len(s.bullets) - 1; i >= 0; i -= 1 {
if ( s.bullets[i].pos.x < 0 || s.bullets[i].pos.x > BW
|| s.bullets[i].pos.y < 0 || s.bullets[i].pos.y > BH) {
unordered_remove(&s.bullets, i)
continue
}
s.bullets[i].pos += s.bullets[i].vel
}
weapon += dt
}
draw :: proc(using s: ^GameState) {
rl.DrawCircleV(player.pos, 10, rl.BLACK)
rect := Rect{player.pos.x, player.pos.y, 15, 5}
rl.DrawRectanglePro(rect, Vec2{0,2.5}, player.angle * rl.RAD2DEG, rl.BLACK)
m_pos := rl.GetMousePosition()
reticle_size :f32 = 50
reticle_rect := Rect{m_pos.x - reticle_size / 2, m_pos.y- reticle_size / 2, reticle_size, reticle_size}
color := Color{255, 0, 0, 172}
rl.DrawRectangleRoundedLines(reticle_rect, 0.2, 5, 5, color)
rl.DrawCircleV(m_pos, 3, color)
// Draw Bullets
for i := 0; i < len(s.bullets); i += 1 {
rl.DrawLineV(s.bullets[i].pos, s.bullets[i].pos - s.bullets[i].vel, rl.BLACK)
}
}
main :: proc() {
rl.SetTraceLogLevel(.ERROR)
rl.InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "F&M")
rl.SetTargetFPS(60)
rl.DisableCursor()
state := init_state()
defer free(state)
for !rl.WindowShouldClose() {
state.dt = rl.GetFrameTime()
player_input(state)
update(state)
rl.BeginDrawing()
rl.ClearBackground(rl.WHITE)
draw(state)
rl.EndDrawing()
}
rl.CloseWindow()
}