summaryrefslogtreecommitdiff
path: root/2026/framing/src
diff options
context:
space:
mode:
Diffstat (limited to '2026/framing/src')
-rw-r--r--2026/framing/src/assets.rs1
-rw-r--r--2026/framing/src/assets/audio/footsteps.wavbin0 -> 140588 bytes
-rw-r--r--2026/framing/src/assets/textures/arm.pngbin0 -> 2541 bytes
-rw-r--r--2026/framing/src/assets/textures/lagerboy.pngbin0 -> 886192 bytes
-rw-r--r--2026/framing/src/assets/textures/mrblue.pngbin0 -> 771 bytes
-rw-r--r--2026/framing/src/assets/textures/mrgreen.png (renamed from 2026/framing/src/assets/textures/test.png)bin714 -> 714 bytes
-rw-r--r--2026/framing/src/assets/textures/timbs.pngbin0 -> 4051 bytes
-rw-r--r--2026/framing/src/game.rs198
-rw-r--r--2026/framing/src/lagerboy.pngbin0 -> 886192 bytes
-rw-r--r--2026/framing/src/lib.rs3
10 files changed, 167 insertions, 35 deletions
diff --git a/2026/framing/src/assets.rs b/2026/framing/src/assets.rs
new file mode 100644
index 0000000..31fa1b5
--- /dev/null
+++ b/2026/framing/src/assets.rs
@@ -0,0 +1 @@
+teleia_macros::generate_assets!("src/assets/");
diff --git a/2026/framing/src/assets/audio/footsteps.wav b/2026/framing/src/assets/audio/footsteps.wav
new file mode 100644
index 0000000..57bfddf
--- /dev/null
+++ b/2026/framing/src/assets/audio/footsteps.wav
Binary files differ
diff --git a/2026/framing/src/assets/textures/arm.png b/2026/framing/src/assets/textures/arm.png
new file mode 100644
index 0000000..0b4accf
--- /dev/null
+++ b/2026/framing/src/assets/textures/arm.png
Binary files differ
diff --git a/2026/framing/src/assets/textures/lagerboy.png b/2026/framing/src/assets/textures/lagerboy.png
new file mode 100644
index 0000000..89992f7
--- /dev/null
+++ b/2026/framing/src/assets/textures/lagerboy.png
Binary files differ
diff --git a/2026/framing/src/assets/textures/mrblue.png b/2026/framing/src/assets/textures/mrblue.png
new file mode 100644
index 0000000..8cf2a0b
--- /dev/null
+++ b/2026/framing/src/assets/textures/mrblue.png
Binary files differ
diff --git a/2026/framing/src/assets/textures/test.png b/2026/framing/src/assets/textures/mrgreen.png
index 1f1edca..1f1edca 100644
--- a/2026/framing/src/assets/textures/test.png
+++ b/2026/framing/src/assets/textures/mrgreen.png
Binary files differ
diff --git a/2026/framing/src/assets/textures/timbs.png b/2026/framing/src/assets/textures/timbs.png
new file mode 100644
index 0000000..0c093ad
--- /dev/null
+++ b/2026/framing/src/assets/textures/timbs.png
Binary files differ
diff --git a/2026/framing/src/game.rs b/2026/framing/src/game.rs
index b704b49..8e819c0 100644
--- a/2026/framing/src/game.rs
+++ b/2026/framing/src/game.rs
@@ -1,37 +1,165 @@
#![allow(dead_code, unused_variables)]
use std::collections::HashMap;
use teleia::*;
+use teleia::renderer::UberFlags;
+use wasm_bindgen::prelude::*;
-struct Assets {
- font: font::Bitmap,
- shader_flat: shader::Shader,
- mesh_square: mesh::Mesh,
- texture_test: texture::Texture,
+use crate::assets;
+
+const NUM_LIVES: usize = 4;
+const LIFE_LOSS_FRAMES: u64 = 120;
+
+#[derive(PartialEq, Eq)]
+enum MrColor {
+ Green,
+ Blue,
+}
+impl MrColor {
+ fn texture(&self) -> assets::Texture {
+ match self {
+ Self::Green => assets::Texture::Mrgreen,
+ Self::Blue => assets::Texture::Mrblue,
+ }
+ }
+ fn hue(&self) -> f32 {
+ match self {
+ Self::Green => 0.3,
+ Self::Blue => 0.6,
+ }
+ }
}
-impl Assets {
- fn new(ctx: &context::Context) -> Self {
+struct Lives {
+ lives: [ui::Mode; NUM_LIVES],
+}
+impl Lives {
+ fn new() -> Self {
Self {
- font: font::Bitmap::default(ctx),
- shader_flat: shader::Shader::new(
- ctx,
- include_str!("assets/shaders/flat/vert.glsl"),
- include_str!("assets/shaders/flat/frag.glsl"),
- ),
- mesh_square: mesh::Mesh::from_obj(ctx, include_bytes!("assets/meshes/square.obj")),
- texture_test: texture::Texture::new(ctx, include_bytes!("assets/textures/test.png")),
+ lives: [
+ ui::Mode::new(LIFE_LOSS_FRAMES),
+ ui::Mode::new(LIFE_LOSS_FRAMES),
+ ui::Mode::new(LIFE_LOSS_FRAMES),
+ ui::Mode::new(LIFE_LOSS_FRAMES),
+ ],
+ }
+ }
+ fn last_life(&self) -> Option<usize> {
+ self.lives.iter().rposition(|l| !l.is_active())
+ }
+ fn lives_remaining(&self) -> i32 {
+ self.last_life().map(|x| (x + 1) as i32).unwrap_or(0)
+ }
+ fn lose_life(&mut self, _ctx: &context::Context, st: &state::State) {
+ if let Some(ll) = self.last_life() {
+ self.lives[ll].toggle(st.tick)
}
}
+ fn render(&self,
+ ctx: &context::Context, st: &mut state::State, r: &mut renderer::Renderer<assets::Assets>,
+ ) -> Erm<()> {
+ let base = glam::Vec2::new(90.0, 250.0);
+ let off = glam::Vec2::new(90.0, 0.0);
+ let t = st.tick as f32 / 10.0;
+ for i in 0..NUM_LIVES {
+ let fi = i as f32;
+ let pos = base + fi * off;
+ let osc = (t + fi * 10.0).sin();
+ if self.lives[i].is_active() {
+ let hoff = self.lives[i].progress(st.tick) * st.render_dims.x;
+ draw_mr_armed(ctx, st, r, MrColor::Blue, pos + glam::Vec2::new(hoff, 0.0), osc)?;
+ } else {
+ draw_mr_armed(ctx, st, r, MrColor::Green, pos, osc)?;
+ };
+ }
+ Ok(())
+ }
+}
+
+pub fn draw_texture_rotated_about(
+ ctx: &context::Context, st: &mut state::State, r: &mut renderer::Renderer<assets::Assets>,
+ texture: assets::Texture, flip: bool, hueset: Option<f32>,
+ pos: glam::Vec2, dims: glam::Vec2, joint: glam::Vec2, angle: f32,
+) -> Erm<()> {
+ let origin_offset = glam::Vec3::new(-st.render_dims.x / 2.0, st.render_dims.y / 2.0, 0.0);
+ r.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR | UberFlags::EFFECTS);
+ r.set_i32(ctx, st, "effect_flip", flip as i32);
+ r.set_f32(ctx, st, "effect_flash", 0.0);
+ r.set_f32(ctx, st, "effect_huescale", if hueset.is_some() { 0.0 } else { 1.0 });
+ r.set_f32(ctx, st, "effect_hueshift", if let Some(hs) = hueset { hs } else { 0.0 });
+ r.bind_texture(ctx, st, texture);
+ r.set_position_2d_mat(ctx, st,
+ glam::Mat4::from_translation(glam::Vec3::new(pos.x, -pos.y, 0.0) + origin_offset)
+ .mul_mat4(&glam::Mat4::from_translation(glam::Vec3::new(joint.x, -joint.y, 0.0)))
+ .mul_mat4(&glam::Mat4::from_rotation_z(angle))
+ .mul_mat4(&glam::Mat4::from_translation(glam::Vec3::new(-joint.x, joint.y, 0.0)))
+ .mul_mat4(&glam::Mat4::from_scale(glam::Vec3::new(dims.x / 2.0, dims.y / 2.0, 1.0))),
+ );
+ r.render_square(ctx, st);
+ Ok(())
+}
+
+fn draw_mr_armed(
+ ctx: &context::Context, st: &mut state::State, r: &mut renderer::Renderer<assets::Assets>,
+ mr: MrColor, center: glam::Vec2, oscillation: f32,
+) -> Erm<()> {
+ let dims = glam::Vec2::new(48.0, 48.0);
+ let pos = center + glam::Vec2::new(0.0, 4.0 * oscillation);
+ let topleft = pos - dims / 2.0;
+ let leftedge = pos.x - dims.x / 2.0;
+ let rightedge = pos.x + dims.x / 2.0;
+ let armheight = pos.y - dims.y / 3.0;
+ let legheight = pos.y + dims.y / 2.0;
+ let legangle = 0.2 * oscillation;
+ let armangle = 0.1 * oscillation;
+ let origin_offset = glam::Vec3::new(-st.render_dims.x / 2.0, st.render_dims.y / 2.0, 0.0);
+ draw_texture_rotated_about(ctx, st, r,
+ assets::Texture::Timbs, true, None,
+ glam::Vec2::new(leftedge, legheight),
+ dims,
+ glam::Vec2::new(dims.x / 2.0, -dims.y / 2.0),
+ legangle,
+ )?;
+ draw_texture_rotated_about(ctx, st, r,
+ assets::Texture::Timbs, false, None,
+ glam::Vec2::new(rightedge, legheight),
+ dims,
+ glam::Vec2::new(-dims.x / 2.0, -dims.y / 2.0),
+ -legangle,
+ )?;
+ if mr == MrColor::Green {
+ draw_texture_rotated_about(ctx, st, r,
+ assets::Texture::Arm, true, Some(mr.hue()),
+ glam::Vec2::new(leftedge, armheight),
+ dims,
+ glam::Vec2::new(dims.x / 2.0, dims.y / 2.0),
+ armangle,
+ )?;
+ draw_texture_rotated_about(ctx, st, r,
+ assets::Texture::Arm, false, Some(mr.hue()),
+ glam::Vec2::new(rightedge, armheight),
+ dims,
+ glam::Vec2::new(-dims.x / 2.0, dims.y / 2.0),
+ -armangle,
+ )?;
+ }
+ r.texture_screen(ctx, st,
+ mr.texture(),
+ topleft,
+ dims,
+ );
+ Ok(())
}
pub struct Game {
- assets: Assets,
+ renderer: renderer::Renderer<assets::Assets>,
+ lives: Lives,
}
impl Game {
pub fn new(ctx: &context::Context) -> Self {
Self {
- assets: Assets::new(ctx),
+ renderer: renderer::Renderer::new(ctx, assets::Assets::new),
+ lives: Lives::new(),
}
}
}
@@ -39,29 +167,31 @@ impl Game {
impl teleia::state::Game for Game {
fn initialize_audio(&self, ctx: &context::Context, st: &state::State, actx: &audio::Context) -> HashMap<String, audio::Audio> {
HashMap::from_iter(vec![
- ("test".to_owned(), audio::Audio::new(&actx, include_bytes!("assets/audio/test.wav"))),
+ ("footsteps".to_owned(), audio::Audio::new(&actx, include_bytes!("assets/audio/footsteps.wav"))),
])
}
- fn update(&mut self, _ctx: &context::Context, _st: &mut state::State) -> Erm<()> {
+ fn update(&mut self, ctx: &context::Context, st: &mut state::State) -> Erm<()> {
+ if st.keys.new_a() {
+ log::info!("yo");
+ self.lives.lose_life(ctx, st);
+ st.audio.play_sfx("footsteps");
+ }
Ok(())
}
fn render(&mut self, ctx: &context::Context, st: &mut state::State) -> Erm<()> {
- ctx.clear_color(glam::Vec4::new(1.0, 0.0, 0.0, 0.5));
+ ctx.clear_color(glam::Vec4::ZERO);
ctx.clear();
- self.assets.font.render_text_at(
- ctx, st,
- glam::Vec2::new(0.0, 0.0),
- "hello computer",
- font::BitmapParams::default(),
- );
- st.bind_2d(ctx, &self.assets.shader_flat);
- self.assets.texture_test.bind(ctx);
- self.assets.shader_flat.set_position_2d(
- ctx, st,
- &glam::Vec2::new(40.0, 40.0),
- &glam::Vec2::new(16.0, 16.0),
- );
- self.assets.mesh_square.render(ctx);
+ self.renderer.text_screen(ctx, st, glam::Vec2::new(0.0, 0.0), "hi");
+ self.lives.render(ctx, st, &mut self.renderer)?;
Ok(())
}
}
+
+#[wasm_bindgen]
+pub fn lose_life() {
+ contextualize(|ctx, st, g: &mut Game| {
+ log::info!("lose a life");
+ g.lives.lose_life(ctx, st);
+ st.audio.play_sfx("footsteps");
+ });
+}
diff --git a/2026/framing/src/lagerboy.png b/2026/framing/src/lagerboy.png
new file mode 100644
index 0000000..89992f7
--- /dev/null
+++ b/2026/framing/src/lagerboy.png
Binary files differ
diff --git a/2026/framing/src/lib.rs b/2026/framing/src/lib.rs
index fa27675..19ac407 100644
--- a/2026/framing/src/lib.rs
+++ b/2026/framing/src/lib.rs
@@ -1,4 +1,5 @@
mod game;
+mod assets;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;
@@ -6,5 +7,5 @@ use wasm_bindgen::prelude::*;
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
pub fn main_js() {
- teleia::run(240, 160, teleia::Options::OVERLAY, game::Game::new);
+ teleia::run(480, 320, teleia::Options::OVERLAY, game::Game::new);
}