added update loop and game state.

This commit is contained in:
2025-08-22 11:35:45 -05:00
parent 56c2a6440c
commit 6c7662b5e6
3 changed files with 192 additions and 67 deletions

View File

@@ -16,6 +16,7 @@ features = [
"Document",
"HtmlCanvasElement",
"CanvasRenderingContext2d",
"Performance",
"console",
]

View File

@@ -1,14 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Rust WASM Game Window</title>
</head>
<body style="margin:0; background:#222; display:flex; justify-content:center; align-items:center; height:100vh;">
<canvas id="game-canvas"></canvas>
<script type="module">
import init from "./pkg/hyperbolic_asteroids.js";
init();
</script>
</body>
<head>
<meta charset="utf-8"/>
<title>Rust WASM Game Window</title>
</head>
<body style="margin:0; background:#222; display:flex; justify-content:center; align-items:center; height:100vh;">
<canvas id="game-canvas"></canvas>
<script type="module">
import init, { Game } from "./pkg/hyperbolic_asteroids.js";
async function run() {
await init();
let game = new Game("game-canvas");
let last = performance.now();
function loop(now) {
const dt = (now - last);
last = now;
game.update(dt);
game.draw();
requestAnimationFrame(loop);
}
//game.update(1);
requestAnimationFrame(loop);
}
run();
</script>
</body>
</html>

View File

