Moved tweens to NTween
This commit is contained in:
parent
8a9e20f370
commit
b251553275
BIN
Ragnarokkr
BIN
Ragnarokkr
Binary file not shown.
|
@ -1,14 +1,15 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import rl "vendor:raylib"
|
|
||||||
import "core:math/ease"
|
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
import "core:math/ease"
|
||||||
|
import "ntween"
|
||||||
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
|
|
||||||
GameOver :: struct {
|
GameOver :: struct {
|
||||||
using state: GameState,
|
using state: GameState,
|
||||||
position: vec2,
|
position: vec2,
|
||||||
size: vec2,
|
size: vec2,
|
||||||
ready_to_go: bool,
|
ready_to_go: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +23,15 @@ gameover_init :: proc(prev: ^GameState = nil) -> ^GameState {
|
||||||
state.free = gameover_free
|
state.free = gameover_free
|
||||||
|
|
||||||
state.previous = prev
|
state.previous = prev
|
||||||
tween_to(&state.position.y, WSize.y / 2, 1, ease.Ease.Back_Out, state, gameover_ready)
|
ntween.animate(
|
||||||
|
&vec2_tweens,
|
||||||
|
&state.position,
|
||||||
|
WSize / 2,
|
||||||
|
1,
|
||||||
|
ease.Ease.Back_Out,
|
||||||
|
state,
|
||||||
|
gameover_ready,
|
||||||
|
)
|
||||||
|
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
@ -33,16 +42,24 @@ gameover_update :: proc(state: ^GameState, delta: f32) {
|
||||||
if rl.IsKeyPressed(rl.KeyboardKey.ESCAPE) {
|
if rl.IsKeyPressed(rl.KeyboardKey.ESCAPE) {
|
||||||
gameover.ready_to_go = false
|
gameover.ready_to_go = false
|
||||||
rl.StopMusicStream(current_music)
|
rl.StopMusicStream(current_music)
|
||||||
tween_to(&Overlay_Opacity, 1.0, 0.5, ease.Ease.Cubic_Out, state, proc(data: rawptr) {
|
ntween.animate(
|
||||||
state := transmute(^GameState)data
|
&f32_tweens,
|
||||||
stack_pop()
|
&Overlay_Opacity,
|
||||||
game := transmute(^Game)state.previous
|
1.0,
|
||||||
game_setup(game)
|
0.5,
|
||||||
menu := menu_init(game)
|
ease.Ease.Cubic_Out,
|
||||||
stack_push(menu)
|
state,
|
||||||
free(state)
|
proc(data: rawptr) {
|
||||||
tween_to(&Overlay_Opacity, 0, 0.5, ease.Ease.Cubic_Out)
|
state := transmute(^GameState)data
|
||||||
})
|
stack_pop()
|
||||||
|
game := transmute(^Game)state.previous
|
||||||
|
game_setup(game)
|
||||||
|
menu := menu_init(game)
|
||||||
|
stack_push(menu)
|
||||||
|
free(state)
|
||||||
|
ntween.animate(&f32_tweens, &Overlay_Opacity, 0, 0.5, ease.Ease.Cubic_Out)
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,9 +83,23 @@ gameover_draw :: proc(state: ^GameState) {
|
||||||
|
|
||||||
// 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 {
|
||||||
draw_text_centered(Res.Fonts.UI, c, gameover.position - {0, f32(10 - i * 50)}, SubtitleFontSize, 1, rl.WHITE)
|
draw_text_centered(
|
||||||
|
Res.Fonts.UI,
|
||||||
|
c,
|
||||||
|
gameover.position - {0, f32(10 - i * 50)},
|
||||||
|
SubtitleFontSize,
|
||||||
|
1,
|
||||||
|
rl.WHITE,
|
||||||
|
)
|
||||||
// rl.DrawTextPro(Res.Fonts.UI, c, winning.position - {0, f32(10 - i * 50)}, SubtitleSizes[i] / 2, 0, SubtitleFontSize, SubtitleSpacing, rl.WHITE)
|
// rl.DrawTextPro(Res.Fonts.UI, c, winning.position - {0, f32(10 - i * 50)}, SubtitleSizes[i] / 2, 0, SubtitleFontSize, SubtitleSpacing, rl.WHITE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
218
main.odin
218
main.odin
|
@ -1,9 +1,10 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import rl "vendor:raylib"
|
import "core:fmt"
|
||||||
import "core:path/filepath"
|
import "core:path/filepath"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
import "core:fmt"
|
import "ntween"
|
||||||
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
vec3 :: [3]f32
|
vec3 :: [3]f32
|
||||||
vec3i :: [3]i32
|
vec3i :: [3]i32
|
||||||
|
@ -28,49 +29,49 @@ NeedTutorial := true
|
||||||
KeyboardOnly := false
|
KeyboardOnly := false
|
||||||
|
|
||||||
|
|
||||||
Overlay_Opacity : f32 = 0
|
Overlay_Opacity: f32 = 0
|
||||||
|
|
||||||
Resources :: struct {
|
Resources :: struct {
|
||||||
Fonts: struct {
|
Fonts: struct {
|
||||||
UI: rl.Font,
|
UI: rl.Font,
|
||||||
Title: rl.Font,
|
Title: rl.Font,
|
||||||
},
|
},
|
||||||
Models: struct {
|
Models: struct {
|
||||||
PlayerModel: rl.Model,
|
PlayerModel: rl.Model,
|
||||||
SnakeHeadTop: rl.Model,
|
SnakeHeadTop: rl.Model,
|
||||||
SnakeHeadJaw: rl.Model,
|
SnakeHeadJaw: rl.Model,
|
||||||
SnakeBody: rl.Model,
|
SnakeBody: rl.Model,
|
||||||
Background: rl.Model,
|
Background: rl.Model,
|
||||||
},
|
},
|
||||||
Sfx: struct {
|
Sfx: struct {
|
||||||
Drums: rl.Sound,
|
Drums: rl.Sound,
|
||||||
Lightning: rl.Sound,
|
Lightning: rl.Sound,
|
||||||
LightningHit: rl.Sound,
|
LightningHit: rl.Sound,
|
||||||
Rocket: rl.Sound,
|
Rocket: rl.Sound,
|
||||||
PlayerHit: rl.Sound,
|
PlayerHit: rl.Sound,
|
||||||
PlayerSwoosh: rl.Sound,
|
PlayerSwoosh: rl.Sound,
|
||||||
PlayerDead: rl.Sound,
|
PlayerDead: rl.Sound,
|
||||||
SnakeGrowl: rl.Sound,
|
SnakeGrowl: rl.Sound,
|
||||||
SnakeRoarBlast: rl.Sound,
|
SnakeRoarBlast: rl.Sound,
|
||||||
SnakeEarthHit: rl.Sound,
|
SnakeEarthHit: rl.Sound,
|
||||||
SnakeSegmentExplode: rl.Sound,
|
SnakeSegmentExplode: rl.Sound,
|
||||||
SnakeBeam: rl.Sound,
|
SnakeBeam: rl.Sound,
|
||||||
},
|
},
|
||||||
Music: struct {
|
Music: struct {
|
||||||
First: rl.Music,
|
First: rl.Music,
|
||||||
Second: rl.Music,
|
Second: rl.Music,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
Res : Resources
|
Res: Resources
|
||||||
|
|
||||||
res_paths := map[typeid]string{
|
res_paths := map[typeid]string {
|
||||||
rl.Music = "music",
|
rl.Music = "music",
|
||||||
rl.Sound = "sfx",
|
rl.Sound = "sfx",
|
||||||
rl.Model = "models",
|
rl.Model = "models",
|
||||||
}
|
}
|
||||||
|
|
||||||
get_path :: proc(name: string, $T: typeid) -> cstring{
|
get_path :: proc(name: string, $T: typeid) -> cstring {
|
||||||
p := filepath.join([]string{"./assets", res_paths[T], name})
|
p := filepath.join([]string{"./assets", res_paths[T], name})
|
||||||
cstr := strings.clone_to_cstring(p)
|
cstr := strings.clone_to_cstring(p)
|
||||||
return cstr
|
return cstr
|
||||||
|
@ -84,101 +85,110 @@ load_model :: proc(name: string) -> rl.Model {
|
||||||
|
|
||||||
load_sfx :: proc(name: string, volume: f32 = 1) -> rl.Sound {
|
load_sfx :: proc(name: string, volume: f32 = 1) -> rl.Sound {
|
||||||
p := get_path(name, rl.Sound)
|
p := get_path(name, rl.Sound)
|
||||||
snd := rl.LoadSound(p)
|
snd := rl.LoadSound(p)
|
||||||
rl.SetSoundVolume(snd, volume)
|
rl.SetSoundVolume(snd, volume)
|
||||||
return snd
|
return snd
|
||||||
}
|
}
|
||||||
|
|
||||||
load_music :: proc(name: string, volume: f32 = 1) -> rl.Music {
|
load_music :: proc(name: string, volume: f32 = 1) -> rl.Music {
|
||||||
p := get_path(name, rl.Music)
|
p := get_path(name, rl.Music)
|
||||||
snd := rl.LoadMusicStream(p)
|
snd := rl.LoadMusicStream(p)
|
||||||
rl.SetMusicVolume(snd, volume)
|
rl.SetMusicVolume(snd, volume)
|
||||||
return snd
|
return snd
|
||||||
}
|
}
|
||||||
|
|
||||||
current_music : rl.Music
|
current_music: rl.Music
|
||||||
|
|
||||||
change_track :: proc(music: rl.Music) {
|
change_track :: proc(music: rl.Music) {
|
||||||
rl.StopMusicStream(current_music)
|
rl.StopMusicStream(current_music)
|
||||||
current_music = music
|
current_music = music
|
||||||
rl.PlayMusicStream(current_music)
|
rl.PlayMusicStream(current_music)
|
||||||
}
|
}
|
||||||
|
|
||||||
Cursor : rl.Texture
|
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 = {
|
Res.Models = {
|
||||||
PlayerModel = load_model("chariot.glb"),
|
PlayerModel = load_model("chariot.glb"),
|
||||||
SnakeHeadTop = load_model("snake_head_top.obj"),
|
SnakeHeadTop = load_model("snake_head_top.obj"),
|
||||||
SnakeHeadJaw = load_model("snake_jaw.obj"),
|
SnakeHeadJaw = load_model("snake_jaw.obj"),
|
||||||
SnakeBody = load_model("snake_body.obj"),
|
SnakeBody = load_model("snake_body.obj"),
|
||||||
Background = load_model("background.obj"),
|
Background = load_model("background.obj"),
|
||||||
}
|
}
|
||||||
|
|
||||||
Res.Sfx = {
|
Res.Sfx = {
|
||||||
Drums = load_sfx("drums.ogg"),
|
Drums = load_sfx("drums.ogg"),
|
||||||
Lightning = load_sfx("lightning.ogg", 0.5),
|
Lightning = load_sfx("lightning.ogg", 0.5),
|
||||||
LightningHit = load_sfx("lightning-hit.ogg", 0.3),
|
LightningHit = load_sfx("lightning-hit.ogg", 0.3),
|
||||||
Rocket = load_sfx("rocket.ogg", 0.5),
|
Rocket = load_sfx("rocket.ogg", 0.5),
|
||||||
PlayerHit = load_sfx("player-hit.ogg", 0.5),
|
PlayerHit = load_sfx("player-hit.ogg", 0.5),
|
||||||
PlayerSwoosh = load_sfx("player-swoosh.ogg"),
|
PlayerSwoosh = load_sfx("player-swoosh.ogg"),
|
||||||
PlayerDead = load_sfx("player-dead.ogg"),
|
PlayerDead = load_sfx("player-dead.ogg"),
|
||||||
SnakeGrowl = load_sfx("snake-growl.ogg", 0.7),
|
SnakeGrowl = load_sfx("snake-growl.ogg", 0.7),
|
||||||
SnakeRoarBlast = load_sfx("snake-roar-blast.ogg", 0.8),
|
SnakeRoarBlast = load_sfx("snake-roar-blast.ogg", 0.8),
|
||||||
SnakeBeam = load_sfx("snake-beam.ogg"),
|
SnakeBeam = load_sfx("snake-beam.ogg"),
|
||||||
SnakeSegmentExplode = load_sfx("snake-segment-explode.ogg", 0.8),
|
SnakeSegmentExplode = load_sfx("snake-segment-explode.ogg", 0.8),
|
||||||
SnakeEarthHit = load_sfx("snake-earth-hit.ogg", 0.6),
|
SnakeEarthHit = load_sfx("snake-earth-hit.ogg", 0.6),
|
||||||
}
|
}
|
||||||
|
|
||||||
Res.Music.First = load_music("alexander-nakarada-mjolnir.mp3", 0.7)
|
Res.Music.First = load_music("alexander-nakarada-mjolnir.mp3", 0.7)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f32_tweens: ntween.Tween_Map(f32)
|
||||||
|
vec2_tweens: ntween.Tween_Map(vec2)
|
||||||
|
vec3_tweens: ntween.Tween_Map(vec3)
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
// rl.SetConfigFlags(rl.ConfigFlags{.MSAA_4X_HINT, .FULLSCREEN_MODE, .VSYNC_HINT, .WINDOW_RESIZABLE})
|
f32_tweens = ntween.init(f32)
|
||||||
rl.SetConfigFlags(rl.ConfigFlags{.VSYNC_HINT, .WINDOW_RESIZABLE})
|
vec2_tweens = ntween.init(vec2)
|
||||||
|
vec3_tweens = ntween.init(vec3)
|
||||||
|
// rl.SetConfigFlags(rl.ConfigFlags{.MSAA_4X_HINT, .FULLSCREEN_MODE, .VSYNC_HINT, .WINDOW_RESIZABLE})
|
||||||
|
rl.SetConfigFlags(rl.ConfigFlags{.VSYNC_HINT, .WINDOW_RESIZABLE})
|
||||||
|
|
||||||
rl.InitWindow(800, 600, "Ragnarøkkr")
|
rl.InitWindow(800, 600, "Ragnarøkkr")
|
||||||
rl.InitAudioDevice()
|
rl.InitAudioDevice()
|
||||||
rl.SetWindowMinSize(800, 600)
|
rl.SetWindowMinSize(800, 600)
|
||||||
|
|
||||||
rl.HideCursor()
|
rl.HideCursor()
|
||||||
Cursor = rl.LoadTexture("./assets/gfx/crosshair.png")
|
Cursor = rl.LoadTexture("./assets/gfx/crosshair.png")
|
||||||
load_resources()
|
load_resources()
|
||||||
|
|
||||||
WSizei = {rl.GetScreenWidth(), rl.GetScreenHeight()}
|
WSizei = {rl.GetScreenWidth(), rl.GetScreenHeight()}
|
||||||
WSize = {f32(WSizei.x), f32(WSizei.y)}
|
WSize = {f32(WSizei.x), f32(WSizei.y)}
|
||||||
|
|
||||||
game := game_init()
|
game := game_init()
|
||||||
stack_push(game)
|
stack_push(game)
|
||||||
menu := menu_init(game)
|
menu := menu_init(game)
|
||||||
stack_push(menu)
|
stack_push(menu)
|
||||||
|
|
||||||
for !WindowShouldExit {
|
for !WindowShouldExit {
|
||||||
if rl.IsWindowResized() {
|
if rl.IsWindowResized() {
|
||||||
WSizei = {rl.GetScreenWidth(), rl.GetScreenHeight()}
|
WSizei = {rl.GetScreenWidth(), rl.GetScreenHeight()}
|
||||||
WSize = {f32(WSizei.x), f32(WSizei.y)}
|
WSize = {f32(WSizei.x), f32(WSizei.y)}
|
||||||
}
|
}
|
||||||
|
|
||||||
rl.UpdateMusicStream(current_music)
|
rl.UpdateMusicStream(current_music)
|
||||||
|
|
||||||
state := stack_top()
|
state := stack_top()
|
||||||
delta := rl.GetFrameTime()
|
delta := rl.GetFrameTime()
|
||||||
timers_process(delta)
|
timers_process(delta)
|
||||||
tweens_process(delta)
|
ntween.process(&f32_tweens, delta)
|
||||||
state->update(delta)
|
ntween.process(&vec2_tweens, delta)
|
||||||
|
ntween.process(&vec3_tweens, delta)
|
||||||
|
state->update(delta)
|
||||||
|
|
||||||
rl.BeginDrawing()
|
rl.BeginDrawing()
|
||||||
rl.ClearBackground(rl.SKYBLUE)
|
rl.ClearBackground(rl.SKYBLUE)
|
||||||
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()
|
pos := rl.GetMousePosition()
|
||||||
rl.DrawTextureEx(Cursor, pos - {16, 16} * 3, 0, 3, rl.WHITE)
|
rl.DrawTextureEx(Cursor, pos - {16, 16} * 3, 0, 3, rl.WHITE)
|
||||||
rl.EndDrawing()
|
rl.EndDrawing()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Fullscreen := false
|
Fullscreen := false
|
||||||
|
@ -186,10 +196,10 @@ Fullscreen := false
|
||||||
toggle_fullscreen :: proc() {
|
toggle_fullscreen :: proc() {
|
||||||
monitor := rl.GetCurrentMonitor()
|
monitor := rl.GetCurrentMonitor()
|
||||||
rl.ToggleBorderlessWindowed()
|
rl.ToggleBorderlessWindowed()
|
||||||
WSizei = {rl.GetScreenWidth(), rl.GetScreenHeight()}
|
WSizei = {rl.GetScreenWidth(), rl.GetScreenHeight()}
|
||||||
WSize = {f32(WSizei.x), f32(WSizei.y)}
|
WSize = {f32(WSizei.x), f32(WSizei.y)}
|
||||||
Fullscreen = !Fullscreen
|
Fullscreen = !Fullscreen
|
||||||
|
|
||||||
|
|
||||||
// rl.ToggleFullscreen()
|
// rl.ToggleFullscreen()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import rl "vendor:raylib"
|
|
||||||
import "core:math/ease"
|
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
import "core:math/ease"
|
||||||
|
import "ntween"
|
||||||
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
MenuItemType :: enum {
|
MenuItemType :: enum {
|
||||||
NONE,
|
NONE,
|
||||||
|
@ -11,28 +12,28 @@ MenuItemType :: enum {
|
||||||
}
|
}
|
||||||
|
|
||||||
BoolStrings := map[bool]cstring {
|
BoolStrings := map[bool]cstring {
|
||||||
true = "вкл",
|
true = "вкл",
|
||||||
false = "выкл"
|
false = "выкл",
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuItem :: struct{
|
MenuItem :: struct {
|
||||||
text: cstring,
|
text: cstring,
|
||||||
param: rawptr,
|
param: rawptr,
|
||||||
type: MenuItemType,
|
type: MenuItemType,
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuList :: struct($T: typeid) {
|
MenuList :: struct($T: typeid) {
|
||||||
state: ^GameState,
|
state: ^GameState,
|
||||||
position: vec2,
|
position: vec2,
|
||||||
line_size: f32,
|
line_size: f32,
|
||||||
font_size: f32,
|
font_size: f32,
|
||||||
active_element: T,
|
active_element: T,
|
||||||
active_marker: vec2,
|
active_marker: vec2,
|
||||||
tween: ^Tween,
|
tween: ^ntween.Tween(f32),
|
||||||
elements: ^[T]MenuItem,
|
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,12 +47,10 @@ menu_list_update :: proc(list: ^MenuList($T)) {
|
||||||
list.mouse_pos = rl.GetMousePosition()
|
list.mouse_pos = rl.GetMousePosition()
|
||||||
|
|
||||||
size := menu_list_get_size(list)
|
size := menu_list_get_size(list)
|
||||||
if rl.CheckCollisionPointRec(list.mouse_pos, rl.Rectangle{
|
if rl.CheckCollisionPointRec(
|
||||||
x = list.position.x,
|
list.mouse_pos,
|
||||||
y = list.position.y,
|
rl.Rectangle{x = list.position.x, y = list.position.y, width = size.x, height = size.y},
|
||||||
width = size.x,
|
) {
|
||||||
height = size.y,
|
|
||||||
}) {
|
|
||||||
if last_mouse_pos != list.mouse_pos {
|
if last_mouse_pos != list.mouse_pos {
|
||||||
mouse_relative := list.mouse_pos - list.position
|
mouse_relative := list.mouse_pos - list.position
|
||||||
cur_element = i8(mouse_relative.y / list.line_size)
|
cur_element = i8(mouse_relative.y / list.line_size)
|
||||||
|
@ -63,7 +62,6 @@ menu_list_update :: proc(list: ^MenuList($T)) {
|
||||||
last_mouse_pos = list.mouse_pos
|
last_mouse_pos = list.mouse_pos
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if rl.IsKeyPressed(rl.KeyboardKey.DOWN) {
|
if rl.IsKeyPressed(rl.KeyboardKey.DOWN) {
|
||||||
cur_element += 1
|
cur_element += 1
|
||||||
}
|
}
|
||||||
|
@ -71,13 +69,14 @@ menu_list_update :: proc(list: ^MenuList($T)) {
|
||||||
cur_element -= 1
|
cur_element -= 1
|
||||||
}
|
}
|
||||||
if prev_element != cur_element {
|
if prev_element != cur_element {
|
||||||
if cur_element < 0 { cur_element = len(T) -1 }
|
if cur_element < 0 {cur_element = len(T) - 1}
|
||||||
if cur_element == len(T) { cur_element = 0 }
|
if cur_element == len(T) {cur_element = 0}
|
||||||
list.active_element = cast(T)cur_element
|
list.active_element = cast(T)cur_element
|
||||||
if list.tween != nil {
|
if list.tween != nil {
|
||||||
tween_cancel(list.tween)
|
ntween.cancel(list.tween)
|
||||||
}
|
}
|
||||||
list.tween = tween_to(
|
list.tween = ntween.animate(
|
||||||
|
&f32_tweens,
|
||||||
&list.active_marker.y,
|
&list.active_marker.y,
|
||||||
f32(list.active_element) * list.line_size,
|
f32(list.active_element) * list.line_size,
|
||||||
0.25,
|
0.25,
|
||||||
|
@ -94,7 +93,14 @@ menu_list_draw :: proc(list: ^MenuList($T)) {
|
||||||
size := menu_list_get_size(list)
|
size := menu_list_get_size(list)
|
||||||
rl.DrawRectangleV(list.position - {40, 40}, size + {80, 80}, list.background)
|
rl.DrawRectangleV(list.position - {40, 40}, size + {80, 80}, list.background)
|
||||||
}
|
}
|
||||||
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}
|
||||||
text := el.text
|
text := el.text
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 7136c68f3e63470b9b1c80109dd0904151e08070
|
74
pause.odin
74
pause.odin
|
@ -1,51 +1,50 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import rl "vendor:raylib"
|
|
||||||
import "core:math/ease"
|
import "core:math/ease"
|
||||||
|
import "ntween"
|
||||||
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
|
|
||||||
Pause_Buttons :: enum {
|
Pause_Buttons :: enum {
|
||||||
CONTINUE,
|
CONTINUE,
|
||||||
EXIT
|
EXIT,
|
||||||
}
|
}
|
||||||
|
|
||||||
pause_strings := [Pause_Buttons]cstring {
|
pause_strings := [Pause_Buttons]cstring {
|
||||||
.CONTINUE = "Продолжить",
|
.CONTINUE = "Продолжить",
|
||||||
.EXIT = "Прервать игру"
|
.EXIT = "Прервать игру",
|
||||||
}
|
}
|
||||||
|
|
||||||
pause_items := [Pause_Buttons]MenuItem {
|
pause_items := [Pause_Buttons]MenuItem {
|
||||||
.CONTINUE = {text = pause_strings[.CONTINUE]},
|
.CONTINUE = {text = pause_strings[.CONTINUE]},
|
||||||
.EXIT = {text = pause_strings[.EXIT]}
|
.EXIT = {text = pause_strings[.EXIT]},
|
||||||
}
|
}
|
||||||
|
|
||||||
Pause :: struct {
|
Pause :: struct {
|
||||||
using state: GameState,
|
using state: GameState,
|
||||||
|
active: bool,
|
||||||
active: bool,
|
list: MenuList(Pause_Buttons),
|
||||||
list: MenuList(Pause_Buttons),
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pause_init :: proc(prev: ^GameState = nil) -> ^GameState {
|
pause_init :: proc(prev: ^GameState = nil) -> ^GameState {
|
||||||
state := new(Pause)
|
state := new(Pause)
|
||||||
state.variant = state
|
state.variant = state
|
||||||
state.list = MenuList(Pause_Buttons){
|
state.list = MenuList(Pause_Buttons) {
|
||||||
state = state,
|
state = state,
|
||||||
position = {-300, WSize.y / 2},
|
position = {-300, WSize.y / 2},
|
||||||
line_size = 60,
|
line_size = 60,
|
||||||
font_size = 48,
|
font_size = 48,
|
||||||
elements = &pause_items,
|
elements = &pause_items,
|
||||||
menu_pressed = pause_button_pressed,
|
menu_pressed = pause_button_pressed,
|
||||||
background = rl.Color{50, 10, 110, 0}
|
background = rl.Color{50, 10, 110, 0},
|
||||||
}
|
}
|
||||||
state.update = pause_update
|
state.update = pause_update
|
||||||
state.draw = pause_draw
|
state.draw = pause_draw
|
||||||
state.free = pause_free
|
state.free = pause_free
|
||||||
state.previous = prev
|
state.previous = prev
|
||||||
state.active = true
|
state.active = true
|
||||||
|
|
||||||
tween_to(&state.list.position.x, 100, 0.5, ease.Ease.Back_Out)
|
ntween.animate(&f32_tweens, &state.list.position.x, 100, 0.5, ease.Ease.Back_Out)
|
||||||
|
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
@ -59,14 +58,21 @@ pause_update :: proc(state: ^GameState, delta: f32) {
|
||||||
|
|
||||||
pause_button_pressed :: proc(state: ^GameState, el: Pause_Buttons) {
|
pause_button_pressed :: proc(state: ^GameState, el: Pause_Buttons) {
|
||||||
pause := transmute(^Pause)state
|
pause := transmute(^Pause)state
|
||||||
if !pause.active { return }
|
if !pause.active {return}
|
||||||
switch el {
|
switch el {
|
||||||
case .CONTINUE:
|
case .CONTINUE:
|
||||||
stack_pop()
|
stack_pop()
|
||||||
case .EXIT:
|
case .EXIT:
|
||||||
pause.active = false
|
pause.active = false
|
||||||
rl.StopMusicStream(current_music)
|
rl.StopMusicStream(current_music)
|
||||||
tween_to(&Overlay_Opacity, 1.0, 0.5, ease.Ease.Cubic_Out, state, proc(data: rawptr) {
|
ntween.animate(
|
||||||
|
&f32_tweens,
|
||||||
|
&Overlay_Opacity,
|
||||||
|
1.0,
|
||||||
|
0.5,
|
||||||
|
ease.Ease.Cubic_Out,
|
||||||
|
state,
|
||||||
|
proc(data: rawptr) {
|
||||||
state := transmute(^GameState)data
|
state := transmute(^GameState)data
|
||||||
stack_pop()
|
stack_pop()
|
||||||
game := transmute(^Game)stack_top()
|
game := transmute(^Game)stack_top()
|
||||||
|
@ -74,21 +80,31 @@ pause_button_pressed :: proc(state: ^GameState, el: Pause_Buttons) {
|
||||||
menu := menu_init(game)
|
menu := menu_init(game)
|
||||||
stack_push(menu)
|
stack_push(menu)
|
||||||
//free(state)
|
//free(state)
|
||||||
tween_to(&Overlay_Opacity, 0, 0.5, ease.Ease.Cubic_Out)
|
ntween.animate(&f32_tweens, &Overlay_Opacity, 0, 0.5, ease.Ease.Cubic_Out)
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pause_draw :: proc(state: ^GameState) {
|
pause_draw :: proc(state: ^GameState) {
|
||||||
pause := transmute(^Pause)state
|
pause := transmute(^Pause)state
|
||||||
|
|
||||||
pause.previous.draw(pause.previous)
|
pause.previous.draw(pause.previous)
|
||||||
|
|
||||||
TitleFontSize :: 96
|
TitleFontSize :: 96
|
||||||
TitleSpacing :: 3
|
TitleSpacing :: 3
|
||||||
TitleText :: "Ragnarøkkr"
|
TitleText :: "Ragnarøkkr"
|
||||||
TitleSize := rl.MeasureTextEx(Res.Fonts.Title, TitleText, TitleFontSize, TitleSpacing)
|
TitleSize := rl.MeasureTextEx(Res.Fonts.Title, TitleText, TitleFontSize, TitleSpacing)
|
||||||
rl.DrawTextPro(Res.Fonts.Title, TitleText, {WSize.x - 50, 50}, {TitleSize.x, 0}, 0, 96, 3, rl.WHITE)
|
rl.DrawTextPro(
|
||||||
|
Res.Fonts.Title,
|
||||||
|
TitleText,
|
||||||
|
{WSize.x - 50, 50},
|
||||||
|
{TitleSize.x, 0},
|
||||||
|
0,
|
||||||
|
96,
|
||||||
|
3,
|
||||||
|
rl.WHITE,
|
||||||
|
)
|
||||||
|
|
||||||
menu_list_draw(&pause.list)
|
menu_list_draw(&pause.list)
|
||||||
|
|
||||||
|
|
476
player.odin
476
player.odin
|
@ -1,270 +1,280 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
import "core:fmt"
|
||||||
|
import "core:math"
|
||||||
|
import "core:math/ease"
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:slice"
|
||||||
|
import "core:strings"
|
||||||
|
import "ntween"
|
||||||
import rl "vendor:raylib"
|
import rl "vendor:raylib"
|
||||||
import "vendor:raylib/rlgl"
|
import "vendor:raylib/rlgl"
|
||||||
import "core:math"
|
|
||||||
import "core:strings"
|
|
||||||
import "core:math/rand"
|
|
||||||
import "core:math/ease"
|
|
||||||
import "core:fmt"
|
|
||||||
import "core:slice"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// PlayerAnims : [^]rl.ModelAnimation
|
// PlayerAnims : [^]rl.ModelAnimation
|
||||||
// PlayerAnimsCount : i32
|
// PlayerAnimsCount : i32
|
||||||
|
|
||||||
Player :: struct {
|
Player :: struct {
|
||||||
pos: vec3,
|
pos: vec3,
|
||||||
vel: vec3,
|
vel: vec3,
|
||||||
dir: f32,
|
dir: f32,
|
||||||
radius: f32,
|
radius: f32,
|
||||||
thrust: f32,
|
thrust: f32,
|
||||||
max_speed: f32,
|
max_speed: f32,
|
||||||
rolling: f32,
|
rolling: f32,
|
||||||
charge: f32,
|
charge: f32,
|
||||||
is_dodging: bool,
|
is_dodging: bool,
|
||||||
can_dodge: bool,
|
can_dodge: bool,
|
||||||
can_shoot: bool,
|
can_shoot: bool,
|
||||||
is_invulnerable: bool,
|
is_invulnerable: bool,
|
||||||
is_dead: bool,
|
is_dead: bool,
|
||||||
intro_timer: f32,
|
intro_timer: f32,
|
||||||
power: f32,
|
power: f32,
|
||||||
reload_timer: f32,
|
reload_timer: f32,
|
||||||
reloading: bool,
|
reloading: bool,
|
||||||
// animation: rl.ModelAnimation,
|
// animation: rl.ModelAnimation,
|
||||||
// animTime: f32,
|
// animTime: f32,
|
||||||
// animFrame: i32,
|
// animFrame: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
player_spawn :: proc(position: vec3) -> Player {
|
player_spawn :: proc(position: vec3) -> Player {
|
||||||
|
|
||||||
// PlayerAnims = rl.LoadModelAnimations(PlayerModelPath, &PlayerAnimsCount)
|
// PlayerAnims = rl.LoadModelAnimations(PlayerModelPath, &PlayerAnimsCount)
|
||||||
return Player{
|
return Player {
|
||||||
pos = position,
|
pos = position,
|
||||||
radius = 1,
|
radius = 1,
|
||||||
max_speed = 40,
|
max_speed = 40,
|
||||||
dir = 0,
|
dir = 0,
|
||||||
vel = {-80, 0, 0},
|
vel = {-80, 0, 0},
|
||||||
can_dodge = true,
|
can_dodge = true,
|
||||||
can_shoot = true,
|
can_shoot = true,
|
||||||
intro_timer = 2,
|
intro_timer = 2,
|
||||||
power = 100,
|
power = 100,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
player_update :: proc(player: ^Player, game: ^Game, delta: f32) {
|
player_update :: proc(player: ^Player, game: ^Game, delta: f32) {
|
||||||
using player
|
using player
|
||||||
|
|
||||||
if intro_timer > 0 {
|
if intro_timer > 0 {
|
||||||
intro_timer -= delta
|
intro_timer -= delta
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mouse_ray := rl.GetMouseRay(rl.GetMousePosition(), game.camera)
|
mouse_ray := rl.GetMouseRay(rl.GetMousePosition(), game.camera)
|
||||||
mouse_pos : vec3
|
mouse_pos: vec3
|
||||||
hit := rl.GetRayCollisionQuad(mouse_ray,
|
hit := rl.GetRayCollisionQuad(
|
||||||
{-1000, -1000, 0},
|
mouse_ray,
|
||||||
{-1000, 1000, 0},
|
{-1000, -1000, 0},
|
||||||
{1000, 1000, 0},
|
{-1000, 1000, 0},
|
||||||
{1000, -1000, 0}
|
{1000, 1000, 0},
|
||||||
)
|
{1000, -1000, 0},
|
||||||
if hit.hit {
|
)
|
||||||
mouse_pos = hit.point
|
if hit.hit {
|
||||||
}
|
mouse_pos = hit.point
|
||||||
|
}
|
||||||
|
|
||||||
mouse_diff := mouse_pos - pos
|
mouse_diff := mouse_pos - pos
|
||||||
mouse_angle := math.atan2(-mouse_diff.y, mouse_diff.x)
|
mouse_angle := math.atan2(-mouse_diff.y, mouse_diff.x)
|
||||||
|
|
||||||
if !is_dead {
|
if !is_dead {
|
||||||
pos += vel * delta
|
pos += vel * delta
|
||||||
if pos.y < radius {
|
if pos.y < radius {
|
||||||
pos.y = radius
|
pos.y = radius
|
||||||
vel.y = - vel.y
|
vel.y = -vel.y
|
||||||
}
|
}
|
||||||
if !is_dodging {
|
if !is_dodging {
|
||||||
dir_vector : vec3
|
dir_vector: vec3
|
||||||
if intro_timer <= 0 {
|
if intro_timer <= 0 {
|
||||||
thrust_key := rl.KeyboardKey.W
|
thrust_key := rl.KeyboardKey.W
|
||||||
if !KeyboardOnly {
|
if !KeyboardOnly {
|
||||||
dir = angle_rotate(dir, mouse_angle, math.PI * 2 * delta)
|
dir = angle_rotate(dir, mouse_angle, math.PI * 2 * delta)
|
||||||
dir_vector = get_vec_from_angle(dir)
|
dir_vector = get_vec_from_angle(dir)
|
||||||
} else {
|
} else {
|
||||||
thrust_key = rl.KeyboardKey.UP
|
thrust_key = rl.KeyboardKey.UP
|
||||||
if rl.IsKeyDown(rl.KeyboardKey.LEFT) {
|
if rl.IsKeyDown(rl.KeyboardKey.LEFT) {
|
||||||
dir += math.PI * 2 * delta
|
dir += math.PI * 2 * delta
|
||||||
}
|
}
|
||||||
if rl.IsKeyDown(rl.KeyboardKey.RIGHT) {
|
if rl.IsKeyDown(rl.KeyboardKey.RIGHT) {
|
||||||
dir -= math.PI * 2 * delta
|
dir -= math.PI * 2 * delta
|
||||||
}
|
}
|
||||||
dir_vector = get_vec_from_angle(dir)
|
dir_vector = get_vec_from_angle(dir)
|
||||||
}
|
}
|
||||||
thrust = 0
|
thrust = 0
|
||||||
if rl.IsKeyDown(thrust_key) {
|
if rl.IsKeyDown(thrust_key) {
|
||||||
thrust = 110
|
thrust = 110
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
thrust = 110
|
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)
|
||||||
}
|
}
|
||||||
if thrust > 0 {
|
if thrust > 0 {
|
||||||
roll := -math.PI / 2 + math.cos(dir) * math.PI / 2
|
roll := -math.PI / 2 + math.cos(dir) * math.PI / 2
|
||||||
vel = rl.Vector3MoveTowards(vel, dir_vector * max_speed, thrust * delta)
|
vel = rl.Vector3MoveTowards(vel, dir_vector * max_speed, thrust * delta)
|
||||||
offset := rl.Vector3RotateByAxisAngle(vec3backward, vec3right, roll) * 2.6
|
offset := rl.Vector3RotateByAxisAngle(vec3backward, vec3right, roll) * 2.6
|
||||||
offset = rl.Vector3RotateByAxisAngle(offset, vec3backward, dir)
|
offset = rl.Vector3RotateByAxisAngle(offset, vec3backward, dir)
|
||||||
pl := pos + offset
|
pl := pos + offset
|
||||||
pr := pos - offset
|
pr := pos - offset
|
||||||
trail(pl, 1, rand.float32_range(1.7, 3.5))
|
trail(pl, 1, rand.float32_range(1.7, 3.5))
|
||||||
trail(pr, 1, rand.float32_range(1.7, 3.5))
|
trail(pr, 1, rand.float32_range(1.7, 3.5))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if thrust == 0 {
|
if thrust == 0 {
|
||||||
vel = rl.Vector3MoveTowards(vel, {0, -30, 0}, 20 * delta)
|
vel = rl.Vector3MoveTowards(vel, {0, -30, 0}, 20 * delta)
|
||||||
rl.StopSound(Res.Sfx.Rocket)
|
rl.StopSound(Res.Sfx.Rocket)
|
||||||
} else {
|
} else {
|
||||||
if !rl.IsSoundPlaying(Res.Sfx.Rocket) && !is_dodging {
|
if !rl.IsSoundPlaying(Res.Sfx.Rocket) && !is_dodging {
|
||||||
rl.PlaySound(Res.Sfx.Rocket)
|
rl.PlaySound(Res.Sfx.Rocket)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dodge := false
|
dodge := false
|
||||||
shoot := false
|
shoot := false
|
||||||
if KeyboardOnly {
|
if KeyboardOnly {
|
||||||
dodge = rl.IsKeyPressed(rl.KeyboardKey.LEFT_SHIFT)
|
dodge = rl.IsKeyPressed(rl.KeyboardKey.LEFT_SHIFT)
|
||||||
shoot = rl.IsKeyDown(rl.KeyboardKey.SPACE)
|
shoot = rl.IsKeyDown(rl.KeyboardKey.SPACE)
|
||||||
} else {
|
} else {
|
||||||
dodge = rl.IsMouseButtonPressed(rl.MouseButton.RIGHT)
|
dodge = rl.IsMouseButtonPressed(rl.MouseButton.RIGHT)
|
||||||
shoot = rl.IsMouseButtonDown(rl.MouseButton.LEFT)
|
shoot = rl.IsMouseButtonDown(rl.MouseButton.LEFT)
|
||||||
}
|
}
|
||||||
|
|
||||||
if dodge && can_dodge && intro_timer <= 0 {
|
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)
|
||||||
rl.PlaySound(Res.Sfx.PlayerSwoosh)
|
rl.PlaySound(Res.Sfx.PlayerSwoosh)
|
||||||
tween_to(&player.rolling, math.PI*2, 0.42, ease.Ease.Quadratic_Out)
|
ntween.animate(
|
||||||
timer_start(0.45, player, proc(data: rawptr) {
|
&f32_tweens,
|
||||||
player := transmute(^Player)data
|
&player.rolling,
|
||||||
player.is_dodging = false
|
math.PI * 2,
|
||||||
player.rolling = 0
|
0.42,
|
||||||
})
|
ease.Ease.Quadratic_Out,
|
||||||
timer_start(0.55, player, proc(data: rawptr) {
|
)
|
||||||
player := transmute(^Player)data
|
timer_start(0.45, player, proc(data: rawptr) {
|
||||||
player.can_dodge = true
|
player := transmute(^Player)data
|
||||||
})
|
player.is_dodging = false
|
||||||
}
|
player.rolling = 0
|
||||||
|
})
|
||||||
|
timer_start(0.55, player, proc(data: rawptr) {
|
||||||
|
player := transmute(^Player)data
|
||||||
|
player.can_dodge = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// player.animation = PlayerAnims[1]
|
// player.animation = PlayerAnims[1]
|
||||||
// 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 := shoot && !is_dodging && intro_timer <= 0 && !reloading
|
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)
|
||||||
}
|
}
|
||||||
if can_shoot {
|
if can_shoot {
|
||||||
roll := -math.PI / 2 + math.cos(dir) * math.PI / 2
|
roll := -math.PI / 2 + math.cos(dir) * math.PI / 2
|
||||||
b := bullet_spawn(pos + get_vec_from_angle(dir) * 3 + get_vec_from_angle(dir+math.PI/2)*.3, dir)
|
b := bullet_spawn(
|
||||||
append(&game.bullets, b)
|
pos + get_vec_from_angle(dir) * 3 + get_vec_from_angle(dir + math.PI / 2) * .3,
|
||||||
can_shoot = false
|
dir,
|
||||||
timer_start(0.07, player, proc(data: rawptr) {
|
)
|
||||||
player := transmute(^Player)data
|
append(&game.bullets, b)
|
||||||
player.can_shoot = true
|
can_shoot = false
|
||||||
})
|
timer_start(0.07, player, proc(data: rawptr) {
|
||||||
player.power -= 2
|
player := transmute(^Player)data
|
||||||
player.reload_timer = 1
|
player.can_shoot = true
|
||||||
if player.power <= 0 {
|
})
|
||||||
player.reloading = true
|
player.power -= 2
|
||||||
player.power = 0
|
player.reload_timer = 1
|
||||||
}
|
if player.power <= 0 {
|
||||||
}
|
player.reloading = true
|
||||||
} else {
|
player.power = 0
|
||||||
rl.StopSound(Res.Sfx.Lightning)
|
}
|
||||||
}
|
}
|
||||||
if !shooting && can_shoot {
|
} else {
|
||||||
reload_timer -= delta
|
rl.StopSound(Res.Sfx.Lightning)
|
||||||
if reload_timer <= 0 {
|
}
|
||||||
player.power += 20 * delta
|
if !shooting && can_shoot {
|
||||||
if player.power > 100 {
|
reload_timer -= delta
|
||||||
player.power = 100
|
if reload_timer <= 0 {
|
||||||
player.reloading = false
|
player.power += 20 * delta
|
||||||
}
|
if player.power > 100 {
|
||||||
}
|
player.power = 100
|
||||||
}
|
player.reloading = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
got_hit := false
|
got_hit := false
|
||||||
|
|
||||||
hit: if !is_invulnerable && !is_dodging && !is_dead {
|
hit: if !is_invulnerable && !is_dodging && !is_dead {
|
||||||
if rl.CheckCollisionCircles(pos.xy, radius, Head.pos.xy, Head.radius) {
|
if rl.CheckCollisionCircles(pos.xy, radius, Head.pos.xy, Head.radius) {
|
||||||
got_hit = true
|
got_hit = true
|
||||||
break hit
|
break hit
|
||||||
}
|
}
|
||||||
ray := rl.Ray{
|
ray := rl.Ray {
|
||||||
position = Head.pos,
|
position = Head.pos,
|
||||||
direction = get_vec_from_angle(Head.dir)
|
direction = get_vec_from_angle(Head.dir),
|
||||||
}
|
}
|
||||||
if Head.is_shooting && rl.GetRayCollisionSphere(ray, pos, radius + 3).hit {
|
if Head.is_shooting && rl.GetRayCollisionSphere(ray, pos, radius + 3).hit {
|
||||||
got_hit = true
|
got_hit = true
|
||||||
break hit
|
break hit
|
||||||
}
|
}
|
||||||
for segment in Segments {
|
for segment in Segments {
|
||||||
if rl.CheckCollisionCircles(pos.xy, radius, segment.pos.xy, radius) {
|
if rl.CheckCollisionCircles(pos.xy, radius, segment.pos.xy, radius) {
|
||||||
got_hit = true
|
got_hit = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if rl.IsKeyPressed(rl.KeyboardKey.M) {
|
if rl.IsKeyPressed(rl.KeyboardKey.M) {
|
||||||
got_hit = true
|
got_hit = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if got_hit {
|
if got_hit {
|
||||||
game.health -= 10
|
game.health -= 10
|
||||||
rl.PlaySound(Res.Sfx.PlayerHit)
|
rl.PlaySound(Res.Sfx.PlayerHit)
|
||||||
is_invulnerable = true
|
is_invulnerable = true
|
||||||
timer_start(1, player, proc(data: rawptr) {
|
timer_start(1, player, proc(data: rawptr) {
|
||||||
plr := transmute(^Player)data
|
plr := transmute(^Player)data
|
||||||
plr.is_invulnerable = false
|
plr.is_invulnerable = false
|
||||||
})
|
})
|
||||||
if game.health <= 0 && !is_dead {
|
if game.health <= 0 && !is_dead {
|
||||||
is_dead = true
|
is_dead = true
|
||||||
explode(pos, 10, 0.8, rl.WHITE)
|
explode(pos, 10, 0.8, rl.WHITE)
|
||||||
rl.StopMusicStream(current_music)
|
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
|
||||||
screen := gameover_init(state)
|
screen := gameover_init(state)
|
||||||
stack_push(screen)
|
stack_push(screen)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
player_draw :: proc(player: ^Player) {
|
player_draw :: proc(player: ^Player) {
|
||||||
using player
|
using player
|
||||||
if player.is_dead { return }
|
if player.is_dead {return}
|
||||||
dir_vector := get_vec_from_angle(dir)
|
dir_vector := get_vec_from_angle(dir)
|
||||||
color := rl.WHITE
|
color := rl.WHITE
|
||||||
if is_invulnerable {
|
if is_invulnerable {
|
||||||
color = rl.Color{255, 170, 170, 255}
|
color = rl.Color{255, 170, 170, 255}
|
||||||
}
|
}
|
||||||
|
|
||||||
roll := -math.PI / 2 + math.cos(dir) * math.PI / 2
|
roll := -math.PI / 2 + math.cos(dir) * math.PI / 2
|
||||||
rlgl.PushMatrix()
|
rlgl.PushMatrix()
|
||||||
rlgl.Translatef(pos.x, pos.y, pos.z)
|
rlgl.Translatef(pos.x, pos.y, pos.z)
|
||||||
rlgl.Rotatef(math.to_degrees(dir), 0, 0, -1)
|
rlgl.Rotatef(math.to_degrees(dir), 0, 0, -1)
|
||||||
rlgl.Rotatef(math.to_degrees(roll + player.rolling), 1, 0, 0)
|
rlgl.Rotatef(math.to_degrees(roll + player.rolling), 1, 0, 0)
|
||||||
// rl.DrawCircle3D({}, radius, vec3up, 0, color)
|
// rl.DrawCircle3D({}, radius, vec3up, 0, color)
|
||||||
// rl.DrawLine3D({}, {-4, 0, 0}, rl.GREEN)
|
// rl.DrawLine3D({}, {-4, 0, 0}, rl.GREEN)
|
||||||
rl.DrawModel(Res.Models.PlayerModel, {}, 6, color)
|
rl.DrawModel(Res.Models.PlayerModel, {}, 6, color)
|
||||||
rlgl.PopMatrix()
|
rlgl.PopMatrix()
|
||||||
// rl.DrawLine3D(pos, pos + dir_vector * radius, rl.BLACK)
|
// rl.DrawLine3D(pos, pos + dir_vector * radius, rl.BLACK)
|
||||||
// rl.DrawLine3D(pos, pos + vel, rl.RED)
|
// rl.DrawLine3D(pos, pos + vel, rl.RED)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
80
tween.odin
80
tween.odin
|
@ -1,80 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import "core:math"
|
|
||||||
import "core:math/ease"
|
|
||||||
import "core:math/linalg"
|
|
||||||
import "core:slice"
|
|
||||||
|
|
||||||
|
|
||||||
Tween :: struct {
|
|
||||||
ptr: ^f32,
|
|
||||||
from: f32,
|
|
||||||
to: f32,
|
|
||||||
time: f32,
|
|
||||||
duration: f32,
|
|
||||||
ease_type: ease.Ease,
|
|
||||||
active: bool,
|
|
||||||
finished: proc(data: rawptr),
|
|
||||||
data: rawptr
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
tweens : [dynamic]^Tween
|
|
||||||
|
|
||||||
|
|
||||||
tween_clean :: proc() {
|
|
||||||
for tween, i in tweens {
|
|
||||||
free(tween)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tween_to :: proc(
|
|
||||||
value: ^f32, to: f32, duration: f32,
|
|
||||||
ease: ease.Ease = ease.Ease.Quartic_In_Out,
|
|
||||||
data: rawptr = nil,
|
|
||||||
callback: proc(data: rawptr) = nil
|
|
||||||
) -> ^Tween {
|
|
||||||
|
|
||||||
tween := new(Tween)
|
|
||||||
tween.ptr = value
|
|
||||||
tween.from = value^
|
|
||||||
tween.to = to
|
|
||||||
tween.duration = duration
|
|
||||||
tween.ease_type = ease
|
|
||||||
tween.active = true
|
|
||||||
tween.data = data
|
|
||||||
tween.finished = callback
|
|
||||||
|
|
||||||
append(&tweens, tween)
|
|
||||||
return tween
|
|
||||||
}
|
|
||||||
|
|
||||||
tween_cancel :: proc(t: ^Tween) {
|
|
||||||
t.active = false
|
|
||||||
}
|
|
||||||
|
|
||||||
tweens_process :: proc(delta: f32) {
|
|
||||||
#reverse for tween, i in tweens {
|
|
||||||
|
|
||||||
tween.time += delta
|
|
||||||
p := clamp(tween.time / tween.duration, 0, 1)
|
|
||||||
|
|
||||||
val := ease.ease(tween.ease_type, p)
|
|
||||||
if tween.ptr != nil {
|
|
||||||
tween.ptr^ = math.lerp(tween.from, tween.to, val)
|
|
||||||
} else {
|
|
||||||
tween.active = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if tween.time >= tween.duration {
|
|
||||||
tween.active = false
|
|
||||||
if tween.finished != nil {
|
|
||||||
tween.finished(tween.data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !tween.active {
|
|
||||||
free(tween)
|
|
||||||
unordered_remove(&tweens, i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
71
winning.odin
71
winning.odin
|
@ -1,14 +1,15 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import rl "vendor:raylib"
|
|
||||||
import "core:math/ease"
|
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
import "core:math/ease"
|
||||||
|
import "ntween"
|
||||||
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
|
|
||||||
Winning :: struct {
|
Winning :: struct {
|
||||||
using state: GameState,
|
using state: GameState,
|
||||||
position: vec2,
|
position: vec2,
|
||||||
size: vec2,
|
size: vec2,
|
||||||
ready_to_go: bool,
|
ready_to_go: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +23,15 @@ winning_init :: proc(prev: ^GameState = nil) -> ^GameState {
|
||||||
state.free = winning_free
|
state.free = winning_free
|
||||||
|
|
||||||
state.previous = prev
|
state.previous = prev
|
||||||
tween_to(&state.position.y, WSize.y / 2, 1, ease.Ease.Back_Out, state, winning_ready)
|
ntween.animate(
|
||||||
|
&vec2_tweens,
|
||||||
|
&state.position,
|
||||||
|
WSize / 2,
|
||||||
|
1,
|
||||||
|
ease.Ease.Back_Out,
|
||||||
|
state,
|
||||||
|
winning_ready,
|
||||||
|
)
|
||||||
|
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
@ -33,16 +42,24 @@ winning_update :: proc(state: ^GameState, delta: f32) {
|
||||||
if rl.IsKeyPressed(rl.KeyboardKey.ESCAPE) {
|
if rl.IsKeyPressed(rl.KeyboardKey.ESCAPE) {
|
||||||
winning.ready_to_go = false
|
winning.ready_to_go = false
|
||||||
rl.StopMusicStream(current_music)
|
rl.StopMusicStream(current_music)
|
||||||
tween_to(&Overlay_Opacity, 1.0, 0.5, ease.Ease.Cubic_Out, nil, proc(data: rawptr) {
|
ntween.animate(
|
||||||
state := transmute(^GameState)data
|
&f32_tweens,
|
||||||
stack_pop()
|
&Overlay_Opacity,
|
||||||
game := transmute(^Game)state.previous
|
1.0,
|
||||||
game_setup(game)
|
0.5,
|
||||||
menu := menu_init(game)
|
ease.Ease.Cubic_Out,
|
||||||
stack_push(menu)
|
nil,
|
||||||
free(state)
|
proc(data: rawptr) {
|
||||||
tween_to(&Overlay_Opacity, 0, 0.5, ease.Ease.Cubic_Out)
|
state := transmute(^GameState)data
|
||||||
})
|
stack_pop()
|
||||||
|
game := transmute(^Game)state.previous
|
||||||
|
game_setup(game)
|
||||||
|
menu := menu_init(game)
|
||||||
|
stack_push(menu)
|
||||||
|
free(state)
|
||||||
|
ntween.animate(&f32_tweens, &Overlay_Opacity, 0, 0.5, ease.Ease.Cubic_Out)
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,15 +76,33 @@ winning_draw :: proc(state: ^GameState) {
|
||||||
TitleSpacing :: 3
|
TitleSpacing :: 3
|
||||||
TitleText :: "GAME OVER"
|
TitleText :: "GAME OVER"
|
||||||
|
|
||||||
SubtitleText := [?]cstring{"Тор смог спасти Асгард", "от Рагнарёка!", "Нажмите Escape чтобы выйти"}
|
SubtitleText := [?]cstring {
|
||||||
|
"Тор смог спасти Асгард",
|
||||||
|
"от Рагнарёка!",
|
||||||
|
"Нажмите Escape чтобы выйти",
|
||||||
|
}
|
||||||
SubtitleFontSize :: 48
|
SubtitleFontSize :: 48
|
||||||
|
|
||||||
|
|
||||||
rl.DrawRectangleV(winning.position - winning.size / 2, winning.size, rl.Color{90, 30, 150, 10})
|
rl.DrawRectangleV(winning.position - winning.size / 2, winning.size, rl.Color{90, 30, 150, 10})
|
||||||
|
|
||||||
draw_text_centered(Res.Fonts.Title, TitleText, winning.position - {0, 100}, TitleFontSize, 1, rl.WHITE)
|
draw_text_centered(
|
||||||
|
Res.Fonts.Title,
|
||||||
|
TitleText,
|
||||||
|
winning.position - {0, 100},
|
||||||
|
TitleFontSize,
|
||||||
|
1,
|
||||||
|
rl.WHITE,
|
||||||
|
)
|
||||||
for c, i in SubtitleText {
|
for c, i in SubtitleText {
|
||||||
draw_text_centered(Res.Fonts.UI, c, winning.position - {0, f32(10 - i * 50)}, SubtitleFontSize, 1, rl.WHITE)
|
draw_text_centered(
|
||||||
|
Res.Fonts.UI,
|
||||||
|
c,
|
||||||
|
winning.position - {0, f32(10 - i * 50)},
|
||||||
|
SubtitleFontSize,
|
||||||
|
1,
|
||||||
|
rl.WHITE,
|
||||||
|
)
|
||||||
// rl.DrawTextPro(Res.Fonts.UI, c, winning.position - {0, f32(10 - i * 50)}, SubtitleSizes[i] / 2, 0, SubtitleFontSize, SubtitleSpacing, rl.WHITE)
|
// rl.DrawTextPro(Res.Fonts.UI, c, winning.position - {0, f32(10 - i * 50)}, SubtitleSizes[i] / 2, 0, SubtitleFontSize, SubtitleSpacing, rl.WHITE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue