summaryrefslogtreecommitdiff
path: root/2026/games_submissions/asrael_io/source/src/player.rs
blob: 637160b25b637c8fe6396deb5b9fb458669d3850 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use crate::color::Palette;
use crate::color::db32::{ORANGE, YELLOW};
use crate::gfx;
use crate::sprite::Sprite;
use crate::{GAME_H, GAME_W};

use aseprite::AsepriteFile;
use glam::{IVec2, Vec2};

const FIRE_COOLDOWN: u32 = 12;
const MOUSE_MAX: f32 = 2.0;

#[derive(Default)]
pub struct Player {
    cooldown: u32,
    pos: Vec2,
    step: Vec2,
    speed: f32,
    sprite: Sprite,
}

impl Player {
    pub fn new(sprites: &AsepriteFile, speed: f32) -> Self {
        let cooldown = 0;
        let pos = Vec2::new(GAME_W as f32 / 2.0, GAME_H as f32 / 2.0);
        let step = Vec2::ZERO;
        let sprite = Sprite::from_ase(sprites, "player");

        Self {
            cooldown,
            pos,
            step,
            speed,
            sprite,
        }
    }

    pub fn win_anim(&mut self, t: u32) {
        let before = self.pos;

        if t < 40 {
            self.pos.y += 0.3;
        } else {
            self.pos.y -= ((t - 40) as f32 * 0.25).min(8.0);
        }

        self.step = self.pos - before;
    }

    pub fn pos(&self) -> Vec2 {
        self.pos
    }

    pub fn size(&self) -> Vec2 {
        self.sprite.size.as_vec2()
    }

    pub fn try_fire(&mut self) -> Option<Vec2> {
        (self.cooldown == 0).then(|| {
            self.cooldown = FIRE_COOLDOWN;
            self.pos + Vec2::new(self.sprite.size.x as f32 / 2.0, 0.0)
        })
    }

    pub fn update(&mut self, direction: IVec2, mouse: Vec2) {
        let before = self.pos;

        self.cooldown = self.cooldown.saturating_sub(1);

        let dir = direction.as_vec2().normalize_or_zero();
        self.pos += dir * self.speed + mouse.clamp_length_max(MOUSE_MAX);

        let w = self.sprite.size.x as f32;
        let h = self.sprite.size.y as f32;

        self.pos.x = self.pos.x.clamp(0.0, GAME_W as f32 - w);
        self.pos.y = self.pos.y.clamp(0.0, GAME_H as f32 - h);
        self.step = self.pos - before;
    }

    pub fn draw(&self, frame: &mut [u32], palette: &Palette, a: f32, tick: u32) {
        let pos = (self.pos - self.step * (1.0 - a)).round().as_ivec2();
        self.sprite.draw_at(frame, palette, pos);

        if self.step.length_squared() > 0.01 {
            let flame = if (tick / 4).is_multiple_of(2) {
                ORANGE
            } else {
                YELLOW
            };
            let exhaust = [flame, flame];
            let nozzle = pos + IVec2::new(self.sprite.size.x / 2, self.sprite.size.y);
            gfx::blit(frame, palette, &exhaust, nozzle, 1, 0);
        }
    }
}