First day
This commit is contained in:
commit
ade25af03a
|
@ -0,0 +1 @@
|
||||||
|
sineus-final.exe
|
|
@ -0,0 +1,2 @@
|
||||||
|
license: Freeware
|
||||||
|
link: https://www.fontspace.com/norse-font-f21080
|
|
@ -0,0 +1,94 @@
|
||||||
|
Copyright (c) 2010, ParaType Ltd. (http://www.paratype.com/public),
|
||||||
|
with Reserved Font Names "PT Sans", "PT Serif" and "ParaType".
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
https://openfontlicense.org
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,49 @@
|
||||||
|
JOEL CARROUCHE - FREE FONT LICENSE
|
||||||
|
version 1.3, january 2021
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
By downloading / installing this font you agree to the terms of this licence :
|
||||||
|
|
||||||
|
|
||||||
|
RIGHTS GRANTED
|
||||||
|
|
||||||
|
This font is a freeware. You are free to use it to create graphics, logos, and artwork for personal or commercial projects.
|
||||||
|
|
||||||
|
You may also embed the font file in pdf documents, applications, web pages or flash animations.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RESTRICTIONS
|
||||||
|
|
||||||
|
You may not modifiy the font files.
|
||||||
|
|
||||||
|
You may not sell this font or licenses for this font.
|
||||||
|
|
||||||
|
You may not redistribute or share this font without written permission of Joël Carrouché.
|
||||||
|
This means you cannot make the font available for download on your website without prior consent.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
COPYRIGHT
|
||||||
|
|
||||||
|
Except for the right to use the font mentionned above, all other rights remain the sole property of Joël Carrouché.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
The font files are provided as is, without warranty of any kind, either expressed or implied. The author shall not be liable for any damage resulting from the use of the font.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
CONTACT
|
||||||
|
|
||||||
|
www.joelcarrouche.com
|
||||||
|
|
||||||
|
|
||||||
|
If you use this font for something cool, let me know !
|
||||||
|
|
||||||
|
|
||||||
|
|
Binary file not shown.
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,4 @@
|
||||||
|
# Made in Blockbench 4.11.1
|
||||||
|
newmtl m_3faa339c-1a1f-acb0-d167-578e9ad5cc6b
|
||||||
|
map_Kd background.png
|
||||||
|
newmtl none
|
|
@ -0,0 +1,111 @@
|
||||||
|
# Made in Blockbench 4.11.1
|
||||||
|
mtllib background.mtl
|
||||||
|
|
||||||
|
o plane
|
||||||
|
v 0.5 0.3125 0.5
|
||||||
|
v 0.5 0 -0.5
|
||||||
|
v -0.5 0.3125 0.5
|
||||||
|
v -0.5 0 -0.5
|
||||||
|
v 0.5 0.14583367270962758 0.16666775267080824
|
||||||
|
v -0.5 0.14583367270962758 0.16666775267080824
|
||||||
|
v 0.5 0.04166717573166087 -0.16666503765868518
|
||||||
|
v -0.5 0.04166717573166087 -0.16666503765868518
|
||||||
|
v 0.5 -0.5077522268648397 -0.8120173603004518
|
||||||
|
v -0.5 -0.5077522268648397 -0.8120173603004518
|
||||||
|
vt 0 0.9296875
|
||||||
|
vt 0 0.6666650376586851
|
||||||
|
vt 1 0.6666650376586851
|
||||||
|
vt 1 0.9296875
|
||||||
|
vt 1 0
|
||||||
|
vt 1 0.33333224732919176
|
||||||
|
vt 0 0.33333224732919176
|
||||||
|
vt 0 0
|
||||||
|
vt 1 0.33333224732919176
|
||||||
|
vt 1 0.6666650376586851
|
||||||
|
vt 0 0.6666650376586851
|
||||||
|
vt 0 0.33333224732919176
|
||||||
|
vt 0 1
|
||||||
|
vt 0 0.9375
|
||||||
|
vt 1 0.9375
|
||||||
|
vt 1 1
|
||||||
|
vn 0 0.9922777648072294 -0.12403562983743448
|
||||||
|
vn 0 0.8944269724450329 -0.447214032609457
|
||||||
|
vn 0 0.9544799780350297 -0.2982749931359468
|
||||||
|
vn 0 0.5235550571328688 -0.8519918439460548
|
||||||
|
usemtl m_3faa339c-1a1f-acb0-d167-578e9ad5cc6b
|
||||||
|
f 4/1/1 8/2/1 7/3/1 2/4/1
|
||||||
|
f 1/5/2 5/6/2 6/7/2 3/8/2
|
||||||
|
f 5/9/3 7/10/3 8/11/3 6/12/3
|
||||||
|
f 2/13/4 9/14/4 10/15/4 4/16/4
|
||||||
|
o plane
|
||||||
|
v -0.5 0.3125 0.5
|
||||||
|
v -0.5 0 -0.5
|
||||||
|
v -1.5 0.3125 0.5
|
||||||
|
v -1.5 0 -0.5
|
||||||
|
v -0.5 0.14583367270962758 0.16666775267080824
|
||||||
|
v -1.5 0.14583367270962758 0.16666775267080824
|
||||||
|
v -0.5 0.04166717573166087 -0.16666503765868518
|
||||||
|
v -1.5 0.04166717573166087 -0.16666503765868518
|
||||||
|
v -0.5 -0.5077522268648397 -0.8120173603004518
|
||||||
|
v -1.5 -0.5077522268648397 -0.8120173603004518
|
||||||
|
vt 0 0.9296875
|
||||||
|
vt 0 0.6666650376586851
|
||||||
|
vt 1 0.6666650376586851
|
||||||
|
vt 1 0.9296875
|
||||||
|
vt 1 0
|
||||||
|
vt 1 0.33333224732919176
|
||||||
|
vt 0 0.33333224732919176
|
||||||
|
vt 0 0
|
||||||
|
vt 1 0.33333224732919176
|
||||||
|
vt 1 0.6666650376586851
|
||||||
|
vt 0 0.6666650376586851
|
||||||
|
vt 0 0.33333224732919176
|
||||||
|
vt 0 1
|
||||||
|
vt 0 0.9375
|
||||||
|
vt 1 0.9375
|
||||||
|
vt 1 1
|
||||||
|
vn 0 0.9922777648072294 -0.12403562983743448
|
||||||
|
vn 0 0.8944269724450329 -0.447214032609457
|
||||||
|
vn 0 0.9544799780350297 -0.2982749931359468
|
||||||
|
vn 0 0.5235550571328688 -0.8519918439460548
|
||||||
|
usemtl m_3faa339c-1a1f-acb0-d167-578e9ad5cc6b
|
||||||
|
f 14/17/5 18/18/5 17/19/5 12/20/5
|
||||||
|
f 11/21/6 15/22/6 16/23/6 13/24/6
|
||||||
|
f 15/25/7 17/26/7 18/27/7 16/28/7
|
||||||
|
f 12/29/8 19/30/8 20/31/8 14/32/8
|
||||||
|
o plane
|
||||||
|
v 1.5 0.3125 0.5
|
||||||
|
v 1.5 0 -0.5
|
||||||
|
v 0.5 0.3125 0.5
|
||||||
|
v 0.5 0 -0.5
|
||||||
|
v 1.5 0.14583367270962758 0.16666775267080824
|
||||||
|
v 0.5 0.14583367270962758 0.16666775267080824
|
||||||
|
v 1.5 0.04166717573166087 -0.16666503765868518
|
||||||
|
v 0.5 0.04166717573166087 -0.16666503765868518
|
||||||
|
v 1.5 -0.5077522268648397 -0.8120173603004518
|
||||||
|
v 0.5 -0.5077522268648397 -0.8120173603004518
|
||||||
|
vt 0 0.9296875
|
||||||
|
vt 0 0.6666650376586851
|
||||||
|
vt 1 0.6666650376586851
|
||||||
|
vt 1 0.9296875
|
||||||
|
vt 1 0
|
||||||
|
vt 1 0.33333224732919176
|
||||||
|
vt 0 0.33333224732919176
|
||||||
|
vt 0 0
|
||||||
|
vt 1 0.33333224732919176
|
||||||
|
vt 1 0.6666650376586851
|
||||||
|
vt 0 0.6666650376586851
|
||||||
|
vt 0 0.33333224732919176
|
||||||
|
vt 0 1
|
||||||
|
vt 0 0.9375
|
||||||
|
vt 1 0.9375
|
||||||
|
vt 1 1
|
||||||
|
vn 0 0.9922777648072294 -0.12403562983743448
|
||||||
|
vn 0 0.8944269724450329 -0.447214032609457
|
||||||
|
vn 0 0.9544799780350297 -0.2982749931359468
|
||||||
|
vn 0 0.5235550571328688 -0.8519918439460548
|
||||||
|
usemtl m_3faa339c-1a1f-acb0-d167-578e9ad5cc6b
|
||||||
|
f 24/33/9 28/34/9 27/35/9 22/36/9
|
||||||
|
f 21/37/10 25/38/10 26/39/10 23/40/10
|
||||||
|
f 25/41/11 27/42/11 28/43/11 26/44/11
|
||||||
|
f 22/45/12 29/46/12 30/47/12 24/48/12
|
Binary file not shown.
After Width: | Height: | Size: 652 B |
|
@ -0,0 +1,144 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import rl "vendor:raylib"
|
||||||
|
import "vendor:raylib/rlgl"
|
||||||
|
import "core:fmt"
|
||||||
|
import "core:math"
|
||||||
|
import "core:math/ease"
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:strings"
|
||||||
|
import "core:strconv"
|
||||||
|
|
||||||
|
// Virtual game field dimensions
|
||||||
|
GameField := vec2{400, 200}
|
||||||
|
|
||||||
|
Game :: struct {
|
||||||
|
using state: GameState,
|
||||||
|
health: u8,
|
||||||
|
player: Player,
|
||||||
|
camera: rl.Camera3D,
|
||||||
|
camera_offset: vec3,
|
||||||
|
score: u32,
|
||||||
|
background: rl.Texture,
|
||||||
|
plane: rl.Model,
|
||||||
|
bullets: [dynamic]Bullet,
|
||||||
|
snake_max_health: int,
|
||||||
|
snake_health: int
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
game_init :: proc(prev: ^GameState = nil) -> ^GameState {
|
||||||
|
state := new(Game)
|
||||||
|
state.previous = prev
|
||||||
|
state.variant = state
|
||||||
|
state.draw = game_draw
|
||||||
|
state.update = game_update
|
||||||
|
state.free = game_free
|
||||||
|
rlgl.DisableBackfaceCulling()
|
||||||
|
|
||||||
|
img := rl.GenImageChecked(1024, 1024, 128, 128, rl.Color{60, 255, 255, 255}, rl.Color{30, 220, 220, 255})
|
||||||
|
state.background = rl.LoadTextureFromImage(img)
|
||||||
|
|
||||||
|
state.plane = rl.LoadModel(".\\assets\\models\\background.obj")
|
||||||
|
rl.UnloadImage(img)
|
||||||
|
|
||||||
|
game_setup(state)
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
game_setup :: proc(game: ^Game) {
|
||||||
|
clear(&game.bullets)
|
||||||
|
game.player = player_spawn({GameField.x / 2 + 50, 20, 0})
|
||||||
|
game.health = 100
|
||||||
|
|
||||||
|
snake_spawn({10, 10, 0}, math.PI, 70)
|
||||||
|
|
||||||
|
|
||||||
|
for segment in Segments {
|
||||||
|
game.snake_max_health += int(segment.health)
|
||||||
|
}
|
||||||
|
|
||||||
|
game.camera = rl.Camera3D{
|
||||||
|
target = game.player.pos,
|
||||||
|
position = game.player.pos + vec3backward * 50,
|
||||||
|
fovy = 60,
|
||||||
|
//offset = WSize/2,
|
||||||
|
projection = rl.CameraProjection.PERSPECTIVE,
|
||||||
|
up = vec3up
|
||||||
|
}
|
||||||
|
game.camera.target.x = clamp(game.camera.target.x, -GameField.x/2, GameField.x/2)
|
||||||
|
game.camera.target.y = clamp(game.camera.target.y, 0, GameField.y)
|
||||||
|
game.camera.position = game.camera.target + vec3backward * 50
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
game_gen_level :: proc(game: ^Game) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
game_update :: proc(state: ^GameState, delta: f32) {
|
||||||
|
game := transmute(^Game)state
|
||||||
|
using game
|
||||||
|
|
||||||
|
|
||||||
|
player_update(&player, game, delta)
|
||||||
|
#reverse for &bullet, i in bullets {
|
||||||
|
bullet_process(&bullet, game, delta)
|
||||||
|
if !bullet.alive {
|
||||||
|
unordered_remove(&bullets, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
snake_process(game, delta)
|
||||||
|
target_offset := player.vel / 5
|
||||||
|
camera_offset = rl.Vector3MoveTowards(camera_offset, target_offset, rl.Vector3Length(target_offset - camera_offset) * 10 * delta)
|
||||||
|
camera.target = player.pos + camera_offset
|
||||||
|
camera.target.x = clamp(camera.target.x, -GameField.x/2, GameField.x/2)
|
||||||
|
camera.target.y = clamp(camera.target.y, 0, GameField.y)
|
||||||
|
camera.position = camera.target + vec3backward * 50
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
game_draw :: proc(state: ^GameState) {
|
||||||
|
|
||||||
|
game := transmute(^Game)state
|
||||||
|
using game
|
||||||
|
|
||||||
|
rl.BeginMode3D(camera)
|
||||||
|
rl.DrawModel(game.plane, {0, 0, 500}, 1000, rl.WHITE)
|
||||||
|
|
||||||
|
yy : i32 = 0
|
||||||
|
|
||||||
|
snake_draw(game)
|
||||||
|
player_draw(&player)
|
||||||
|
for bullet in bullets {
|
||||||
|
bullet_draw(bullet)
|
||||||
|
}
|
||||||
|
rl.EndMode3D()
|
||||||
|
rl.DrawText(rl.TextFormat("HEALTH: %d", snake_health), 0, 0, 20, rl.BLACK)
|
||||||
|
rl.DrawText(rl.TextFormat("STATE: %s", Head.state), 0, 20, 20, rl.BLACK)
|
||||||
|
|
||||||
|
|
||||||
|
hb_text : cstring = "Jörmungandr"
|
||||||
|
height := 30 * (WSize.y / 480)
|
||||||
|
hb_health : f32 = f32(snake_health) / f32(snake_max_health)
|
||||||
|
if snake_health == 0 {
|
||||||
|
hb_health = f32(Head.health) / f32(Head.max_health)
|
||||||
|
hb_text = "Jörmungandr's head"
|
||||||
|
}
|
||||||
|
rl.DrawRectangleV({0, WSize.y - height - 10}, {WSize.x, height + 10}, rl.WHITE)
|
||||||
|
hb_width := hb_health * WSize.x
|
||||||
|
rl.DrawRectangleV({WSize.x / 2 - hb_width / 2, WSize.y - height - 7}, {hb_width, height + 4}, rl.RED)
|
||||||
|
draw_text_centered(FontTitle, hb_text, {WSize.x / 2, WSize.y - height / 2}, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
game_free :: proc(state: ^GameState) {
|
||||||
|
game := transmute(^Game)state
|
||||||
|
|
||||||
|
rl.UnloadTexture(game.background)
|
||||||
|
free(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
|
vec3 :: [3]f32
|
||||||
|
vec2 :: [2]f32
|
||||||
|
vec3right := vec3{1, 0, 0}
|
||||||
|
vec3left := vec3{-1, 0, 0}
|
||||||
|
vec3up := vec3{0, 1, 0}
|
||||||
|
vec3down := vec3{0, -1, 0}
|
||||||
|
vec3forward := vec3{0, 0, 1}
|
||||||
|
vec3backward := vec3{0, 0, -1}
|
||||||
|
|
||||||
|
|
||||||
|
WSize := [2]f32{}
|
||||||
|
WSizei := [2]i32{}
|
||||||
|
|
||||||
|
WindowShouldExit := false
|
||||||
|
|
||||||
|
FontUI: rl.Font
|
||||||
|
FontTitle: rl.Font
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
rl.SetConfigFlags(rl.ConfigFlags{.MSAA_4X_HINT, .WINDOW_MAXIMIZED, .WINDOW_RESIZABLE})
|
||||||
|
rl.InitWindow(800, 480, "Ragnarøkkr")
|
||||||
|
WSizei = {rl.GetScreenWidth(), rl.GetScreenHeight()}
|
||||||
|
WSize = {f32(WSizei.x), f32(WSizei.y)}
|
||||||
|
|
||||||
|
FontUI = rl.LoadFontEx(".\\assets\\fonts\\PTSerif-Regular.ttf", 96, nil, 2048)
|
||||||
|
FontTitle = rl.LoadFontEx(".\\assets\\fonts\\norse.otf", 96*2, nil, 2048)
|
||||||
|
|
||||||
|
|
||||||
|
game := game_init()
|
||||||
|
stack_push(game)
|
||||||
|
menu := menu_init(game)
|
||||||
|
stack_push(menu)
|
||||||
|
|
||||||
|
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.BeginDrawing()
|
||||||
|
rl.ClearBackground(rl.SKYBLUE)
|
||||||
|
state->draw()
|
||||||
|
rl.EndDrawing()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import rl "vendor:raylib"
|
||||||
|
import "core:math/ease"
|
||||||
|
|
||||||
|
|
||||||
|
Menu_Buttons :: enum {
|
||||||
|
START,
|
||||||
|
HOW_TO_PLAY,
|
||||||
|
EXIT
|
||||||
|
}
|
||||||
|
|
||||||
|
menu_strings := [Menu_Buttons]cstring {
|
||||||
|
.START = "Старт",
|
||||||
|
.HOW_TO_PLAY = "Как играть?",
|
||||||
|
.EXIT = "Выход"
|
||||||
|
}
|
||||||
|
|
||||||
|
Menu :: struct {
|
||||||
|
using state: GameState,
|
||||||
|
|
||||||
|
list: MenuList(Menu_Buttons),
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
menu_init :: proc(prev: ^GameState = nil) -> ^GameState {
|
||||||
|
state := new(Menu)
|
||||||
|
state.variant = state
|
||||||
|
state.list = MenuList(Menu_Buttons){
|
||||||
|
state = state,
|
||||||
|
position = {100, WSize.y / 2},
|
||||||
|
line_size = 60,
|
||||||
|
font_size = 48,
|
||||||
|
elements = &menu_strings,
|
||||||
|
menu_pressed = menu_button_pressed,
|
||||||
|
background = rl.Color{50, 10, 110, 10}
|
||||||
|
}
|
||||||
|
state.update = menu_update
|
||||||
|
state.draw = menu_draw
|
||||||
|
state.free = menu_free
|
||||||
|
state.previous = prev
|
||||||
|
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
menu_update :: proc(state: ^GameState, delta: f32) {
|
||||||
|
menu := transmute(^Menu)state
|
||||||
|
menu.list.position.y = WSize.y / 2
|
||||||
|
|
||||||
|
menu_list_update(&menu.list)
|
||||||
|
}
|
||||||
|
|
||||||
|
menu_button_pressed :: proc(state: ^GameState, el: Menu_Buttons) {
|
||||||
|
switch el {
|
||||||
|
case .START:
|
||||||
|
stack_pop()
|
||||||
|
case .HOW_TO_PLAY:
|
||||||
|
// howtoplay := howtoplay_init(state)
|
||||||
|
// stack_push(howtoplay)
|
||||||
|
case .EXIT:
|
||||||
|
WindowShouldExit = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
menu_draw :: proc(state: ^GameState) {
|
||||||
|
menu := transmute(^Menu)state
|
||||||
|
|
||||||
|
menu.previous.draw(menu.previous)
|
||||||
|
|
||||||
|
TitleFontSize :: 96
|
||||||
|
TitleSpacing :: 3
|
||||||
|
TitleText :: "Ragnarøkkr"
|
||||||
|
TitleSize := rl.MeasureTextEx(FontTitle, TitleText, TitleFontSize, TitleSpacing)
|
||||||
|
rl.DrawTextPro(FontTitle, TitleText, {WSize.x - 50, 50}, {TitleSize.x, 0}, 0, 96, 3, rl.WHITE)
|
||||||
|
|
||||||
|
menu_list_draw(&menu.list)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
menu_free :: proc(state: ^GameState) {
|
||||||
|
free(state)
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import rl "vendor:raylib"
|
||||||
|
import "core:math/ease"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
MenuList :: struct($T: typeid) {
|
||||||
|
state: ^GameState,
|
||||||
|
position: vec2,
|
||||||
|
line_size: f32,
|
||||||
|
font_size: f32,
|
||||||
|
active_element: T,
|
||||||
|
active_marker: vec2,
|
||||||
|
tween: ^Tween,
|
||||||
|
elements: ^[T]cstring,
|
||||||
|
menu_pressed: proc(state: ^GameState, element: T),
|
||||||
|
background: rl.Color,
|
||||||
|
mouse_pos: vec2,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
menu_list_update :: proc(list: ^MenuList($T)) {
|
||||||
|
|
||||||
|
activate_element := false
|
||||||
|
prev_element := cast(i8)list.active_element
|
||||||
|
cur_element := prev_element
|
||||||
|
|
||||||
|
last_mouse_pos := list.mouse_pos
|
||||||
|
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 last_mouse_pos != list.mouse_pos {
|
||||||
|
mouse_relative := list.mouse_pos - list.position
|
||||||
|
cur_element = i8(mouse_relative.y / list.line_size)
|
||||||
|
}
|
||||||
|
if rl.IsMouseButtonPressed(rl.MouseButton.LEFT) {
|
||||||
|
list.menu_pressed(list.state, list.active_element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last_mouse_pos = list.mouse_pos
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if rl.IsKeyPressed(rl.KeyboardKey.DOWN) {
|
||||||
|
cur_element += 1
|
||||||
|
}
|
||||||
|
if rl.IsKeyPressed(rl.KeyboardKey.UP) {
|
||||||
|
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 }
|
||||||
|
list.active_element = cast(T)cur_element
|
||||||
|
if list.tween != nil {
|
||||||
|
tween_cancel(list.tween)
|
||||||
|
}
|
||||||
|
list.tween = tween_to(
|
||||||
|
&list.active_marker.y,
|
||||||
|
f32(list.active_element) * list.line_size,
|
||||||
|
0.25,
|
||||||
|
ease.Ease.Quadratic_Out,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if rl.IsKeyPressed(rl.KeyboardKey.ENTER) || rl.IsKeyPressed(rl.KeyboardKey.SPACE) {
|
||||||
|
list.menu_pressed(list.state, list.active_element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
menu_list_draw :: proc(list: ^MenuList($T)) {
|
||||||
|
if list.background[3] != 0 {
|
||||||
|
size := menu_list_get_size(list)
|
||||||
|
rl.DrawRectangleV(list.position - {40, 40}, size + {80, 80}, list.background)
|
||||||
|
}
|
||||||
|
rl.DrawTextEx(FontUI, ">", 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}
|
||||||
|
rl.DrawTextEx(FontUI, el, pos, list.font_size, 2, rl.WHITE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
menu_list_get_size :: proc(list: ^MenuList($T)) -> vec2 {
|
||||||
|
size := vec2{}
|
||||||
|
for el, i in list.elements {
|
||||||
|
line_size := rl.MeasureTextEx(FontUI, el, list.font_size, 2)
|
||||||
|
if line_size.x > size.x {
|
||||||
|
size.x = line_size.x
|
||||||
|
}
|
||||||
|
size.y += list.line_size
|
||||||
|
}
|
||||||
|
return size
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://raw.githubusercontent.com/DanielGavin/ols/master/misc/ols.schema.json",
|
||||||
|
"enable_document_symbols": true,
|
||||||
|
"enable_hover": true,
|
||||||
|
"enable_snippets": true,
|
||||||
|
"enable_format": true
|
||||||
|
}
|
|
@ -0,0 +1,134 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import rl "vendor:raylib"
|
||||||
|
import "core:math"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
|
||||||
|
Player :: struct {
|
||||||
|
pos: vec3,
|
||||||
|
vel: vec3,
|
||||||
|
dir: f32,
|
||||||
|
radius: f32,
|
||||||
|
thrust: f32,
|
||||||
|
max_speed: f32,
|
||||||
|
is_dodging: bool,
|
||||||
|
can_dodge: bool,
|
||||||
|
can_shoot: bool,
|
||||||
|
is_invulnerable: bool,
|
||||||
|
is_dead: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
player_spawn :: proc(position: vec3) -> Player {
|
||||||
|
return Player{
|
||||||
|
pos = position,
|
||||||
|
radius = 1,
|
||||||
|
max_speed = 40,
|
||||||
|
dir = 0,
|
||||||
|
vel = {-40, 0, 0},
|
||||||
|
can_dodge = true,
|
||||||
|
can_shoot = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
player_update :: proc(player: ^Player, game: ^Game, delta: f32) {
|
||||||
|
using player
|
||||||
|
|
||||||
|
pos += vel * 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 {
|
||||||
|
if !is_dodging {
|
||||||
|
dir = angle_rotate(dir, mouse_angle, math.PI * 2 * delta)
|
||||||
|
dir_vector := get_vec_from_angle(dir)
|
||||||
|
|
||||||
|
thrust = 0
|
||||||
|
if rl.IsKeyDown(rl.KeyboardKey.W) {
|
||||||
|
thrust = 70
|
||||||
|
}
|
||||||
|
if thrust > 0 {
|
||||||
|
vel = rl.Vector3MoveTowards(vel, dir_vector * max_speed, thrust * delta)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if thrust == 0 {
|
||||||
|
vel = rl.Vector3MoveTowards(vel, {0, -30, 0}, 20 * delta)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rl.IsMouseButtonPressed(rl.MouseButton.RIGHT) && can_dodge {
|
||||||
|
is_dodging = true
|
||||||
|
can_dodge = false
|
||||||
|
timer_start(0.45, player, proc(data: rawptr) {
|
||||||
|
player := transmute(^Player)data
|
||||||
|
player.is_dodging = false
|
||||||
|
})
|
||||||
|
timer_start(0.55, player, proc(data: rawptr) {
|
||||||
|
player := transmute(^Player)data
|
||||||
|
player.can_dodge = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if rl.IsMouseButtonDown(rl.MouseButton.LEFT) && can_shoot {
|
||||||
|
b := bullet_spawn(pos, dir)
|
||||||
|
append(&game.bullets, b)
|
||||||
|
can_shoot = false
|
||||||
|
timer_start(0.1, player, proc(data: rawptr) {
|
||||||
|
player := transmute(^Player)data
|
||||||
|
player.can_shoot = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
got_hit := false
|
||||||
|
|
||||||
|
if !is_invulnerable && !is_dodging && !is_dead {
|
||||||
|
for segment in Segments {
|
||||||
|
if rl.Vector3DistanceSqrt(pos, segment.pos) < math.pow(radius + segment.radius, 2) {
|
||||||
|
got_hit = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if got_hit {
|
||||||
|
game.health -= 10
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
player_draw :: proc(player: ^Player) {
|
||||||
|
using player
|
||||||
|
|
||||||
|
dir_vector := get_vec_from_angle(dir)
|
||||||
|
color := rl.GREEN
|
||||||
|
if is_dodging {
|
||||||
|
color = rl.GRAY
|
||||||
|
}
|
||||||
|
if is_invulnerable {
|
||||||
|
color = rl.YELLOW
|
||||||
|
}
|
||||||
|
rl.DrawCircle3D(pos, radius, vec3up, 0, color)
|
||||||
|
rl.DrawLine3D(pos, pos + dir_vector * radius, rl.BLACK)
|
||||||
|
rl.DrawLine3D(pos, pos + vel, rl.RED)
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
|
bullets : [dynamic]Bullet
|
||||||
|
|
||||||
|
Bullet :: struct{
|
||||||
|
pos: vec3,
|
||||||
|
vel: vec3,
|
||||||
|
radius: f32,
|
||||||
|
alive: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
bullet_spawn :: proc(pos: vec3, dir: f32) -> Bullet {
|
||||||
|
return Bullet {
|
||||||
|
pos = pos,
|
||||||
|
vel = get_vec_from_angle(dir) * 70,
|
||||||
|
alive = true,
|
||||||
|
radius = 0.4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bullet_process :: proc(bullet: ^Bullet, game: ^Game, delta: f32) {
|
||||||
|
bullet.vel = rl.Vector3MoveTowards(bullet.vel, {}, 60 * delta)
|
||||||
|
bullet.pos += bullet.vel * delta
|
||||||
|
if rl.Vector3LengthSqr(bullet.vel) < 0.2 {
|
||||||
|
bullet.alive = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if rl.CheckCollisionCircles(bullet.pos.xy, bullet.radius, Head.pos.xy, Head.radius) {
|
||||||
|
bullet.alive = false
|
||||||
|
if game.snake_health == 0 {
|
||||||
|
Head.health -= 1
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for &segment in Segments {
|
||||||
|
if rl.CheckCollisionCircles(bullet.pos.xy, bullet.radius, segment.pos.xy, segment.collider_radius) {
|
||||||
|
bullet.alive = false
|
||||||
|
if segment.health > 0 {
|
||||||
|
segment.health -= 1
|
||||||
|
if segment.health == 0 {
|
||||||
|
segment.collider_radius = 1.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bullet_draw :: proc(bullet: Bullet) {
|
||||||
|
rl.DrawSphere(bullet.pos, bullet.radius, rl.WHITE)
|
||||||
|
}
|
|
@ -0,0 +1,263 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import rl "vendor:raylib"
|
||||||
|
import "core:math"
|
||||||
|
import "core:fmt"
|
||||||
|
import "core:math/linalg"
|
||||||
|
|
||||||
|
Snake_Health := 1000
|
||||||
|
|
||||||
|
Segments: [dynamic]^SnakeSegment
|
||||||
|
Head: SnakeHead
|
||||||
|
|
||||||
|
SnakeState :: enum {
|
||||||
|
Chasing,
|
||||||
|
Chase_to_Dive,
|
||||||
|
Dive_to_Chase,
|
||||||
|
Diving,
|
||||||
|
Hunt,
|
||||||
|
Shot
|
||||||
|
}
|
||||||
|
|
||||||
|
SnakeHead :: struct {
|
||||||
|
pos: vec3,
|
||||||
|
vel: vec3,
|
||||||
|
dir: f32,
|
||||||
|
radius: f32,
|
||||||
|
health: int,
|
||||||
|
max_health: int,
|
||||||
|
next: ^SnakeSegment,
|
||||||
|
state: SnakeState,
|
||||||
|
next_state: SnakeState,
|
||||||
|
state_timer: f32,
|
||||||
|
shot_timer: f32,
|
||||||
|
is_shooting: bool,
|
||||||
|
is_dead: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
SnakeSegment :: struct {
|
||||||
|
pos: vec3,
|
||||||
|
vel: vec3,
|
||||||
|
dir: f32,
|
||||||
|
radius: f32,
|
||||||
|
collider_radius: f32,
|
||||||
|
active: bool,
|
||||||
|
health: u8,
|
||||||
|
head: ^SnakeHead,
|
||||||
|
next: ^SnakeSegment,
|
||||||
|
prev: ^SnakeSegment
|
||||||
|
}
|
||||||
|
|
||||||
|
snake_spawn :: proc(pos: vec3, dir: f32, length: int){
|
||||||
|
dir_vec := rl.Vector3RotateByAxisAngle(vec3right, vec3backward, dir)
|
||||||
|
|
||||||
|
Head = SnakeHead{
|
||||||
|
pos = pos,
|
||||||
|
dir = dir,
|
||||||
|
radius = 3,
|
||||||
|
state = .Chasing,
|
||||||
|
vel = dir_vec * 20,
|
||||||
|
health = 100,
|
||||||
|
max_health = 100,
|
||||||
|
state_timer = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < length; i += 1 {
|
||||||
|
segment := new(SnakeSegment)
|
||||||
|
segment.active = false
|
||||||
|
segment.health = 3
|
||||||
|
segment.radius = 2.5
|
||||||
|
segment.collider_radius = 2.5
|
||||||
|
segment.pos = pos - dir_vec * segment.radius
|
||||||
|
segment.dir = dir
|
||||||
|
segment.head = &Head
|
||||||
|
if i != 0 {
|
||||||
|
segment.prev = Segments[i-1]
|
||||||
|
Segments[i-1].next = segment
|
||||||
|
} else {
|
||||||
|
Head.next = segment
|
||||||
|
}
|
||||||
|
append(&Segments, segment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snake_clear :: proc() {
|
||||||
|
for segment in Segments {
|
||||||
|
free(segment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snake_process :: proc(game: ^Game, delta: f32) {
|
||||||
|
switch Head.state {
|
||||||
|
case .Chasing:
|
||||||
|
snake_chase_smooth(game, delta)
|
||||||
|
case .Diving:
|
||||||
|
snake_dive(game, delta)
|
||||||
|
case .Chase_to_Dive,.Dive_to_Chase:
|
||||||
|
snake_dropdown(game, delta)
|
||||||
|
case .Hunt:
|
||||||
|
snake_hunt(game, delta)
|
||||||
|
case .Shot:
|
||||||
|
snake_shot(game, delta)
|
||||||
|
}
|
||||||
|
total_health := 0
|
||||||
|
for segment in Segments {
|
||||||
|
total_health += int(segment.health)
|
||||||
|
}
|
||||||
|
game.snake_health = total_health
|
||||||
|
if game.snake_health == 0 && Head.next != nil {
|
||||||
|
Head.next = nil
|
||||||
|
Head.state = .Hunt
|
||||||
|
Head.state_timer = 20
|
||||||
|
fmt.println("Tail is dead")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for segment, i in Segments {
|
||||||
|
if segment.prev == nil && total_health == 0 { // Хвост падает, когда у него не осталось жизней
|
||||||
|
segment.vel.y -= 30 * delta
|
||||||
|
segment.pos += segment.vel * delta
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
target_pos := Head.pos
|
||||||
|
if segment.prev != nil {
|
||||||
|
target_pos = segment.prev.pos
|
||||||
|
} else {
|
||||||
|
segment.vel = Head.vel
|
||||||
|
}
|
||||||
|
diff := target_pos - segment.pos
|
||||||
|
if rl.Vector3Length(diff) > segment.radius {
|
||||||
|
segment.pos = target_pos - rl.Vector3Normalize(diff) * segment.radius
|
||||||
|
}
|
||||||
|
segment.dir = math.atan2(-diff.y, diff.x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
snake_chase :: proc(game: ^Game, delta: f32) {
|
||||||
|
using game
|
||||||
|
diff := player.pos - Head.pos
|
||||||
|
target_angle := math.atan2(-diff.y, diff.x)
|
||||||
|
dir_diff := angle_cycle(target_angle - Head.dir, -math.PI, math.PI)
|
||||||
|
Head.dir = angle_rotate(Head.dir, target_angle, min(abs(dir_diff), math.PI) * delta)
|
||||||
|
Head.vel = rl.Vector3RotateByAxisAngle(vec3right, vec3backward, Head.dir) * 500
|
||||||
|
Head.pos += Head.vel * delta
|
||||||
|
}
|
||||||
|
|
||||||
|
snake_chase_smooth :: proc(game: ^Game, delta: f32) {
|
||||||
|
using game
|
||||||
|
|
||||||
|
if rl.IsKeyPressed(rl.KeyboardKey.K) {
|
||||||
|
for segment in Segments {
|
||||||
|
segment.health = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Head.state_timer -= delta
|
||||||
|
if Head.state_timer <= 0 {
|
||||||
|
Head.state = .Chase_to_Dive
|
||||||
|
Head.next_state = .Diving
|
||||||
|
Head.state_timer = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
if Head.pos.y < -3 && Head.vel.y < 0 {
|
||||||
|
Head.pos.y = -3
|
||||||
|
Head.vel.y = -Head.vel.y
|
||||||
|
}
|
||||||
|
|
||||||
|
diff := player.pos - Head.pos
|
||||||
|
norm := rl.Vector3Normalize(diff)
|
||||||
|
Head.vel = rl.Vector3MoveTowards(Head.vel, norm * 70, 70 * delta)
|
||||||
|
Head.vel = rl.Vector3ClampValue(Head.vel, 30, 50)
|
||||||
|
Head.dir = math.atan2(-Head.vel.y, Head.vel.x)
|
||||||
|
Head.pos += Head.vel * delta
|
||||||
|
}
|
||||||
|
|
||||||
|
snake_dive :: proc(game: ^Game, delta: f32) {
|
||||||
|
Head.state_timer -= delta
|
||||||
|
if Head.state_timer <= 0 {
|
||||||
|
Head.state = .Dive_to_Chase
|
||||||
|
Head.next_state = .Chasing
|
||||||
|
}
|
||||||
|
if Head.pos.y < 0 && Segments[len(Segments)-1].pos.y < 0 && Head.vel.y < 0 {
|
||||||
|
Head.pos.x = game.player.pos.x
|
||||||
|
Head.pos.y = -5
|
||||||
|
Head.vel.x = 0
|
||||||
|
Head.vel.y = 70
|
||||||
|
} else {
|
||||||
|
grav : f32 = 20
|
||||||
|
if Head.vel.y < 0 { grav = 30 }
|
||||||
|
else if Head.pos.y < game.player.pos.y {
|
||||||
|
grav = 7
|
||||||
|
}
|
||||||
|
Head.vel.y -= grav * delta
|
||||||
|
Head.vel.x = (game.player.pos.x - Head.pos.x) * 2
|
||||||
|
}
|
||||||
|
Head.dir = math.atan2(-Head.vel.y, Head.vel.x)
|
||||||
|
Head.pos += Head.vel * delta
|
||||||
|
}
|
||||||
|
|
||||||
|
snake_dropdown :: proc(game: ^Game, delta: f32) {
|
||||||
|
Head.vel.y -= 100 * delta
|
||||||
|
Head.pos += Head.vel * delta
|
||||||
|
if Segments[len(Segments)-1].pos.y < 0 {
|
||||||
|
Head.state = Head.next_state
|
||||||
|
Head.state_timer = 20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snake_hunt :: proc(game: ^Game, delta: f32) {
|
||||||
|
Head.state_timer -= delta
|
||||||
|
if Head.state_timer <= 0 {
|
||||||
|
Head.state_timer = 10
|
||||||
|
Head.state = .Shot
|
||||||
|
}
|
||||||
|
diff := game.player.pos - Head.pos
|
||||||
|
target_pos := game.player.pos + rl.Vector3Normalize(diff) * 10
|
||||||
|
target_diff := target_pos - Head.pos
|
||||||
|
|
||||||
|
Head.vel = rl.Vector3MoveTowards(Head.vel, rl.Vector3Normalize(target_diff) * 50, 40 * delta)
|
||||||
|
fmt.println(Head.vel)
|
||||||
|
Head.dir = math.atan2(-Head.vel.y, Head.vel.x)
|
||||||
|
Head.pos += Head.vel * delta
|
||||||
|
}
|
||||||
|
|
||||||
|
snake_shot :: proc(game: ^Game, delta: f32) {
|
||||||
|
Head.state_timer -= delta
|
||||||
|
if Head.state_timer <= 0 {
|
||||||
|
Head.state_timer = 20
|
||||||
|
Head.state = .Hunt
|
||||||
|
}
|
||||||
|
Head.is_shooting = false
|
||||||
|
if Head.state_timer < 8 && Head.state_timer > 3 {
|
||||||
|
Head.is_shooting = true
|
||||||
|
}
|
||||||
|
diff := game.player.pos - Head.pos
|
||||||
|
angle := math.atan2(-diff.y, diff.x)
|
||||||
|
|
||||||
|
Head.dir = angle_rotate(Head.dir, angle, angle_cycle(abs(angle - Head.dir), -math.PI, math.PI) * delta * 2)
|
||||||
|
Head.vel = rl.Vector3MoveTowards(Head.vel, {}, 30 * delta)
|
||||||
|
Head.pos += Head.vel * delta
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
snake_draw :: proc(game: ^Game) {
|
||||||
|
|
||||||
|
dir_vector := get_vec_from_angle(Head.dir)
|
||||||
|
rl.DrawCircle3D(Head.pos, Head.radius, vec3up, 0, rl.RED)
|
||||||
|
rl.DrawLine3D(Head.pos, Head.pos + dir_vector * Head.radius, rl.BLACK)
|
||||||
|
|
||||||
|
if Head.is_shooting {
|
||||||
|
rl.DrawLine3D(Head.pos, Head.pos + get_vec_from_angle(Head.dir) * 300, rl.YELLOW)
|
||||||
|
}
|
||||||
|
|
||||||
|
for segment in Segments {
|
||||||
|
dir_vector := get_vec_from_angle(segment.dir)
|
||||||
|
col := rl.RED
|
||||||
|
if segment.health == 0 {
|
||||||
|
col = rl.GRAY
|
||||||
|
}
|
||||||
|
rl.DrawCircle3D(segment.pos, segment.radius, vec3up, 0, col)
|
||||||
|
rl.DrawLine3D(segment.pos, segment.pos + dir_vector * segment.radius, rl.BLACK)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
|
||||||
|
import "core:slice"
|
||||||
|
|
||||||
|
StateVariant :: union{^Game, ^Menu}
|
||||||
|
|
||||||
|
|
||||||
|
GameState :: struct {
|
||||||
|
update: proc(state: ^GameState, delta: f32),
|
||||||
|
draw: proc(state: ^GameState),
|
||||||
|
free: proc(state: ^GameState),
|
||||||
|
previous: ^GameState,
|
||||||
|
|
||||||
|
variant: StateVariant
|
||||||
|
}
|
||||||
|
|
||||||
|
new_state :: proc($T: typeid) -> ^T {
|
||||||
|
state := new(T)
|
||||||
|
state.variant = state
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
state_stack : [dynamic]^GameState
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
stack_push :: proc(state: ^GameState) -> (bool) {
|
||||||
|
append(&state_stack, state)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
stack_pop :: proc() -> (bool) {
|
||||||
|
if len(state_stack) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
state := pop(&state_stack)
|
||||||
|
state->free()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
stack_top :: proc() -> ^GameState {
|
||||||
|
return state_stack[len(state_stack)-1]
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "core:math"
|
||||||
|
import "core:math/linalg"
|
||||||
|
import "core:slice"
|
||||||
|
|
||||||
|
|
||||||
|
Timer :: struct {
|
||||||
|
duration: f32,
|
||||||
|
time: f32,
|
||||||
|
active: bool,
|
||||||
|
finished: proc(data: rawptr),
|
||||||
|
data: rawptr
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TIMER_SIZE :: 128
|
||||||
|
timers : [dynamic]^Timer
|
||||||
|
|
||||||
|
timers_clean :: proc() {
|
||||||
|
for timer, i in timers {
|
||||||
|
free(timer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
timer_start :: proc(
|
||||||
|
time: f32,
|
||||||
|
data: rawptr = nil,
|
||||||
|
callback: proc(data: rawptr) = nil
|
||||||
|
) -> ^Timer {
|
||||||
|
|
||||||
|
timer := new(Timer)
|
||||||
|
timer.duration = time
|
||||||
|
timer.active = true
|
||||||
|
timer.data = data
|
||||||
|
timer.finished = callback
|
||||||
|
|
||||||
|
append(&timers, timer)
|
||||||
|
return timer
|
||||||
|
}
|
||||||
|
|
||||||
|
timer_cancel :: proc(t: ^Timer) {
|
||||||
|
t.active = false
|
||||||
|
}
|
||||||
|
|
||||||
|
timers_process :: proc(delta: f32) {
|
||||||
|
#reverse for timer, i in timers {
|
||||||
|
if !timer.active {
|
||||||
|
free(timer)
|
||||||
|
unordered_remove(&timers, i)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
timer.time += delta
|
||||||
|
|
||||||
|
if timer.time >= timer.duration {
|
||||||
|
timer.active = false
|
||||||
|
if timer.finished != nil {
|
||||||
|
timer.finished(timer.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "core:math"
|
||||||
|
import "core:math/linalg"
|
||||||
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
|
|
||||||
|
angle_cycle :: proc(value, min, max: f32) -> f32 {
|
||||||
|
delta := (max - min)
|
||||||
|
result := linalg.mod(value - min, delta)
|
||||||
|
if result < 0 {
|
||||||
|
result += delta
|
||||||
|
}
|
||||||
|
|
||||||
|
return min + result
|
||||||
|
}
|
||||||
|
|
||||||
|
angle_rotate :: proc(angle, target, speed: f32) -> f32 {
|
||||||
|
diff := angle_cycle(target - angle, -math.PI, math.PI)
|
||||||
|
if diff < -speed {return angle - speed}
|
||||||
|
if diff > speed {return angle + speed}
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
get_vec_from_angle :: proc(angle: f32) -> vec3 {
|
||||||
|
return rl.Vector3RotateByAxisAngle(vec3right, vec3backward, angle)
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_text_centered :: proc(font: rl.Font, text: cstring, pos: vec2, size: f32) {
|
||||||
|
text_size := rl.MeasureTextEx(font, text, size, 1)
|
||||||
|
rl.DrawTextPro(font, text, pos, text_size / 2, 0, size, 1, rl.BLACK)
|
||||||
|
}
|
Loading…
Reference in New Issue