231 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Odin
		
	
	
	
	
	
			
		
		
	
	
			231 lines
		
	
	
		
			6.8 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,
 | 
						|
    // 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,
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
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 {
 | 
						|
                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
 | 
						|
                }
 | 
						|
            } else {
 | 
						|
                thrust = 70
 | 
						|
                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)
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if rl.IsMouseButtonPressed(rl.MouseButton.RIGHT) && 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 := rl.IsMouseButtonDown(rl.MouseButton.LEFT) && !is_dodging && intro_timer <= 0
 | 
						|
        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
 | 
						|
                })
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            rl.StopSound(Res.Sfx.Lightning)
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    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)
 | 
						|
 | 
						|
}
 |