Compare commits
	
		
			5 Commits
		
	
	
		
			Hackathon-
			...
			f72ac633ee
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| f72ac633ee | |||
| 4df0bcd5ff | |||
| b251553275 | |||
| 8a9e20f370 | |||
| 4f0b5dace4 | 
							
								
								
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
			
		||||
[submodule "ntween"]
 | 
			
		||||
	path = ntween
 | 
			
		||||
	url = https://git.nefrace.ru/nefrace/ntween.git
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								Ragnarokkr
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Ragnarokkr
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Ragnarokkr.exe
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Ragnarokkr.exe
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							@ -1,14 +1,15 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import rl "vendor:raylib"
 | 
			
		||||
import "core:math/ease"
 | 
			
		||||
import "core:fmt"
 | 
			
		||||
import "core:math/ease"
 | 
			
		||||
import "ntween"
 | 
			
		||||
import rl "vendor:raylib"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
GameOver :: struct {
 | 
			
		||||
	using state: GameState,
 | 
			
		||||
	position: vec2,
 | 
			
		||||
	size: vec2,
 | 
			
		||||
	position:    vec2,
 | 
			
		||||
	size:        vec2,
 | 
			
		||||
	ready_to_go: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -22,8 +23,16 @@ gameover_init :: proc(prev: ^GameState = nil) -> ^GameState {
 | 
			
		||||
	state.free = gameover_free
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -33,16 +42,24 @@ gameover_update :: proc(state: ^GameState, delta: f32) {
 | 
			
		||||
		if rl.IsKeyPressed(rl.KeyboardKey.ESCAPE) {
 | 
			
		||||
			gameover.ready_to_go = false
 | 
			
		||||
			rl.StopMusicStream(current_music)
 | 
			
		||||
			tween_to(&Overlay_Opacity, 1.0, 0.5, ease.Ease.Cubic_Out, state, proc(data: rawptr) {
 | 
			
		||||
				state := transmute(^GameState)data
 | 
			
		||||
				stack_pop()
 | 
			
		||||
				game := transmute(^Game)state.previous
 | 
			
		||||
				game_setup(game)
 | 
			
		||||
				menu := menu_init(game)
 | 
			
		||||
				stack_push(menu)
 | 
			
		||||
				free(state)
 | 
			
		||||
				tween_to(&Overlay_Opacity, 0, 0.5, ease.Ease.Cubic_Out)
 | 
			
		||||
			})
 | 
			
		||||
			ntween.animate(
 | 
			
		||||
				&f32_tweens,
 | 
			
		||||
				&Overlay_Opacity,
 | 
			
		||||
				1.0,
 | 
			
		||||
				0.5,
 | 
			
		||||
				ease.Ease.Cubic_Out,
 | 
			
		||||
				state,
 | 
			
		||||
				proc(data: rawptr) {
 | 
			
		||||
					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)
 | 
			
		||||
				},
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -50,7 +67,7 @@ gameover_update :: proc(state: ^GameState, delta: f32) {
 | 
			
		||||
 | 
			
		||||
gameover_draw :: proc(state: ^GameState) {
 | 
			
		||||
	gameover := transmute(^GameOver)state
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	if state.previous != nil {
 | 
			
		||||
		state.previous->draw()
 | 
			
		||||
	}
 | 
			
		||||
@ -63,12 +80,26 @@ gameover_draw :: proc(state: ^GameState) {
 | 
			
		||||
	SubtitleText := [?]cstring{"Нажмите Escape чтобы выйти"}
 | 
			
		||||
	SubtitleFontSize :: 48
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	// 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 {
 | 
			
		||||
		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)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										229
									
								
								main.odin
									
									
									
									
									
								
							
							
						
						
									
										229
									
								
								main.odin
									
									
									
									
									
								
							@ -1,11 +1,15 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import rl "vendor:raylib"
 | 
			
		||||
import "core:fmt"
 | 
			
		||||
import "core:path/filepath"
 | 
			
		||||
import "core:strings"
 | 
			
		||||
import "ntween"
 | 
			
		||||
import rl "vendor:raylib"
 | 
			
		||||
 | 
			
		||||
vec3 :: [3]f32
 | 
			
		||||
vec3i :: [3]i32
 | 
			
		||||
vec2 :: [2]f32
 | 
			
		||||
vec2i :: [2]i32
 | 
			
		||||
vec3right := vec3{1, 0, 0}
 | 
			
		||||
vec3left := vec3{-1, 0, 0}
 | 
			
		||||
vec3up := vec3{0, 1, 0}
 | 
			
		||||
@ -17,55 +21,57 @@ vec3backward := vec3{0, 0, -1}
 | 
			
		||||
WSize := [2]f32{}
 | 
			
		||||
WSizei := [2]i32{}
 | 
			
		||||
 | 
			
		||||
WSizeLast := vec2i{}
 | 
			
		||||
 | 
			
		||||
WindowShouldExit := false
 | 
			
		||||
 | 
			
		||||
NeedTutorial := true
 | 
			
		||||
KeyboardOnly := false
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Overlay_Opacity : f32 = 0
 | 
			
		||||
Overlay_Opacity: f32 = 0
 | 
			
		||||
 | 
			
		||||
Resources :: struct {
 | 
			
		||||
    Fonts: struct {
 | 
			
		||||
        UI: rl.Font,
 | 
			
		||||
        Title: rl.Font,
 | 
			
		||||
    },
 | 
			
		||||
    Models: struct {
 | 
			
		||||
        PlayerModel: rl.Model,
 | 
			
		||||
        SnakeHeadTop: rl.Model,
 | 
			
		||||
        SnakeHeadJaw: rl.Model,
 | 
			
		||||
        SnakeBody: rl.Model,
 | 
			
		||||
        Background: rl.Model,
 | 
			
		||||
    },
 | 
			
		||||
    Sfx: struct {
 | 
			
		||||
        Drums: rl.Sound,
 | 
			
		||||
        Lightning: rl.Sound,
 | 
			
		||||
        LightningHit: rl.Sound,
 | 
			
		||||
        Rocket: rl.Sound,
 | 
			
		||||
        PlayerHit: rl.Sound,
 | 
			
		||||
        PlayerSwoosh: rl.Sound,
 | 
			
		||||
        PlayerDead: rl.Sound,
 | 
			
		||||
        SnakeGrowl: rl.Sound,
 | 
			
		||||
        SnakeRoarBlast: rl.Sound,
 | 
			
		||||
        SnakeEarthHit: rl.Sound,
 | 
			
		||||
        SnakeSegmentExplode: rl.Sound,
 | 
			
		||||
        SnakeBeam: rl.Sound,
 | 
			
		||||
    },
 | 
			
		||||
    Music: struct {
 | 
			
		||||
        First: rl.Music,
 | 
			
		||||
        Second: rl.Music,
 | 
			
		||||
    }
 | 
			
		||||
	Fonts:  struct {
 | 
			
		||||
		UI:    rl.Font,
 | 
			
		||||
		Title: rl.Font,
 | 
			
		||||
	},
 | 
			
		||||
	Models: struct {
 | 
			
		||||
		PlayerModel:  rl.Model,
 | 
			
		||||
		SnakeHeadTop: rl.Model,
 | 
			
		||||
		SnakeHeadJaw: rl.Model,
 | 
			
		||||
		SnakeBody:    rl.Model,
 | 
			
		||||
		Background:   rl.Model,
 | 
			
		||||
	},
 | 
			
		||||
	Sfx:    struct {
 | 
			
		||||
		Drums:               rl.Sound,
 | 
			
		||||
		Lightning:           rl.Sound,
 | 
			
		||||
		LightningHit:        rl.Sound,
 | 
			
		||||
		Rocket:              rl.Sound,
 | 
			
		||||
		PlayerHit:           rl.Sound,
 | 
			
		||||
		PlayerSwoosh:        rl.Sound,
 | 
			
		||||
		PlayerDead:          rl.Sound,
 | 
			
		||||
		SnakeGrowl:          rl.Sound,
 | 
			
		||||
		SnakeRoarBlast:      rl.Sound,
 | 
			
		||||
		SnakeEarthHit:       rl.Sound,
 | 
			
		||||
		SnakeSegmentExplode: rl.Sound,
 | 
			
		||||
		SnakeBeam:           rl.Sound,
 | 
			
		||||
	},
 | 
			
		||||
	Music:  struct {
 | 
			
		||||
		First:  rl.Music,
 | 
			
		||||
		Second: rl.Music,
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Res : Resources
 | 
			
		||||
Res: Resources
 | 
			
		||||
 | 
			
		||||
res_paths := map[typeid]string{
 | 
			
		||||
res_paths := map[typeid]string {
 | 
			
		||||
	rl.Music = "music",
 | 
			
		||||
	rl.Sound = "sfx",
 | 
			
		||||
	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})
 | 
			
		||||
	cstr := strings.clone_to_cstring(p)
 | 
			
		||||
	return cstr
 | 
			
		||||
@ -79,100 +85,121 @@ load_model :: proc(name: string) -> rl.Model {
 | 
			
		||||
 | 
			
		||||
load_sfx :: proc(name: string, volume: f32 = 1) -> rl.Sound {
 | 
			
		||||
	p := get_path(name, rl.Sound)
 | 
			
		||||
    snd := rl.LoadSound(p)
 | 
			
		||||
    rl.SetSoundVolume(snd, volume)
 | 
			
		||||
    return snd
 | 
			
		||||
	snd := rl.LoadSound(p)
 | 
			
		||||
	rl.SetSoundVolume(snd, volume)
 | 
			
		||||
	return snd
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
load_music :: proc(name: string, volume: f32 = 1) -> rl.Music {
 | 
			
		||||
	p := get_path(name, rl.Music)
 | 
			
		||||
    snd := rl.LoadMusicStream(p)
 | 
			
		||||
    rl.SetMusicVolume(snd, volume)
 | 
			
		||||
    return snd
 | 
			
		||||
	snd := rl.LoadMusicStream(p)
 | 
			
		||||
	rl.SetMusicVolume(snd, volume)
 | 
			
		||||
	return snd
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
current_music : rl.Music
 | 
			
		||||
current_music: rl.Music
 | 
			
		||||
 | 
			
		||||
change_track :: proc(music: rl.Music) {
 | 
			
		||||
    rl.StopMusicStream(current_music)
 | 
			
		||||
    current_music = music
 | 
			
		||||
    rl.PlayMusicStream(current_music)
 | 
			
		||||
	rl.StopMusicStream(current_music)
 | 
			
		||||
	current_music = music
 | 
			
		||||
	rl.PlayMusicStream(current_music)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Cursor : rl.Texture
 | 
			
		||||
Cursor: rl.Texture
 | 
			
		||||
load_resources :: proc() {
 | 
			
		||||
    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.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.Models = {
 | 
			
		||||
    	PlayerModel = load_model("chariot.glb"),
 | 
			
		||||
    	SnakeHeadTop = load_model("snake_head_top.obj"),
 | 
			
		||||
    	SnakeHeadJaw = load_model("snake_jaw.obj"),
 | 
			
		||||
    	SnakeBody = load_model("snake_body.obj"),
 | 
			
		||||
    	Background = load_model("background.obj"),
 | 
			
		||||
		PlayerModel  = load_model("chariot.glb"),
 | 
			
		||||
		SnakeHeadTop = load_model("snake_head_top.obj"),
 | 
			
		||||
		SnakeHeadJaw = load_model("snake_jaw.obj"),
 | 
			
		||||
		SnakeBody    = load_model("snake_body.obj"),
 | 
			
		||||
		Background   = load_model("background.obj"),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    Res.Sfx = {
 | 
			
		||||
		Drums = load_sfx("drums.ogg"),
 | 
			
		||||
    	Lightning = load_sfx("lightning.ogg", 0.5),
 | 
			
		||||
    	LightningHit = load_sfx("lightning-hit.ogg", 0.3),
 | 
			
		||||
    	Rocket = load_sfx("rocket.ogg", 0.5),
 | 
			
		||||
    	PlayerHit = load_sfx("player-hit.ogg", 0.5),
 | 
			
		||||
    	PlayerSwoosh = load_sfx("player-swoosh.ogg"),
 | 
			
		||||
    	PlayerDead = load_sfx("player-dead.ogg"),
 | 
			
		||||
    	SnakeGrowl = load_sfx("snake-growl.ogg", 0.7),
 | 
			
		||||
    	SnakeRoarBlast = load_sfx("snake-roar-blast.ogg", 0.8),
 | 
			
		||||
    	SnakeBeam = load_sfx("snake-beam.ogg"),
 | 
			
		||||
    	SnakeSegmentExplode = load_sfx("snake-segment-explode.ogg", 0.8),
 | 
			
		||||
    	SnakeEarthHit = load_sfx("snake-earth-hit.ogg", 0.6),
 | 
			
		||||
	Res.Sfx = {
 | 
			
		||||
		Drums               = load_sfx("drums.ogg"),
 | 
			
		||||
		Lightning           = load_sfx("lightning.ogg", 0.5),
 | 
			
		||||
		LightningHit        = load_sfx("lightning-hit.ogg", 0.3),
 | 
			
		||||
		Rocket              = load_sfx("rocket.ogg", 0.5),
 | 
			
		||||
		PlayerHit           = load_sfx("player-hit.ogg", 0.5),
 | 
			
		||||
		PlayerSwoosh        = load_sfx("player-swoosh.ogg"),
 | 
			
		||||
		PlayerDead          = load_sfx("player-dead.ogg"),
 | 
			
		||||
		SnakeGrowl          = load_sfx("snake-growl.ogg", 0.7),
 | 
			
		||||
		SnakeRoarBlast      = load_sfx("snake-roar-blast.ogg", 0.8),
 | 
			
		||||
		SnakeBeam           = load_sfx("snake-beam.ogg"),
 | 
			
		||||
		SnakeSegmentExplode = load_sfx("snake-segment-explode.ogg", 0.8),
 | 
			
		||||
		SnakeEarthHit       = load_sfx("snake-earth-hit.ogg", 0.6),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    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.First = load_music("alexander-nakarada-mjolnir.mp3", 0.7)
 | 
			
		||||
	Res.Music.Second = load_music("alexander-nakarada-the-northern-path.mp3", 0.7)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Fullscreen := true
 | 
			
		||||
f32_tweens: ntween.Tween_Map(f32)
 | 
			
		||||
vec2_tweens: ntween.Tween_Map(vec2)
 | 
			
		||||
vec3_tweens: ntween.Tween_Map(vec3)
 | 
			
		||||
 | 
			
		||||
main :: proc() {
 | 
			
		||||
    rl.SetConfigFlags(rl.ConfigFlags{.MSAA_4X_HINT, .FULLSCREEN_MODE, .VSYNC_HINT, .WINDOW_RESIZABLE})
 | 
			
		||||
    
 | 
			
		||||
    rl.InitWindow(0, 0, "Ragnarøkkr")
 | 
			
		||||
    rl.InitAudioDevice()
 | 
			
		||||
    rl.SetWindowMinSize(800, 480)
 | 
			
		||||
	f32_tweens = ntween.init(f32)
 | 
			
		||||
	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.HideCursor()
 | 
			
		||||
    Cursor = rl.LoadTexture("./assets/gfx/crosshair.png")
 | 
			
		||||
    load_resources()
 | 
			
		||||
	rl.InitWindow(800, 600, "Ragnarøkkr")
 | 
			
		||||
	rl.InitAudioDevice()
 | 
			
		||||
	rl.SetWindowMinSize(800, 600)
 | 
			
		||||
 | 
			
		||||
    WSizei = {rl.GetScreenWidth(), rl.GetScreenHeight()}
 | 
			
		||||
    WSize = {f32(WSizei.x), f32(WSizei.y)}
 | 
			
		||||
	rl.HideCursor()
 | 
			
		||||
	Cursor = rl.LoadTexture("./assets/gfx/crosshair.png")
 | 
			
		||||
	load_resources()
 | 
			
		||||
 | 
			
		||||
    game := game_init()
 | 
			
		||||
    stack_push(game)
 | 
			
		||||
    menu := menu_init(game)
 | 
			
		||||
    stack_push(menu)
 | 
			
		||||
	WSizei = {rl.GetScreenWidth(), rl.GetScreenHeight()}
 | 
			
		||||
	WSize = {f32(WSizei.x), f32(WSizei.y)}
 | 
			
		||||
 | 
			
		||||
    for !WindowShouldExit {
 | 
			
		||||
        if rl.IsWindowResized() {
 | 
			
		||||
            WSizei = {rl.GetScreenWidth(), rl.GetScreenHeight()}
 | 
			
		||||
            WSize = {f32(WSizei.x), f32(WSizei.y)}
 | 
			
		||||
        }
 | 
			
		||||
	game := game_init()
 | 
			
		||||
	stack_push(game)
 | 
			
		||||
	menu := menu_init(game)
 | 
			
		||||
	stack_push(menu)
 | 
			
		||||
 | 
			
		||||
        rl.UpdateMusicStream(current_music)
 | 
			
		||||
	for !WindowShouldExit {
 | 
			
		||||
		if rl.IsWindowResized() {
 | 
			
		||||
			WSizei = {rl.GetScreenWidth(), rl.GetScreenHeight()}
 | 
			
		||||
			WSize = {f32(WSizei.x), f32(WSizei.y)}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        state := stack_top() 
 | 
			
		||||
        delta := rl.GetFrameTime()
 | 
			
		||||
        timers_process(delta)
 | 
			
		||||
        tweens_process(delta)
 | 
			
		||||
        state->update(delta)
 | 
			
		||||
		rl.UpdateMusicStream(current_music)
 | 
			
		||||
 | 
			
		||||
        rl.BeginDrawing()
 | 
			
		||||
            rl.ClearBackground(rl.SKYBLUE)
 | 
			
		||||
            state->draw()
 | 
			
		||||
		state := stack_top()
 | 
			
		||||
		delta := rl.GetFrameTime()
 | 
			
		||||
		timers_process(delta)
 | 
			
		||||
		ntween.process(&f32_tweens, delta)
 | 
			
		||||
		ntween.process(&vec2_tweens, delta)
 | 
			
		||||
		ntween.process(&vec3_tweens, delta)
 | 
			
		||||
		state->update(delta)
 | 
			
		||||
 | 
			
		||||
            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.BeginDrawing()
 | 
			
		||||
		rl.ClearBackground(rl.SKYBLUE)
 | 
			
		||||
		state->draw()
 | 
			
		||||
 | 
			
		||||
		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()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Fullscreen := false
 | 
			
		||||
 | 
			
		||||
toggle_fullscreen :: proc() {
 | 
			
		||||
	monitor := rl.GetCurrentMonitor()
 | 
			
		||||
	rl.ToggleBorderlessWindowed()
 | 
			
		||||
	WSizei = {rl.GetScreenWidth(), rl.GetScreenHeight()}
 | 
			
		||||
	WSize = {f32(WSizei.x), f32(WSizei.y)}
 | 
			
		||||
	Fullscreen = !Fullscreen
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	//	rl.ToggleFullscreen()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -75,8 +75,8 @@ menu_button_pressed :: proc(state: ^GameState, el: Menu_Buttons) {
 | 
			
		||||
			KeyboardOnly = !KeyboardOnly
 | 
			
		||||
			NeedTutorial = true
 | 
			
		||||
		case .FULLSCREEN:
 | 
			
		||||
			rl.ToggleFullscreen()
 | 
			
		||||
			Fullscreen = rl.IsWindowFullscreen()
 | 
			
		||||
			toggle_fullscreen()
 | 
			
		||||
//			Fullscreen = rl.IsWindowFullscreen()
 | 
			
		||||
 | 
			
		||||
		case .EXIT:
 | 
			
		||||
			WindowShouldExit = true
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,9 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import rl "vendor:raylib"
 | 
			
		||||
import "core:math/ease"
 | 
			
		||||
import "core:fmt"
 | 
			
		||||
import "core:math/ease"
 | 
			
		||||
import "ntween"
 | 
			
		||||
import rl "vendor:raylib"
 | 
			
		||||
 | 
			
		||||
MenuItemType :: enum {
 | 
			
		||||
	NONE,
 | 
			
		||||
@ -11,28 +12,28 @@ MenuItemType :: enum {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BoolStrings := map[bool]cstring {
 | 
			
		||||
	true = "вкл",
 | 
			
		||||
	false = "выкл"
 | 
			
		||||
	true  = "вкл",
 | 
			
		||||
	false = "выкл",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MenuItem :: struct{
 | 
			
		||||
	text: cstring,
 | 
			
		||||
MenuItem :: struct {
 | 
			
		||||
	text:  cstring,
 | 
			
		||||
	param: rawptr,
 | 
			
		||||
	type: MenuItemType,
 | 
			
		||||
	type:  MenuItemType,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MenuList :: struct($T: typeid) {
 | 
			
		||||
	state: ^GameState,
 | 
			
		||||
	position: vec2,
 | 
			
		||||
	line_size: f32,
 | 
			
		||||
	font_size: f32,
 | 
			
		||||
	state:          ^GameState,
 | 
			
		||||
	position:       vec2,
 | 
			
		||||
	line_size:      f32,
 | 
			
		||||
	font_size:      f32,
 | 
			
		||||
	active_element: T,
 | 
			
		||||
	active_marker: vec2,
 | 
			
		||||
	tween: ^Tween,
 | 
			
		||||
	elements: ^[T]MenuItem,
 | 
			
		||||
	menu_pressed: proc(state: ^GameState, element: T),
 | 
			
		||||
	background: rl.Color,
 | 
			
		||||
	mouse_pos: vec2,
 | 
			
		||||
	active_marker:  vec2,
 | 
			
		||||
	tween:          ^ntween.Tween(f32),
 | 
			
		||||
	elements:       ^[T]MenuItem,
 | 
			
		||||
	menu_pressed:   proc(state: ^GameState, element: T),
 | 
			
		||||
	background:     rl.Color,
 | 
			
		||||
	mouse_pos:      vec2,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -46,14 +47,12 @@ menu_list_update :: proc(list: ^MenuList($T)) {
 | 
			
		||||
	list.mouse_pos = rl.GetMousePosition()
 | 
			
		||||
 | 
			
		||||
	size := menu_list_get_size(list)
 | 
			
		||||
	if rl.CheckCollisionPointRec(list.mouse_pos, rl.Rectangle{
 | 
			
		||||
		x = list.position.x,
 | 
			
		||||
		y = list.position.y,
 | 
			
		||||
		width = size.x,
 | 
			
		||||
		height = size.y,
 | 
			
		||||
	}) {
 | 
			
		||||
	if rl.CheckCollisionPointRec(
 | 
			
		||||
		list.mouse_pos,
 | 
			
		||||
		rl.Rectangle{x = list.position.x, y = list.position.y, width = size.x, height = size.y},
 | 
			
		||||
	) {
 | 
			
		||||
		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)
 | 
			
		||||
		}
 | 
			
		||||
		if rl.IsMouseButtonPressed(rl.MouseButton.LEFT) {
 | 
			
		||||
@ -63,7 +62,6 @@ menu_list_update :: proc(list: ^MenuList($T)) {
 | 
			
		||||
	last_mouse_pos = list.mouse_pos
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	if rl.IsKeyPressed(rl.KeyboardKey.DOWN) {
 | 
			
		||||
		cur_element += 1
 | 
			
		||||
	}
 | 
			
		||||
@ -71,13 +69,14 @@ menu_list_update :: proc(list: ^MenuList($T)) {
 | 
			
		||||
		cur_element -= 1
 | 
			
		||||
	}
 | 
			
		||||
	if prev_element != cur_element {
 | 
			
		||||
		if cur_element < 0 { cur_element = len(T) -1 }
 | 
			
		||||
		if cur_element == len(T) { cur_element = 0 }
 | 
			
		||||
		if cur_element < 0 {cur_element = len(T) - 1}
 | 
			
		||||
		if cur_element == len(T) {cur_element = 0}
 | 
			
		||||
		list.active_element = cast(T)cur_element
 | 
			
		||||
		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,
 | 
			
		||||
			f32(list.active_element) * list.line_size,
 | 
			
		||||
			0.25,
 | 
			
		||||
@ -94,10 +93,17 @@ menu_list_draw :: proc(list: ^MenuList($T)) {
 | 
			
		||||
		size := menu_list_get_size(list)
 | 
			
		||||
		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 {
 | 
			
		||||
		pos := list.position + {0, f32(i) * list.line_size}
 | 
			
		||||
		text := el.text 
 | 
			
		||||
		text := el.text
 | 
			
		||||
		if el.type == .BOOL {
 | 
			
		||||
			param := transmute(^bool)el.param
 | 
			
		||||
			value := param^
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								ntween
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								ntween
									
									
									
									
									
										Submodule
									
								
							 Submodule ntween added at 7136c68f3e
									
								
							
							
								
								
									
										78
									
								
								pause.odin
									
									
									
									
									
								
							
							
						
						
									
										78
									
								
								pause.odin
									
									
									
									
									
								
							@ -1,51 +1,50 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import rl "vendor:raylib"
 | 
			
		||||
import "core:math/ease"
 | 
			
		||||
import "ntween"
 | 
			
		||||
import rl "vendor:raylib"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Pause_Buttons :: enum {
 | 
			
		||||
	CONTINUE,
 | 
			
		||||
	EXIT
 | 
			
		||||
	EXIT,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pause_strings := [Pause_Buttons]cstring {
 | 
			
		||||
	.CONTINUE = "Продолжить",
 | 
			
		||||
	.EXIT = "Прервать игру"
 | 
			
		||||
	.EXIT     = "Прервать игру",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pause_items := [Pause_Buttons]MenuItem {
 | 
			
		||||
	.CONTINUE = {text = pause_strings[.CONTINUE]},
 | 
			
		||||
	.EXIT = {text = pause_strings[.EXIT]}
 | 
			
		||||
	.EXIT = {text = pause_strings[.EXIT]},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Pause :: struct {
 | 
			
		||||
	using state: GameState,
 | 
			
		||||
 | 
			
		||||
    active: bool,
 | 
			
		||||
	list: MenuList(Pause_Buttons),
 | 
			
		||||
 | 
			
		||||
	active:      bool,
 | 
			
		||||
	list:        MenuList(Pause_Buttons),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pause_init :: proc(prev: ^GameState = nil) -> ^GameState {
 | 
			
		||||
	state := new(Pause)
 | 
			
		||||
	state.variant = state
 | 
			
		||||
	state.list = MenuList(Pause_Buttons){
 | 
			
		||||
		state = state,
 | 
			
		||||
		position = {-300, WSize.y / 2},
 | 
			
		||||
		line_size = 60,
 | 
			
		||||
		font_size = 48,
 | 
			
		||||
		elements = &pause_items,
 | 
			
		||||
	state.list = MenuList(Pause_Buttons) {
 | 
			
		||||
		state        = state,
 | 
			
		||||
		position     = {-300, WSize.y / 2},
 | 
			
		||||
		line_size    = 60,
 | 
			
		||||
		font_size    = 48,
 | 
			
		||||
		elements     = &pause_items,
 | 
			
		||||
		menu_pressed = pause_button_pressed,
 | 
			
		||||
		background = rl.Color{50, 10, 110, 0}
 | 
			
		||||
		background   = rl.Color{50, 10, 110, 0},
 | 
			
		||||
	}
 | 
			
		||||
	state.update = pause_update
 | 
			
		||||
	state.draw = pause_draw 
 | 
			
		||||
	state.draw = pause_draw
 | 
			
		||||
	state.free = pause_free
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
@ -53,20 +52,27 @@ pause_init :: proc(prev: ^GameState = nil) -> ^GameState {
 | 
			
		||||
pause_update :: proc(state: ^GameState, delta: f32) {
 | 
			
		||||
	pause := transmute(^Pause)state
 | 
			
		||||
	pause.list.position.y = WSize.y / 2
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	menu_list_update(&pause.list)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pause_button_pressed :: proc(state: ^GameState, el: Pause_Buttons) {
 | 
			
		||||
	pause := transmute(^Pause)state
 | 
			
		||||
	if !pause.active { return }
 | 
			
		||||
	switch el  {
 | 
			
		||||
		case .CONTINUE:
 | 
			
		||||
			stack_pop()
 | 
			
		||||
		case .EXIT:
 | 
			
		||||
			pause.active = false
 | 
			
		||||
			rl.StopMusicStream(current_music)
 | 
			
		||||
			tween_to(&Overlay_Opacity, 1.0, 0.5, ease.Ease.Cubic_Out, state, proc(data: rawptr) {
 | 
			
		||||
	if !pause.active {return}
 | 
			
		||||
	switch el {
 | 
			
		||||
	case .CONTINUE:
 | 
			
		||||
		stack_pop()
 | 
			
		||||
	case .EXIT:
 | 
			
		||||
		pause.active = false
 | 
			
		||||
		rl.StopMusicStream(current_music)
 | 
			
		||||
		ntween.animate(
 | 
			
		||||
			&f32_tweens,
 | 
			
		||||
			&Overlay_Opacity,
 | 
			
		||||
			1.0,
 | 
			
		||||
			0.5,
 | 
			
		||||
			ease.Ease.Cubic_Out,
 | 
			
		||||
			state,
 | 
			
		||||
			proc(data: rawptr) {
 | 
			
		||||
				state := transmute(^GameState)data
 | 
			
		||||
				stack_pop()
 | 
			
		||||
				game := transmute(^Game)stack_top()
 | 
			
		||||
@ -74,21 +80,31 @@ pause_button_pressed :: proc(state: ^GameState, el: Pause_Buttons) {
 | 
			
		||||
				menu := menu_init(game)
 | 
			
		||||
				stack_push(menu)
 | 
			
		||||
				//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 := transmute(^Pause)state
 | 
			
		||||
 | 
			
		||||
    pause.previous.draw(pause.previous)
 | 
			
		||||
	pause.previous.draw(pause.previous)
 | 
			
		||||
 | 
			
		||||
	TitleFontSize :: 96
 | 
			
		||||
	TitleSpacing :: 3
 | 
			
		||||
	TitleText :: "Ragnarøkkr"
 | 
			
		||||
	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)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										482
									
								
								player.odin
									
									
									
									
									
								
							
							
						
						
									
										482
									
								
								player.odin
									
									
									
									
									
								
							@ -1,270 +1,280 @@
 | 
			
		||||
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 "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
 | 
			
		||||
// PlayerAnimsCount : i32
 | 
			
		||||
 | 
			
		||||
Player :: struct {
 | 
			
		||||
    pos: vec3,
 | 
			
		||||
    vel: vec3,
 | 
			
		||||
    dir: f32,
 | 
			
		||||
    radius: f32,
 | 
			
		||||
    thrust: f32,
 | 
			
		||||
    max_speed: f32,
 | 
			
		||||
    rolling: f32,
 | 
			
		||||
    charge: f32,
 | 
			
		||||
    is_dodging: bool,
 | 
			
		||||
    can_dodge: bool,
 | 
			
		||||
    can_shoot: bool,
 | 
			
		||||
    is_invulnerable: bool,
 | 
			
		||||
    is_dead: bool,
 | 
			
		||||
    intro_timer: f32,
 | 
			
		||||
    power: f32,
 | 
			
		||||
    reload_timer: f32,
 | 
			
		||||
    reloading: bool,
 | 
			
		||||
    // animation: rl.ModelAnimation,
 | 
			
		||||
    // animTime: f32,
 | 
			
		||||
    // animFrame: i32,
 | 
			
		||||
	pos:             vec3,
 | 
			
		||||
	vel:             vec3,
 | 
			
		||||
	dir:             f32,
 | 
			
		||||
	radius:          f32,
 | 
			
		||||
	thrust:          f32,
 | 
			
		||||
	max_speed:       f32,
 | 
			
		||||
	rolling:         f32,
 | 
			
		||||
	charge:          f32,
 | 
			
		||||
	is_dodging:      bool,
 | 
			
		||||
	can_dodge:       bool,
 | 
			
		||||
	can_shoot:       bool,
 | 
			
		||||
	is_invulnerable: bool,
 | 
			
		||||
	is_dead:         bool,
 | 
			
		||||
	intro_timer:     f32,
 | 
			
		||||
	power:           f32,
 | 
			
		||||
	reload_timer:    f32,
 | 
			
		||||
	reloading:       bool,
 | 
			
		||||
	// animation: rl.ModelAnimation,
 | 
			
		||||
	// animTime: f32,
 | 
			
		||||
	// animFrame: i32,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
player_spawn :: proc(position: vec3) -> Player {
 | 
			
		||||
 | 
			
		||||
    // PlayerAnims = rl.LoadModelAnimations(PlayerModelPath, &PlayerAnimsCount)
 | 
			
		||||
    return Player{
 | 
			
		||||
        pos = position,
 | 
			
		||||
        radius = 1,
 | 
			
		||||
        max_speed = 40,
 | 
			
		||||
        dir = 0,
 | 
			
		||||
        vel = {-80, 0, 0},
 | 
			
		||||
        can_dodge = true,
 | 
			
		||||
        can_shoot = true,
 | 
			
		||||
        intro_timer = 2,
 | 
			
		||||
        power = 100,
 | 
			
		||||
    }
 | 
			
		||||
	// PlayerAnims = rl.LoadModelAnimations(PlayerModelPath, &PlayerAnimsCount)
 | 
			
		||||
	return Player {
 | 
			
		||||
		pos = position,
 | 
			
		||||
		radius = 1,
 | 
			
		||||
		max_speed = 40,
 | 
			
		||||
		dir = 0,
 | 
			
		||||
		vel = {-80, 0, 0},
 | 
			
		||||
		can_dodge = true,
 | 
			
		||||
		can_shoot = true,
 | 
			
		||||
		intro_timer = 2,
 | 
			
		||||
		power = 100,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
player_update :: proc(player: ^Player, game: ^Game, delta: f32) {
 | 
			
		||||
    using player
 | 
			
		||||
	using player
 | 
			
		||||
 | 
			
		||||
    if intro_timer > 0 {
 | 
			
		||||
        intro_timer -= delta
 | 
			
		||||
    }
 | 
			
		||||
	if intro_timer > 0 {
 | 
			
		||||
		intro_timer -= delta
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    mouse_ray := rl.GetMouseRay(rl.GetMousePosition(), game.camera)
 | 
			
		||||
    mouse_pos : vec3
 | 
			
		||||
    hit := rl.GetRayCollisionQuad(mouse_ray,
 | 
			
		||||
        {-1000, -1000, 0},
 | 
			
		||||
        {-1000, 1000, 0},
 | 
			
		||||
        {1000, 1000, 0},
 | 
			
		||||
        {1000, -1000, 0}
 | 
			
		||||
    )
 | 
			
		||||
    if hit.hit {
 | 
			
		||||
        mouse_pos = hit.point
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    mouse_diff := mouse_pos - pos
 | 
			
		||||
    mouse_angle := math.atan2(-mouse_diff.y, mouse_diff.x)
 | 
			
		||||
 | 
			
		||||
    if !is_dead {
 | 
			
		||||
        pos += vel * delta 
 | 
			
		||||
        if pos.y < radius {
 | 
			
		||||
            pos.y = radius
 | 
			
		||||
            vel.y = - vel.y
 | 
			
		||||
        }
 | 
			
		||||
        if !is_dodging {
 | 
			
		||||
            dir_vector : vec3
 | 
			
		||||
            if intro_timer <= 0 {
 | 
			
		||||
                thrust_key := rl.KeyboardKey.W
 | 
			
		||||
                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
 | 
			
		||||
                if rl.IsKeyDown(thrust_key) {
 | 
			
		||||
                    thrust = 110
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                thrust = 110
 | 
			
		||||
                dir_vector = vec3left
 | 
			
		||||
                dir = math.atan2(-dir_vector.y, dir_vector.x)
 | 
			
		||||
            }
 | 
			
		||||
            if thrust > 0 {
 | 
			
		||||
                roll := -math.PI / 2 + math.cos(dir) * math.PI / 2
 | 
			
		||||
                vel = rl.Vector3MoveTowards(vel, dir_vector * max_speed, thrust * delta)
 | 
			
		||||
                offset := rl.Vector3RotateByAxisAngle(vec3backward, vec3right, roll) * 2.6
 | 
			
		||||
                offset = rl.Vector3RotateByAxisAngle(offset, vec3backward, dir)
 | 
			
		||||
                pl := pos + offset
 | 
			
		||||
                pr := pos - offset
 | 
			
		||||
                trail(pl, 1, rand.float32_range(1.7, 3.5))
 | 
			
		||||
                trail(pr, 1, rand.float32_range(1.7, 3.5))
 | 
			
		||||
            }             
 | 
			
		||||
        }
 | 
			
		||||
        if thrust == 0 {
 | 
			
		||||
            vel = rl.Vector3MoveTowards(vel, {0, -30, 0}, 20 * delta)
 | 
			
		||||
            rl.StopSound(Res.Sfx.Rocket)
 | 
			
		||||
        } else {
 | 
			
		||||
            if !rl.IsSoundPlaying(Res.Sfx.Rocket) && !is_dodging {
 | 
			
		||||
                rl.PlaySound(Res.Sfx.Rocket)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
	mouse_ray := rl.GetMouseRay(rl.GetMousePosition(), game.camera)
 | 
			
		||||
	mouse_pos: vec3
 | 
			
		||||
	hit := rl.GetRayCollisionQuad(
 | 
			
		||||
		mouse_ray,
 | 
			
		||||
		{-1000, -1000, 0},
 | 
			
		||||
		{-1000, 1000, 0},
 | 
			
		||||
		{1000, 1000, 0},
 | 
			
		||||
		{1000, -1000, 0},
 | 
			
		||||
	)
 | 
			
		||||
	if hit.hit {
 | 
			
		||||
		mouse_pos = hit.point
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        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)
 | 
			
		||||
        }
 | 
			
		||||
	mouse_diff := mouse_pos - pos
 | 
			
		||||
	mouse_angle := math.atan2(-mouse_diff.y, mouse_diff.x)
 | 
			
		||||
 | 
			
		||||
        if dodge && can_dodge && intro_timer <= 0 {
 | 
			
		||||
            is_dodging = true
 | 
			
		||||
            can_dodge = false
 | 
			
		||||
            rl.StopSound(Res.Sfx.Rocket)
 | 
			
		||||
            rl.PlaySound(Res.Sfx.PlayerSwoosh)
 | 
			
		||||
            tween_to(&player.rolling, math.PI*2, 0.42, ease.Ease.Quadratic_Out)
 | 
			
		||||
            timer_start(0.45, player, proc(data: rawptr) {
 | 
			
		||||
                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
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
	if !is_dead {
 | 
			
		||||
		pos += vel * delta
 | 
			
		||||
		if pos.y < radius {
 | 
			
		||||
			pos.y = radius
 | 
			
		||||
			vel.y = -vel.y
 | 
			
		||||
		}
 | 
			
		||||
		if !is_dodging {
 | 
			
		||||
			dir_vector: vec3
 | 
			
		||||
			if intro_timer <= 0 {
 | 
			
		||||
				thrust_key := rl.KeyboardKey.W
 | 
			
		||||
				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
 | 
			
		||||
				if rl.IsKeyDown(thrust_key) {
 | 
			
		||||
					thrust = 110
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				thrust = 110
 | 
			
		||||
				dir_vector = vec3left
 | 
			
		||||
				dir = math.atan2(-dir_vector.y, dir_vector.x)
 | 
			
		||||
			}
 | 
			
		||||
			if thrust > 0 {
 | 
			
		||||
				roll := -math.PI / 2 + math.cos(dir) * math.PI / 2
 | 
			
		||||
				vel = rl.Vector3MoveTowards(vel, dir_vector * max_speed, thrust * delta)
 | 
			
		||||
				offset := rl.Vector3RotateByAxisAngle(vec3backward, vec3right, roll) * 2.6
 | 
			
		||||
				offset = rl.Vector3RotateByAxisAngle(offset, vec3backward, dir)
 | 
			
		||||
				pl := pos + offset
 | 
			
		||||
				pr := pos - offset
 | 
			
		||||
				trail(pl, 1, rand.float32_range(1.7, 3.5))
 | 
			
		||||
				trail(pr, 1, rand.float32_range(1.7, 3.5))
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if thrust == 0 {
 | 
			
		||||
			vel = rl.Vector3MoveTowards(vel, {0, -30, 0}, 20 * delta)
 | 
			
		||||
			rl.StopSound(Res.Sfx.Rocket)
 | 
			
		||||
		} else {
 | 
			
		||||
			if !rl.IsSoundPlaying(Res.Sfx.Rocket) && !is_dodging {
 | 
			
		||||
				rl.PlaySound(Res.Sfx.Rocket)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        // player.animation = PlayerAnims[1]
 | 
			
		||||
        // player.animTime += delta
 | 
			
		||||
        // player.animFrame = i32(player.animTime * 60) % player.animation.frameCount
 | 
			
		||||
        // rl.UpdateModelAnimation(PlayerModel, player.animation, player.animFrame)
 | 
			
		||||
        shooting := shoot && !is_dodging && intro_timer <= 0 && !reloading
 | 
			
		||||
        if shooting {
 | 
			
		||||
            if !rl.IsSoundPlaying(Res.Sfx.Lightning) {
 | 
			
		||||
                rl.PlaySound(Res.Sfx.Lightning)
 | 
			
		||||
            }
 | 
			
		||||
            if can_shoot {
 | 
			
		||||
                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)
 | 
			
		||||
                append(&game.bullets, b)
 | 
			
		||||
                can_shoot = false
 | 
			
		||||
                timer_start(0.07, player, proc(data: rawptr) {
 | 
			
		||||
                    player := transmute(^Player)data
 | 
			
		||||
                    player.can_shoot = true
 | 
			
		||||
                })
 | 
			
		||||
                player.power -= 2
 | 
			
		||||
                player.reload_timer = 1
 | 
			
		||||
                if player.power <= 0 {
 | 
			
		||||
                    player.reloading = true
 | 
			
		||||
                    player.power = 0
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            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
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
		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)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
    got_hit := false
 | 
			
		||||
		if dodge && can_dodge && intro_timer <= 0 {
 | 
			
		||||
			is_dodging = true
 | 
			
		||||
			can_dodge = false
 | 
			
		||||
			rl.StopSound(Res.Sfx.Rocket)
 | 
			
		||||
			rl.PlaySound(Res.Sfx.PlayerSwoosh)
 | 
			
		||||
			ntween.animate(
 | 
			
		||||
				&f32_tweens,
 | 
			
		||||
				&player.rolling,
 | 
			
		||||
				math.PI * 2,
 | 
			
		||||
				0.42,
 | 
			
		||||
				ease.Ease.Quadratic_Out,
 | 
			
		||||
			)
 | 
			
		||||
			timer_start(0.45, player, proc(data: rawptr) {
 | 
			
		||||
				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
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
    hit: if !is_invulnerable && !is_dodging && !is_dead {
 | 
			
		||||
        if rl.CheckCollisionCircles(pos.xy, radius, Head.pos.xy, Head.radius) {
 | 
			
		||||
            got_hit = true
 | 
			
		||||
            break hit
 | 
			
		||||
        }
 | 
			
		||||
        ray := rl.Ray{
 | 
			
		||||
            position = Head.pos,
 | 
			
		||||
            direction = get_vec_from_angle(Head.dir)
 | 
			
		||||
        }
 | 
			
		||||
        if Head.is_shooting && rl.GetRayCollisionSphere(ray, pos, radius + 3).hit {
 | 
			
		||||
            got_hit = true
 | 
			
		||||
            break hit
 | 
			
		||||
        }
 | 
			
		||||
        for segment in Segments {
 | 
			
		||||
            if rl.CheckCollisionCircles(pos.xy, radius, segment.pos.xy, radius) {
 | 
			
		||||
                got_hit = true
 | 
			
		||||
                break
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if rl.IsKeyPressed(rl.KeyboardKey.M) {
 | 
			
		||||
        got_hit = true
 | 
			
		||||
    }
 | 
			
		||||
		// player.animation = PlayerAnims[1]
 | 
			
		||||
		// player.animTime += delta
 | 
			
		||||
		// player.animFrame = i32(player.animTime * 60) % player.animation.frameCount
 | 
			
		||||
		// rl.UpdateModelAnimation(PlayerModel, player.animation, player.animFrame)
 | 
			
		||||
		shooting := shoot && !is_dodging && intro_timer <= 0 && !reloading
 | 
			
		||||
		if shooting {
 | 
			
		||||
			if !rl.IsSoundPlaying(Res.Sfx.Lightning) {
 | 
			
		||||
				rl.PlaySound(Res.Sfx.Lightning)
 | 
			
		||||
			}
 | 
			
		||||
			if can_shoot {
 | 
			
		||||
				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,
 | 
			
		||||
				)
 | 
			
		||||
				append(&game.bullets, b)
 | 
			
		||||
				can_shoot = false
 | 
			
		||||
				timer_start(0.07, player, proc(data: rawptr) {
 | 
			
		||||
					player := transmute(^Player)data
 | 
			
		||||
					player.can_shoot = true
 | 
			
		||||
				})
 | 
			
		||||
				player.power -= 2
 | 
			
		||||
				player.reload_timer = 1
 | 
			
		||||
				if player.power <= 0 {
 | 
			
		||||
					player.reloading = true
 | 
			
		||||
					player.power = 0
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			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
 | 
			
		||||
 | 
			
		||||
	hit: if !is_invulnerable && !is_dodging && !is_dead {
 | 
			
		||||
		if rl.CheckCollisionCircles(pos.xy, radius, Head.pos.xy, Head.radius) {
 | 
			
		||||
			got_hit = true
 | 
			
		||||
			break hit
 | 
			
		||||
		}
 | 
			
		||||
		ray := rl.Ray {
 | 
			
		||||
			position  = Head.pos,
 | 
			
		||||
			direction = get_vec_from_angle(Head.dir),
 | 
			
		||||
		}
 | 
			
		||||
		if Head.is_shooting && rl.GetRayCollisionSphere(ray, pos, radius + 3).hit {
 | 
			
		||||
			got_hit = true
 | 
			
		||||
			break hit
 | 
			
		||||
		}
 | 
			
		||||
		for segment in Segments {
 | 
			
		||||
			if rl.CheckCollisionCircles(pos.xy, radius, segment.pos.xy, radius) {
 | 
			
		||||
				got_hit = true
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if rl.IsKeyPressed(rl.KeyboardKey.M) {
 | 
			
		||||
		got_hit = true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if got_hit {
 | 
			
		||||
		game.health -= 10
 | 
			
		||||
		rl.PlaySound(Res.Sfx.PlayerHit)
 | 
			
		||||
		is_invulnerable = true
 | 
			
		||||
		timer_start(1, player, proc(data: rawptr) {
 | 
			
		||||
			plr := transmute(^Player)data
 | 
			
		||||
			plr.is_invulnerable = false
 | 
			
		||||
		})
 | 
			
		||||
		if game.health <= 0 && !is_dead {
 | 
			
		||||
			is_dead = true
 | 
			
		||||
			explode(pos, 10, 0.8, rl.WHITE)
 | 
			
		||||
			rl.StopMusicStream(current_music)
 | 
			
		||||
			rl.PlaySound(Res.Sfx.PlayerDead)
 | 
			
		||||
			timer_start(3, game, proc(data: rawptr) {
 | 
			
		||||
				state := transmute(^Game)data
 | 
			
		||||
				screen := gameover_init(state)
 | 
			
		||||
				stack_push(screen)
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    if got_hit {
 | 
			
		||||
        game.health -= 10
 | 
			
		||||
        rl.PlaySound(Res.Sfx.PlayerHit)
 | 
			
		||||
        is_invulnerable = true
 | 
			
		||||
        timer_start(1, player, proc(data: rawptr) {
 | 
			
		||||
            plr := transmute(^Player)data
 | 
			
		||||
            plr.is_invulnerable = false
 | 
			
		||||
        })
 | 
			
		||||
        if game.health <= 0 && !is_dead {
 | 
			
		||||
            is_dead = true
 | 
			
		||||
            explode(pos, 10, 0.8, rl.WHITE)
 | 
			
		||||
            rl.StopMusicStream(current_music)
 | 
			
		||||
            rl.PlaySound(Res.Sfx.PlayerDead)
 | 
			
		||||
            timer_start(3, game, proc(data: rawptr) {
 | 
			
		||||
                state := transmute(^Game)data
 | 
			
		||||
                screen := gameover_init(state)
 | 
			
		||||
                stack_push(screen)
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
player_draw :: proc(player: ^Player) {
 | 
			
		||||
    using player
 | 
			
		||||
    if player.is_dead { return }
 | 
			
		||||
    dir_vector := get_vec_from_angle(dir)
 | 
			
		||||
    color := rl.WHITE
 | 
			
		||||
    if is_invulnerable {
 | 
			
		||||
        color = rl.Color{255, 170, 170, 255}
 | 
			
		||||
    }
 | 
			
		||||
	using player
 | 
			
		||||
	if player.is_dead {return}
 | 
			
		||||
	dir_vector := get_vec_from_angle(dir)
 | 
			
		||||
	color := rl.WHITE
 | 
			
		||||
	if is_invulnerable {
 | 
			
		||||
		color = rl.Color{255, 170, 170, 255}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    roll := -math.PI / 2 + math.cos(dir) * math.PI / 2
 | 
			
		||||
    rlgl.PushMatrix()
 | 
			
		||||
    rlgl.Translatef(pos.x, pos.y, pos.z)
 | 
			
		||||
        rlgl.Rotatef(math.to_degrees(dir), 0, 0, -1)
 | 
			
		||||
        rlgl.Rotatef(math.to_degrees(roll + player.rolling), 1, 0, 0)
 | 
			
		||||
        // rl.DrawCircle3D({}, radius, vec3up, 0, color)
 | 
			
		||||
        // rl.DrawLine3D({}, {-4, 0, 0}, rl.GREEN)
 | 
			
		||||
        rl.DrawModel(Res.Models.PlayerModel, {}, 6, color)
 | 
			
		||||
    rlgl.PopMatrix()
 | 
			
		||||
    // rl.DrawLine3D(pos, pos + dir_vector * radius, rl.BLACK)
 | 
			
		||||
    // rl.DrawLine3D(pos, pos + vel, rl.RED)
 | 
			
		||||
	roll := -math.PI / 2 + math.cos(dir) * math.PI / 2
 | 
			
		||||
	rlgl.PushMatrix()
 | 
			
		||||
	rlgl.Translatef(pos.x, pos.y, pos.z)
 | 
			
		||||
	rlgl.Rotatef(math.to_degrees(dir), 0, 0, -1)
 | 
			
		||||
	rlgl.Rotatef(math.to_degrees(roll + player.rolling), 1, 0, 0)
 | 
			
		||||
	// rl.DrawCircle3D({}, radius, vec3up, 0, color)
 | 
			
		||||
	// rl.DrawLine3D({}, {-4, 0, 0}, rl.GREEN)
 | 
			
		||||
	rl.DrawModel(Res.Models.PlayerModel, {}, 6, color)
 | 
			
		||||
	rlgl.PopMatrix()
 | 
			
		||||
	// rl.DrawLine3D(pos, pos + dir_vector * radius, rl.BLACK)
 | 
			
		||||
	// 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)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										77
									
								
								winning.odin
									
									
									
									
									
								
							
							
						
						
									
										77
									
								
								winning.odin
									
									
									
									
									
								
							@ -1,14 +1,15 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import rl "vendor:raylib"
 | 
			
		||||
import "core:math/ease"
 | 
			
		||||
import "core:fmt"
 | 
			
		||||
import "core:math/ease"
 | 
			
		||||
import "ntween"
 | 
			
		||||
import rl "vendor:raylib"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Winning :: struct {
 | 
			
		||||
	using state: GameState,
 | 
			
		||||
	position: vec2,
 | 
			
		||||
	size: vec2,
 | 
			
		||||
	position:    vec2,
 | 
			
		||||
	size:        vec2,
 | 
			
		||||
	ready_to_go: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -22,8 +23,16 @@ winning_init :: proc(prev: ^GameState = nil) -> ^GameState {
 | 
			
		||||
	state.free = winning_free
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -33,16 +42,24 @@ winning_update :: proc(state: ^GameState, delta: f32) {
 | 
			
		||||
		if rl.IsKeyPressed(rl.KeyboardKey.ESCAPE) {
 | 
			
		||||
			winning.ready_to_go = false
 | 
			
		||||
			rl.StopMusicStream(current_music)
 | 
			
		||||
			tween_to(&Overlay_Opacity, 1.0, 0.5, ease.Ease.Cubic_Out, nil, proc(data: rawptr) {
 | 
			
		||||
				state := transmute(^GameState)data
 | 
			
		||||
				stack_pop()
 | 
			
		||||
				game := transmute(^Game)state.previous
 | 
			
		||||
				game_setup(game)
 | 
			
		||||
				menu := menu_init(game)
 | 
			
		||||
				stack_push(menu)
 | 
			
		||||
				free(state)
 | 
			
		||||
				tween_to(&Overlay_Opacity, 0, 0.5, ease.Ease.Cubic_Out)
 | 
			
		||||
			})
 | 
			
		||||
			ntween.animate(
 | 
			
		||||
				&f32_tweens,
 | 
			
		||||
				&Overlay_Opacity,
 | 
			
		||||
				1.0,
 | 
			
		||||
				0.5,
 | 
			
		||||
				ease.Ease.Cubic_Out,
 | 
			
		||||
				nil,
 | 
			
		||||
				proc(data: rawptr) {
 | 
			
		||||
					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)
 | 
			
		||||
				},
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -50,7 +67,7 @@ winning_update :: proc(state: ^GameState, delta: f32) {
 | 
			
		||||
 | 
			
		||||
winning_draw :: proc(state: ^GameState) {
 | 
			
		||||
	winning := transmute(^Winning)state
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	if state.previous != nil {
 | 
			
		||||
		state.previous->draw()
 | 
			
		||||
	}
 | 
			
		||||
@ -59,15 +76,33 @@ winning_draw :: proc(state: ^GameState) {
 | 
			
		||||
	TitleSpacing :: 3
 | 
			
		||||
	TitleText :: "GAME OVER"
 | 
			
		||||
 | 
			
		||||
	SubtitleText := [?]cstring{"Тор смог спасти Асгард", "от Рагнарёка!", "Нажмите Escape чтобы выйти"}
 | 
			
		||||
	SubtitleText := [?]cstring {
 | 
			
		||||
		"Тор смог спасти Асгард",
 | 
			
		||||
		"от Рагнарёка!",
 | 
			
		||||
		"Нажмите Escape чтобы выйти",
 | 
			
		||||
	}
 | 
			
		||||
	SubtitleFontSize :: 48
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	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 {
 | 
			
		||||
		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)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user