Ragnarokkr/player.odin

271 lines
8.2 KiB
Odin

package main
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,
}
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,
}
}
player_update :: proc(player: ^Player, game: ^Game, delta: f32) {
using player
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)
}
}
dodge := false
shoot := false
if KeyboardOnly {
dodge = rl.IsKeyPressed(rl.KeyboardKey.LEFT_SHIFT)
shoot = rl.IsKeyDown(rl.KeyboardKey.SPACE)
} else {
dodge = rl.IsMouseButtonPressed(rl.MouseButton.RIGHT)
shoot = rl.IsMouseButtonDown(rl.MouseButton.LEFT)
}
if dodge && can_dodge && intro_timer <= 0 {
is_dodging = true
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
})
}
// 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)
})
}
}
}
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}
}
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)
}