Final version. Fixed menus, music. Added tutorial and control schemes
This commit is contained in:
parent
061f255be4
commit
83ca097f8d
|
@ -1 +1,2 @@
|
||||||
sineus-final.exe
|
sineus-final.exe
|
||||||
|
*.zip
|
||||||
|
|
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 278 B |
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 940 B |
74
game.odin
74
game.odin
|
@ -25,9 +25,35 @@ Game :: struct {
|
||||||
snake_max_health: int,
|
snake_max_health: int,
|
||||||
snake_health: int,
|
snake_health: int,
|
||||||
music: rl.Music,
|
music: rl.Music,
|
||||||
|
tutorial_enabled: bool,
|
||||||
|
tutorial_finished: bool,
|
||||||
|
tutorial_timer: f32,
|
||||||
|
tutorial_step: TutorSteps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TutorSteps :: enum {
|
||||||
|
THRUST,
|
||||||
|
LOOK,
|
||||||
|
SHOOT,
|
||||||
|
DODGE,
|
||||||
|
DONE
|
||||||
|
}
|
||||||
|
|
||||||
|
TutorTextsMouse := [TutorSteps]cstring{
|
||||||
|
.THRUST = "Используйте W/Ц для ускорения",
|
||||||
|
.LOOK = "Двигайте мышью для наведения",
|
||||||
|
.SHOOT = "Левая кнопка мыши: стрельба",
|
||||||
|
.DODGE = "Правая кнопка мыши: уклонение",
|
||||||
|
.DONE = "Удачи!"
|
||||||
|
}
|
||||||
|
|
||||||
|
TutorTextsKeyboard := [TutorSteps]cstring{
|
||||||
|
.THRUST = "Используйте стрелку \"Вверх\" для ускорения",
|
||||||
|
.LOOK = "Стрелки \"Влево\"/\"Вправо\" для наведения",
|
||||||
|
.SHOOT = "Пробел: стрельба",
|
||||||
|
.DODGE = "Shift: уклонение",
|
||||||
|
.DONE = "Удачи!"
|
||||||
|
}
|
||||||
|
|
||||||
game_init :: proc(prev: ^GameState = nil) -> ^GameState {
|
game_init :: proc(prev: ^GameState = nil) -> ^GameState {
|
||||||
state := new(Game)
|
state := new(Game)
|
||||||
|
@ -61,9 +87,7 @@ game_setup :: proc(game: ^Game) {
|
||||||
game.health = 100
|
game.health = 100
|
||||||
game.snake_max_health = 0
|
game.snake_max_health = 0
|
||||||
|
|
||||||
snake_spawn({10, 10, 0}, math.PI, 70)
|
snake_spawn({0, -10, 0}, math.PI * 3 / 2, 100)
|
||||||
|
|
||||||
|
|
||||||
for segment in Segments {
|
for segment in Segments {
|
||||||
game.snake_max_health += int(segment.health)
|
game.snake_max_health += int(segment.health)
|
||||||
}
|
}
|
||||||
|
@ -79,6 +103,8 @@ game_setup :: proc(game: ^Game) {
|
||||||
game.camera.target.x = clamp(game.camera.target.x, -GameField.x/2, GameField.x/2)
|
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.target.y = clamp(game.camera.target.y, 0, GameField.y)
|
||||||
game.camera.position = game.camera.target + vec3backward * 50
|
game.camera.position = game.camera.target + vec3backward * 50
|
||||||
|
|
||||||
|
game.tutorial_timer = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -89,6 +115,30 @@ game_gen_level :: proc(game: ^Game) {
|
||||||
game_update :: proc(state: ^GameState, delta: f32) {
|
game_update :: proc(state: ^GameState, delta: f32) {
|
||||||
game := transmute(^Game)state
|
game := transmute(^Game)state
|
||||||
using game
|
using game
|
||||||
|
tutorial_enabled = NeedTutorial && !tutorial_finished && player.intro_timer <= 0
|
||||||
|
if tutorial_enabled {
|
||||||
|
tutorial_timer -= delta
|
||||||
|
if tutorial_timer <= 0 {
|
||||||
|
tutorial_timer = 3
|
||||||
|
switch tutorial_step {
|
||||||
|
case .THRUST: tutorial_step = .LOOK
|
||||||
|
case .LOOK: tutorial_step = .SHOOT
|
||||||
|
case .SHOOT: tutorial_step = .DODGE
|
||||||
|
case .DODGE: tutorial_step = .DONE; tutorial_timer = 2
|
||||||
|
case .DONE:
|
||||||
|
tutorial_finished = true
|
||||||
|
NeedTutorial = false
|
||||||
|
SnakeActive = true
|
||||||
|
rl.PlaySound(Res.Sfx.SnakeRoarBlast)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if player.intro_timer <= 0 && !SnakeActive {
|
||||||
|
SnakeActive = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// if rl.IsMusicStreamPlaying(game.music) {
|
// if rl.IsMusicStreamPlaying(game.music) {
|
||||||
rl.UpdateMusicStream(game.music)
|
rl.UpdateMusicStream(game.music)
|
||||||
// }
|
// }
|
||||||
|
@ -153,8 +203,24 @@ game_draw :: proc(state: ^GameState) {
|
||||||
// hb_width := hb_health * WSize.x
|
// hb_width := hb_health * WSize.x
|
||||||
// rl.DrawRectangleV({WSize.x / 2 - hb_width / 2, WSize.y - height - 7}, {hb_width, height + 4}, rl.RED)
|
// rl.DrawRectangleV({WSize.x / 2 - hb_width / 2, WSize.y - height - 7}, {hb_width, height + 4}, rl.RED)
|
||||||
// draw_text_centered(Res.Fonts.Title, hb_text, {WSize.x / 2, WSize.y - height / 2}, height)
|
// draw_text_centered(Res.Fonts.Title, hb_text, {WSize.x / 2, WSize.y - height / 2}, height)
|
||||||
draw_hbar(hb_text, hb_health, {0, WSize.y - height}, {WSize.x, height}, rl.RED)
|
if SnakeActive {
|
||||||
|
draw_hbar(hb_text, hb_health, {0, WSize.y - height}, {WSize.x, height}, rl.RED)
|
||||||
|
}
|
||||||
draw_hbar("Þórr", f32(health) / 100.0, {0, 0}, {WSize.x, height}, rl.GREEN)
|
draw_hbar("Þórr", f32(health) / 100.0, {0, 0}, {WSize.x, height}, rl.GREEN)
|
||||||
|
reload_color := rl.SKYBLUE
|
||||||
|
if player.reloading {
|
||||||
|
reload_color = rl.RED
|
||||||
|
}
|
||||||
|
draw_hbar("", f32(player.power) / 100.0, {0, height}, {WSize.x, 10}, reload_color)
|
||||||
|
|
||||||
|
if tutorial_enabled {
|
||||||
|
texts := TutorTextsMouse
|
||||||
|
if KeyboardOnly {
|
||||||
|
texts = TutorTextsKeyboard
|
||||||
|
}
|
||||||
|
draw_text_centered(Res.Fonts.UI, texts[tutorial_step], WSize / 2 + vec2{0, 100}, 48, 1, rl.WHITE)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ gameover_draw :: proc(state: ^GameState) {
|
||||||
SubtitleFontSize :: 48
|
SubtitleFontSize :: 48
|
||||||
|
|
||||||
|
|
||||||
rl.DrawRectangleV(gameover.position - gameover.size / 2, gameover.size, rl.Color{90, 30, 150, 10})
|
// rl.DrawRectangleV(gameover.position - gameover.size / 2, gameover.size, rl.Color{90, 30, 150, 10})
|
||||||
|
|
||||||
draw_text_centered(Res.Fonts.Title, TitleText, gameover.position - {0, 100}, TitleFontSize, 1, rl.WHITE)
|
draw_text_centered(Res.Fonts.Title, TitleText, gameover.position - {0, 100}, TitleFontSize, 1, rl.WHITE)
|
||||||
for c, i in SubtitleText {
|
for c, i in SubtitleText {
|
||||||
|
|
32
main.odin
32
main.odin
|
@ -19,6 +19,9 @@ WSizei := [2]i32{}
|
||||||
|
|
||||||
WindowShouldExit := false
|
WindowShouldExit := false
|
||||||
|
|
||||||
|
NeedTutorial := true
|
||||||
|
KeyboardOnly := false
|
||||||
|
|
||||||
|
|
||||||
Overlay_Opacity : f32 = 0
|
Overlay_Opacity : f32 = 0
|
||||||
|
|
||||||
|
@ -58,7 +61,7 @@ Res : Resources
|
||||||
|
|
||||||
|
|
||||||
load_sfx :: proc(name: string, volume: f32 = 1) -> rl.Sound {
|
load_sfx :: proc(name: string, volume: f32 = 1) -> rl.Sound {
|
||||||
p := filepath.join([]string{".\\assets\\sfx\\", name})
|
p := filepath.join([]string{"./assets/sfx/", name})
|
||||||
cstr := strings.clone_to_cstring(p)
|
cstr := strings.clone_to_cstring(p)
|
||||||
snd := rl.LoadSound(cstr)
|
snd := rl.LoadSound(cstr)
|
||||||
rl.SetSoundVolume(snd, volume)
|
rl.SetSoundVolume(snd, volume)
|
||||||
|
@ -66,7 +69,7 @@ load_sfx :: proc(name: string, volume: f32 = 1) -> rl.Sound {
|
||||||
}
|
}
|
||||||
|
|
||||||
load_music :: proc(name: string, volume: f32 = 1) -> rl.Music {
|
load_music :: proc(name: string, volume: f32 = 1) -> rl.Music {
|
||||||
p := filepath.join([]string{".\\assets\\music\\", name})
|
p := filepath.join([]string{"./assets/music/", name})
|
||||||
cstr := strings.clone_to_cstring(p)
|
cstr := strings.clone_to_cstring(p)
|
||||||
snd := rl.LoadMusicStream(cstr)
|
snd := rl.LoadMusicStream(cstr)
|
||||||
rl.SetMusicVolume(snd, volume)
|
rl.SetMusicVolume(snd, volume)
|
||||||
|
@ -81,14 +84,15 @@ change_track :: proc(music: rl.Music) {
|
||||||
rl.PlayMusicStream(current_music)
|
rl.PlayMusicStream(current_music)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Cursor : rl.Texture
|
||||||
load_resources :: proc() {
|
load_resources :: proc() {
|
||||||
Res.Fonts.Title = rl.LoadFontEx(".\\assets\\fonts\\norse.otf", 96*2, nil, 2048)
|
Res.Fonts.Title = rl.LoadFontEx("./assets/fonts/norse.otf", 96*2, nil, 2048)
|
||||||
Res.Fonts.UI = rl.LoadFontEx(".\\assets\\fonts\\PTSerif-Regular.ttf", 96, nil, 2048)
|
Res.Fonts.UI = rl.LoadFontEx("./assets/fonts/PTSerif-Regular.ttf", 96, nil, 2048)
|
||||||
|
|
||||||
Res.Models.PlayerModel = rl.LoadModel(".\\assets\\models\\chariot.glb")
|
Res.Models.PlayerModel = rl.LoadModel("./assets/models/chariot.glb")
|
||||||
Res.Models.SnakeHeadTop = rl.LoadModel(".\\assets\\models\\snake_head_top.obj")
|
Res.Models.SnakeHeadTop = rl.LoadModel("./assets/models/snake_head_top.obj")
|
||||||
Res.Models.SnakeHeadJaw = rl.LoadModel(".\\assets\\models\\snake_jaw.obj")
|
Res.Models.SnakeHeadJaw = rl.LoadModel("./assets/models/snake_jaw.obj")
|
||||||
Res.Models.SnakeBody = rl.LoadModel(".\\assets\\models\\snake_body.obj")
|
Res.Models.SnakeBody = rl.LoadModel("./assets/models/snake_body.obj")
|
||||||
|
|
||||||
Res.Sfx.Drums = load_sfx("drums.ogg")
|
Res.Sfx.Drums = load_sfx("drums.ogg")
|
||||||
Res.Sfx.Lightning = load_sfx("lightning.ogg", 0.5)
|
Res.Sfx.Lightning = load_sfx("lightning.ogg", 0.5)
|
||||||
|
@ -107,11 +111,17 @@ load_resources :: proc() {
|
||||||
Res.Music.Second = load_music("alexander-nakarada-the-northern-path.mp3", 0.7)
|
Res.Music.Second = load_music("alexander-nakarada-the-northern-path.mp3", 0.7)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Fullscreen := true
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
rl.SetConfigFlags(rl.ConfigFlags{.MSAA_4X_HINT, .WINDOW_MAXIMIZED, .WINDOW_RESIZABLE})
|
rl.SetConfigFlags(rl.ConfigFlags{.MSAA_4X_HINT, .FULLSCREEN_MODE, .VSYNC_HINT, .WINDOW_RESIZABLE})
|
||||||
rl.InitWindow(800, 480, "Ragnarøkkr")
|
rl.SetWindowMinSize(800, 480)
|
||||||
|
|
||||||
|
rl.InitWindow(0, 0, "Ragnarøkkr")
|
||||||
rl.InitAudioDevice()
|
rl.InitAudioDevice()
|
||||||
|
|
||||||
|
rl.HideCursor()
|
||||||
|
Cursor = rl.LoadTexture("./assets/gfx/crosshair.png")
|
||||||
load_resources()
|
load_resources()
|
||||||
|
|
||||||
WSizei = {rl.GetScreenWidth(), rl.GetScreenHeight()}
|
WSizei = {rl.GetScreenWidth(), rl.GetScreenHeight()}
|
||||||
|
@ -141,6 +151,8 @@ main :: proc() {
|
||||||
state->draw()
|
state->draw()
|
||||||
|
|
||||||
rl.DrawRectangleV({}, WSize, rl.Color{0, 0, 0, u8(Overlay_Opacity * 255)})
|
rl.DrawRectangleV({}, WSize, rl.Color{0, 0, 0, u8(Overlay_Opacity * 255)})
|
||||||
|
pos := rl.GetMousePosition()
|
||||||
|
rl.DrawTextureEx(Cursor, pos - {16, 16} * 3, 0, 3, rl.WHITE)
|
||||||
rl.EndDrawing()
|
rl.EndDrawing()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
32
menu.odin
32
menu.odin
|
@ -6,16 +6,28 @@ import "core:math/ease"
|
||||||
|
|
||||||
Menu_Buttons :: enum {
|
Menu_Buttons :: enum {
|
||||||
START,
|
START,
|
||||||
HOW_TO_PLAY,
|
TUTORIAL,
|
||||||
|
KEYBOARD_ONLY,
|
||||||
|
FULLSCREEN,
|
||||||
EXIT
|
EXIT
|
||||||
}
|
}
|
||||||
|
|
||||||
menu_strings := [Menu_Buttons]cstring {
|
menu_strings := [Menu_Buttons]cstring {
|
||||||
.START = "Старт",
|
.START = "Старт",
|
||||||
.HOW_TO_PLAY = "Как играть?",
|
.TUTORIAL = "Обучение",
|
||||||
|
.KEYBOARD_ONLY = "Только клавиатура",
|
||||||
|
.FULLSCREEN = "Полный экран",
|
||||||
.EXIT = "Выход"
|
.EXIT = "Выход"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
menu_items := [Menu_Buttons]MenuItem {
|
||||||
|
.START = {text = menu_strings[.START]},
|
||||||
|
.TUTORIAL = {text = menu_strings[.TUTORIAL], param = &NeedTutorial, type = MenuItemType.BOOL},
|
||||||
|
.KEYBOARD_ONLY = {text = menu_strings[.KEYBOARD_ONLY], param = &KeyboardOnly, type = MenuItemType.BOOL},
|
||||||
|
.FULLSCREEN = {text = menu_strings[.FULLSCREEN], param = &Fullscreen, type = MenuItemType.BOOL},
|
||||||
|
.EXIT = {text = menu_strings[.EXIT]}
|
||||||
|
}
|
||||||
|
|
||||||
Menu :: struct {
|
Menu :: struct {
|
||||||
using state: GameState,
|
using state: GameState,
|
||||||
|
|
||||||
|
@ -31,9 +43,9 @@ menu_init :: proc(prev: ^GameState = nil) -> ^GameState {
|
||||||
position = {100, WSize.y / 2},
|
position = {100, WSize.y / 2},
|
||||||
line_size = 60,
|
line_size = 60,
|
||||||
font_size = 48,
|
font_size = 48,
|
||||||
elements = &menu_strings,
|
elements = &menu_items,
|
||||||
menu_pressed = menu_button_pressed,
|
menu_pressed = menu_button_pressed,
|
||||||
background = rl.Color{50, 10, 110, 10}
|
background = rl.Color{50, 10, 110, 0}
|
||||||
}
|
}
|
||||||
state.update = menu_update
|
state.update = menu_update
|
||||||
state.draw = menu_draw
|
state.draw = menu_draw
|
||||||
|
@ -56,9 +68,15 @@ menu_button_pressed :: proc(state: ^GameState, el: Menu_Buttons) {
|
||||||
game := transmute(^Game)state.previous
|
game := transmute(^Game)state.previous
|
||||||
change_track(Res.Music.First)
|
change_track(Res.Music.First)
|
||||||
stack_pop()
|
stack_pop()
|
||||||
case .HOW_TO_PLAY:
|
case .TUTORIAL:
|
||||||
// howtoplay := howtoplay_init(state)
|
NeedTutorial = !NeedTutorial
|
||||||
// stack_push(howtoplay)
|
case .KEYBOARD_ONLY:
|
||||||
|
KeyboardOnly = !KeyboardOnly
|
||||||
|
NeedTutorial = true
|
||||||
|
case .FULLSCREEN:
|
||||||
|
rl.ToggleFullscreen()
|
||||||
|
Fullscreen = rl.IsWindowFullscreen()
|
||||||
|
|
||||||
case .EXIT:
|
case .EXIT:
|
||||||
WindowShouldExit = true
|
WindowShouldExit = true
|
||||||
return
|
return
|
||||||
|
|
|
@ -4,6 +4,23 @@ import rl "vendor:raylib"
|
||||||
import "core:math/ease"
|
import "core:math/ease"
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
|
MenuItemType :: enum {
|
||||||
|
NONE,
|
||||||
|
BOOL,
|
||||||
|
INT,
|
||||||
|
}
|
||||||
|
|
||||||
|
BoolStrings := map[bool]cstring {
|
||||||
|
true = "вкл",
|
||||||
|
false = "выкл"
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem :: struct{
|
||||||
|
text: cstring,
|
||||||
|
param: rawptr,
|
||||||
|
type: MenuItemType,
|
||||||
|
}
|
||||||
|
|
||||||
MenuList :: struct($T: typeid) {
|
MenuList :: struct($T: typeid) {
|
||||||
state: ^GameState,
|
state: ^GameState,
|
||||||
position: vec2,
|
position: vec2,
|
||||||
|
@ -12,7 +29,7 @@ MenuList :: struct($T: typeid) {
|
||||||
active_element: T,
|
active_element: T,
|
||||||
active_marker: vec2,
|
active_marker: vec2,
|
||||||
tween: ^Tween,
|
tween: ^Tween,
|
||||||
elements: ^[T]cstring,
|
elements: ^[T]MenuItem,
|
||||||
menu_pressed: proc(state: ^GameState, element: T),
|
menu_pressed: proc(state: ^GameState, element: T),
|
||||||
background: rl.Color,
|
background: rl.Color,
|
||||||
mouse_pos: vec2,
|
mouse_pos: vec2,
|
||||||
|
@ -80,7 +97,13 @@ menu_list_draw :: proc(list: ^MenuList($T)) {
|
||||||
rl.DrawTextEx(Res.Fonts.UI, ">", list.position + list.active_marker + {-30, 0}, 48, 2, rl.WHITE)
|
rl.DrawTextEx(Res.Fonts.UI, ">", list.position + list.active_marker + {-30, 0}, 48, 2, rl.WHITE)
|
||||||
for el, i in list.elements {
|
for el, i in list.elements {
|
||||||
pos := list.position + {0, f32(i) * list.line_size}
|
pos := list.position + {0, f32(i) * list.line_size}
|
||||||
rl.DrawTextEx(Res.Fonts.UI, el, pos, list.font_size, 2, rl.WHITE)
|
text := el.text
|
||||||
|
if el.type == .BOOL {
|
||||||
|
param := transmute(^bool)el.param
|
||||||
|
value := param^
|
||||||
|
text = rl.TextFormat("%s: %s", el.text, BoolStrings[value])
|
||||||
|
}
|
||||||
|
rl.DrawTextEx(Res.Fonts.UI, text, pos, list.font_size, 2, rl.WHITE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +111,7 @@ menu_list_draw :: proc(list: ^MenuList($T)) {
|
||||||
menu_list_get_size :: proc(list: ^MenuList($T)) -> vec2 {
|
menu_list_get_size :: proc(list: ^MenuList($T)) -> vec2 {
|
||||||
size := vec2{}
|
size := vec2{}
|
||||||
for el, i in list.elements {
|
for el, i in list.elements {
|
||||||
line_size := rl.MeasureTextEx(Res.Fonts.UI, el, list.font_size, 2)
|
line_size := rl.MeasureTextEx(Res.Fonts.UI, el.text, list.font_size, 2)
|
||||||
if line_size.x > size.x {
|
if line_size.x > size.x {
|
||||||
size.x = line_size.x
|
size.x = line_size.x
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,11 @@ pause_strings := [Pause_Buttons]cstring {
|
||||||
.EXIT = "Прервать игру"
|
.EXIT = "Прервать игру"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pause_items := [Pause_Buttons]MenuItem {
|
||||||
|
.CONTINUE = {text = pause_strings[.CONTINUE]},
|
||||||
|
.EXIT = {text = pause_strings[.EXIT]}
|
||||||
|
}
|
||||||
|
|
||||||
Pause :: struct {
|
Pause :: struct {
|
||||||
using state: GameState,
|
using state: GameState,
|
||||||
|
|
||||||
|
@ -30,9 +35,9 @@ pause_init :: proc(prev: ^GameState = nil) -> ^GameState {
|
||||||
position = {-300, WSize.y / 2},
|
position = {-300, WSize.y / 2},
|
||||||
line_size = 60,
|
line_size = 60,
|
||||||
font_size = 48,
|
font_size = 48,
|
||||||
elements = &pause_strings,
|
elements = &pause_items,
|
||||||
menu_pressed = pause_button_pressed,
|
menu_pressed = pause_button_pressed,
|
||||||
background = rl.Color{50, 10, 110, 10}
|
background = rl.Color{50, 10, 110, 0}
|
||||||
}
|
}
|
||||||
state.update = pause_update
|
state.update = pause_update
|
||||||
state.draw = pause_draw
|
state.draw = pause_draw
|
||||||
|
|
58
player.odin
58
player.odin
|
@ -29,6 +29,9 @@ Player :: struct {
|
||||||
is_invulnerable: bool,
|
is_invulnerable: bool,
|
||||||
is_dead: bool,
|
is_dead: bool,
|
||||||
intro_timer: f32,
|
intro_timer: f32,
|
||||||
|
power: f32,
|
||||||
|
reload_timer: f32,
|
||||||
|
reloading: bool,
|
||||||
// animation: rl.ModelAnimation,
|
// animation: rl.ModelAnimation,
|
||||||
// animTime: f32,
|
// animTime: f32,
|
||||||
// animFrame: i32,
|
// animFrame: i32,
|
||||||
|
@ -47,6 +50,7 @@ player_spawn :: proc(position: vec3) -> Player {
|
||||||
can_dodge = true,
|
can_dodge = true,
|
||||||
can_shoot = true,
|
can_shoot = true,
|
||||||
intro_timer = 2,
|
intro_timer = 2,
|
||||||
|
power = 100,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,16 +86,26 @@ player_update :: proc(player: ^Player, game: ^Game, delta: f32) {
|
||||||
if !is_dodging {
|
if !is_dodging {
|
||||||
dir_vector : vec3
|
dir_vector : vec3
|
||||||
if intro_timer <= 0 {
|
if intro_timer <= 0 {
|
||||||
dir = angle_rotate(dir, mouse_angle, math.PI * 2 * delta)
|
thrust_key := rl.KeyboardKey.W
|
||||||
dir_vector = get_vec_from_angle(dir)
|
if !KeyboardOnly {
|
||||||
|
dir = angle_rotate(dir, mouse_angle, math.PI * 2 * delta)
|
||||||
|
dir_vector = get_vec_from_angle(dir)
|
||||||
|
} else {
|
||||||
|
thrust_key = rl.KeyboardKey.UP
|
||||||
|
if rl.IsKeyDown(rl.KeyboardKey.LEFT) {
|
||||||
|
dir += math.PI * 2 * delta
|
||||||
|
}
|
||||||
|
if rl.IsKeyDown(rl.KeyboardKey.RIGHT) {
|
||||||
|
dir -= math.PI * 2 * delta
|
||||||
|
}
|
||||||
|
dir_vector = get_vec_from_angle(dir)
|
||||||
|
}
|
||||||
thrust = 0
|
thrust = 0
|
||||||
|
if rl.IsKeyDown(thrust_key) {
|
||||||
if rl.IsKeyDown(rl.KeyboardKey.W) {
|
thrust = 110
|
||||||
thrust = 70
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
thrust = 70
|
thrust = 110
|
||||||
dir_vector = vec3left
|
dir_vector = vec3left
|
||||||
dir = math.atan2(-dir_vector.y, dir_vector.x)
|
dir = math.atan2(-dir_vector.y, dir_vector.x)
|
||||||
}
|
}
|
||||||
|
@ -115,7 +129,17 @@ player_update :: proc(player: ^Player, game: ^Game, delta: f32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if rl.IsMouseButtonPressed(rl.MouseButton.RIGHT) && can_dodge && intro_timer <= 0 {
|
dodge := false
|
||||||
|
shoot := false
|
||||||
|
if KeyboardOnly {
|
||||||
|
dodge = rl.IsKeyPressed(rl.KeyboardKey.LEFT_SHIFT)
|
||||||
|
shoot = rl.IsKeyDown(rl.KeyboardKey.SPACE)
|
||||||
|
} else {
|
||||||
|
dodge = rl.IsMouseButtonPressed(rl.MouseButton.RIGHT)
|
||||||
|
shoot = rl.IsMouseButtonDown(rl.MouseButton.LEFT)
|
||||||
|
}
|
||||||
|
|
||||||
|
if dodge && can_dodge && intro_timer <= 0 {
|
||||||
is_dodging = true
|
is_dodging = true
|
||||||
can_dodge = false
|
can_dodge = false
|
||||||
rl.StopSound(Res.Sfx.Rocket)
|
rl.StopSound(Res.Sfx.Rocket)
|
||||||
|
@ -136,7 +160,7 @@ player_update :: proc(player: ^Player, game: ^Game, delta: f32) {
|
||||||
// player.animTime += delta
|
// player.animTime += delta
|
||||||
// player.animFrame = i32(player.animTime * 60) % player.animation.frameCount
|
// player.animFrame = i32(player.animTime * 60) % player.animation.frameCount
|
||||||
// rl.UpdateModelAnimation(PlayerModel, player.animation, player.animFrame)
|
// rl.UpdateModelAnimation(PlayerModel, player.animation, player.animFrame)
|
||||||
shooting := rl.IsMouseButtonDown(rl.MouseButton.LEFT) && !is_dodging && intro_timer <= 0
|
shooting := shoot && !is_dodging && intro_timer <= 0 && !reloading
|
||||||
if shooting {
|
if shooting {
|
||||||
if !rl.IsSoundPlaying(Res.Sfx.Lightning) {
|
if !rl.IsSoundPlaying(Res.Sfx.Lightning) {
|
||||||
rl.PlaySound(Res.Sfx.Lightning)
|
rl.PlaySound(Res.Sfx.Lightning)
|
||||||
|
@ -150,10 +174,26 @@ player_update :: proc(player: ^Player, game: ^Game, delta: f32) {
|
||||||
player := transmute(^Player)data
|
player := transmute(^Player)data
|
||||||
player.can_shoot = true
|
player.can_shoot = true
|
||||||
})
|
})
|
||||||
|
player.power -= 2
|
||||||
|
player.reload_timer = 1
|
||||||
|
if player.power <= 0 {
|
||||||
|
player.reloading = true
|
||||||
|
player.power = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rl.StopSound(Res.Sfx.Lightning)
|
rl.StopSound(Res.Sfx.Lightning)
|
||||||
}
|
}
|
||||||
|
if !shooting && can_shoot {
|
||||||
|
reload_timer -= delta
|
||||||
|
if reload_timer <= 0 {
|
||||||
|
player.power += 20 * delta
|
||||||
|
if player.power > 100 {
|
||||||
|
player.power = 100
|
||||||
|
player.reloading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
got_hit := false
|
got_hit := false
|
||||||
|
|
19
snake.odin
19
snake.odin
|
@ -52,19 +52,22 @@ SnakeSegment :: struct {
|
||||||
prev: ^SnakeSegment
|
prev: ^SnakeSegment
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SnakeActive := false
|
||||||
|
|
||||||
snake_spawn :: proc(pos: vec3, dir: f32, length: int){
|
snake_spawn :: proc(pos: vec3, dir: f32, length: int){
|
||||||
dir_vec := rl.Vector3RotateByAxisAngle(vec3right, vec3backward, dir)
|
// dir_vec := rl.Vector3RotateByAxisAngle(vec3right, vec3backward, dir)
|
||||||
|
dir_vec := vec3down
|
||||||
|
direction := math.atan2(-dir_vec.y, dir_vec.x)
|
||||||
|
SnakeActive = false
|
||||||
Head = SnakeHead{
|
Head = SnakeHead{
|
||||||
pos = pos,
|
pos = pos,
|
||||||
dir = dir,
|
dir = dir,
|
||||||
radius = 3,
|
radius = 3,
|
||||||
state = .Chasing,
|
state = .Diving,
|
||||||
vel = dir_vec * 20,
|
vel = dir_vec * 20,
|
||||||
health = 100,
|
health = 100,
|
||||||
max_health = 100,
|
max_health = 100,
|
||||||
state_timer = 30,
|
state_timer = 15,
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < length; i += 1 {
|
for i := 0; i < length; i += 1 {
|
||||||
|
@ -93,6 +96,9 @@ snake_clear :: proc() {
|
||||||
}
|
}
|
||||||
|
|
||||||
snake_process :: proc(game: ^Game, delta: f32) {
|
snake_process :: proc(game: ^Game, delta: f32) {
|
||||||
|
if !SnakeActive || Head.is_dead{
|
||||||
|
return
|
||||||
|
}
|
||||||
// Head.state = .Shot
|
// Head.state = .Shot
|
||||||
// Head.state_timer = 200
|
// Head.state_timer = 200
|
||||||
switch Head.state {
|
switch Head.state {
|
||||||
|
@ -124,6 +130,7 @@ snake_process :: proc(game: ^Game, delta: f32) {
|
||||||
if Head.health <= 0 && !Head.is_dead {
|
if Head.health <= 0 && !Head.is_dead {
|
||||||
Head.is_dead = true
|
Head.is_dead = true
|
||||||
explode(Head.pos, 9, 0.9, rl.YELLOW)
|
explode(Head.pos, 9, 0.9, rl.YELLOW)
|
||||||
|
rl.StopMusicStream(current_music)
|
||||||
rl.PlaySound(Res.Sfx.PlayerDead)
|
rl.PlaySound(Res.Sfx.PlayerDead)
|
||||||
timer_start(3, game, proc(data: rawptr) {
|
timer_start(3, game, proc(data: rawptr) {
|
||||||
state := transmute(^Game)data
|
state := transmute(^Game)data
|
||||||
|
@ -274,7 +281,9 @@ snake_shot :: proc(game: ^Game, delta: f32) {
|
||||||
|
|
||||||
|
|
||||||
snake_draw :: proc(game: ^Game) {
|
snake_draw :: proc(game: ^Game) {
|
||||||
|
if !SnakeActive || Head.is_dead {
|
||||||
|
return
|
||||||
|
}
|
||||||
dir_vector := get_vec_from_angle(Head.dir)
|
dir_vector := get_vec_from_angle(Head.dir)
|
||||||
roll := -math.PI / 2 + math.cos(Head.dir) * math.PI / 2
|
roll := -math.PI / 2 + math.cos(Head.dir) * math.PI / 2
|
||||||
rlgl.PushMatrix()
|
rlgl.PushMatrix()
|
||||||
|
|
Loading…
Reference in New Issue