@@ -3,7 +3,7 @@ use std::f64;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement};
//use web_sys::console;
use web_sys::console;
mod cga;
use cga::CGA;
@@ -58,9 +58,9 @@ const E2: usize = 2;
//const E12345: usize = 31;
struct Ship {
_pos: CGA,
_vel: CGA,
_orientation: CGA,
pos: CGA,
//_vel: CGA,
//_orientation: CGA,
}
enum Geometry {
@@ -97,7 +97,8 @@ fn point_to_screen_space(x: f64, y: f64) -> (f64, f64) {
fn draw_point(context: &CanvasRenderingContext2d, point: &CGA) {
//Naively assume we are given a valid point
let (x,y) = point_to_screen_space(point[E1], point[E2]);
let (x,y) = get_point(point);
let (x,y) = point_to_screen_space(x, y);
context.begin_path();
context.set_fill_style_str(RED);
@@ -105,6 +106,18 @@ fn draw_point(context: &CanvasRenderingContext2d, point: &CGA) {
context.fill();
}
//TODO Integrate into get geometry
fn get_point(point: &CGA) -> (f64, f64) {
let e_vec = CGA::e4();
let e_bar = CGA::e5();
let n_vec = &e_vec + &e_bar; //Null vector for the point at infinity.
let normalization = -(point | &n_vec)[SCALAR];
let x = point[E1] / normalization;
let y = point[E2] / normalization;
(x,y)
}
fn get_geometry(circle: &CGA) -> Geometry {
//Naively assume we are given a valid line/circle
let n_bar = CGA::e4() - CGA::e5();
@@ -159,11 +172,103 @@ fn draw_line(context: &CanvasRenderingContext2d, line: &CGA) {
context.stroke();
}
fn get_hyperbolic_translation(vec: &CGA) -> CGA {
let vec_sqr = (vec * vec)[SCALAR];
if vec_sqr >= 1. {
panic!("Translation Vector Out of Bounds");
}
let message = format!("Get TX\nvec {} \nvecvec {}\nvec_sqr {}", vec, vec*vec, vec_sqr);
console::log_1(&message.into());
let t = 1.0 / ( 1. - vec_sqr).sqrt() * ( CGA::new(1., SCALAR) + CGA::e5()*vec);
t
}
fn get_hyperbolic_point(vec: &CGA) -> CGA {
let vec_sqr = (vec * vec)[SCALAR];
if vec_sqr >= 1. {
panic!("Vector out of bounds");
}
let p = 1. / (1. - vec_sqr)*(CGA::new(vec_sqr, SCALAR) + 2.*vec - (CGA::e4() - CGA::e5()));
p
}
struct Asteroid {
}
#[wasm_bindgen]
pub struct Game {
context: CanvasRenderingContext2d,
ship: Ship,
//asteroids: Vec::<Asteroid>,
point: (f64, f64),
//keys: HashSet<String>,
}
#[wasm_bindgen]
impl Game {
#[wasm_bindgen(constructor)]
pub fn new(canvas_id: &str) -> Self {
let window = web_sys::window().unwrap();
let document = window.document().unwrap();
let canvas = document
.get_element_by_id(canvas_id)
.ok_or_else( || JsValue::from_str("Canvas not found")).unwrap()
.dyn_into::<HtmlCanvasElement>().unwrap();
canvas.set_width(WIDTH as u32);
canvas.set_height(HEIGHT as u32);
let context = canvas
.get_context("2d").unwrap()
.ok_or_else( || JsValue::from_str("Failed to get context")).unwrap()
.dyn_into::<CanvasRenderingContext2d>().unwrap();
let ship = Ship { pos: get_hyperbolic_point(&CGA::zero()) };
Game { context: context, point: (0.,0.), ship }
}
pub fn draw(&self) {
self.context.begin_path();
self.context.set_fill_style_str(BACKGROUND);
self.context.fill_rect(0.0, 0.0, WIDTH, HEIGHT);
self.context.fill();
self.context.set_stroke_style_str(BLACK);
self.context.arc(CENTER_X, CENTER_Y, RADIUS, 0., TWO_PI).unwrap();
self.context.stroke();
let x = self.point.0;
let y = self.point.1;
draw_point(&self.context, &self.ship.pos);
//self.context.begin_path();
//self.context.set_fill_style_str(GREEN);
//self.context.arc(x, y, 20., 0., TWO_PI).unwrap();
//self.context.fill();
}
pub fn update(&mut self, dt: f64) { //dt in milliseconds
let theta:f64 = 0.1;
let vel:f64 = 1.*dt/1000.;
let dir = theta.cos()*CGA::e1() + theta.sin()*CGA::e2();
let vec = vel* &dir;
let tx = get_hyperbolic_translation(&vec);
let txr = tx.Reverse();
self.ship.pos = &tx * &self.ship.pos * &txr;
let norm = (&self.ship.pos | CGA::e4() )[SCALAR];
self.ship.pos = &self.ship.pos * (1.0 / norm);
}
}
// Start entry point
#[wasm_bindgen(start)]
pub fn start() -> Result<(), JsValue> {
let _ship = Ship { _pos: point_to_cga(0.,0.), _vel: CGA::zero(), _orientation: CGA::zero() };
// let _ship = Ship { _pos: point_to_cga(0.,0.), _vel: CGA::zero(), _orientation: CGA::zero() };
/*
// Grab document and canvas
let window = web_sys::window().unwrap();
let document = window.document().unwrap();
@@ -178,7 +283,7 @@ pub fn start() -> Result<(), JsValue> {
let context = canvas
.get_context("2d")?
.unwrap()
.dyn_into::<CanvasRenderingContext2d>()?;
.dyn_into::<CanvasRenderingContext2d>().unwrap();
//Set up play area.
context.begin_path();
@@ -188,8 +293,8 @@ pub fn start() -> Result<(), JsValue> {
context.set_stroke_style_str(BLACK);
context.arc(CENTER_X, CENTER_Y, RADIUS, 0., TWO_PI).unwrap();
context.stroke();
//Testing example lines and circles.
*/
/* //Testing example lines and circles.
let point = point_to_cga(0.,0.);
draw_point(&context, &point);
@@ -232,7 +337,7 @@ pub fn start() -> Result<(), JsValue> {
let p2 = point_to_cga(0.9, -0.1);
draw_point(&context, &p2);
let circle = &p1 ^ &p2 ^ &CGA::e5() ^ &CGA::e3(); //Orthogonal to the line at infinity
draw_line(&context, &circle);
draw_line(&context, &circle);*/
Ok(())
}