summaryrefslogtreecommitdiff
path: root/2026/games/asrael_io/source/src/player.rs
diff options
context:
space:
mode:
Diffstat (limited to '2026/games/asrael_io/source/src/player.rs')
-rw-r--r--2026/games/asrael_io/source/src/player.rs96
1 files changed, 96 insertions, 0 deletions
diff --git a/2026/games/asrael_io/source/src/player.rs b/2026/games/asrael_io/source/src/player.rs
new file mode 100644
index 0000000..637160b
--- /dev/null
+++ b/2026/games/asrael_io/source/src/player.rs
@@ -0,0 +1,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);
+ }
+ }
+}