From 6c7662b5e6b88a04ccdbd70fa0cc03a71af5fdb1 Mon Sep 17 00:00:00 2001 From: Lily Iliana Luna Ylva Anderson Grigaitis Date: Fri, 22 Aug 2025 11:35:45 -0500 Subject: [PATCH] added update loop and game state. --- Cargo.toml | 1 + index.html | 41 +++++++--- src/lib.rs | 217 +++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 192 insertions(+), 67 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7f1f76c..b63108a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ features = [ "Document", "HtmlCanvasElement", "CanvasRenderingContext2d", + "Performance", "console", ] diff --git a/index.html b/index.html index 8701c32..fcac4de 100644 --- a/index.html +++ b/index.html @@ -1,14 +1,33 @@ - - - Rust WASM Game Window - - - - - + + +Rust WASM Game Window + + + + + diff --git a/src/lib.rs b/src/lib.rs index aeb33d5..3d5072f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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(); @@ -146,24 +159,116 @@ fn draw_line(context: &CanvasRenderingContext2d, line: &CGA) { let canvas_r = r*RADIUS; context.arc(canvas_x, canvas_y, canvas_r, 0., TWO_PI).unwrap(); }, - Geometry::Line(x,y,theta) => { - let (p1x, p1y) = (x - theta.cos(), y - theta.sin()); - let (p2x, p2y) = (x + theta.cos(), y + theta.sin()); - let (canvas_x1, canvas_y1) = point_to_screen_space(p1x, p1y); - let (canvas_x2, canvas_y2) = point_to_screen_space(p2x, p2y); - draw_point(&context, &point_to_cga(x,y)); - context.move_to(canvas_x1, canvas_y1); - context.line_to(canvas_x2, canvas_y2); - }, + Geometry::Line(x,y,theta) => { + let (p1x, p1y) = (x - theta.cos(), y - theta.sin()); + let (p2x, p2y) = (x + theta.cos(), y + theta.sin()); + let (canvas_x1, canvas_y1) = point_to_screen_space(p1x, p1y); + let (canvas_x2, canvas_y2) = point_to_screen_space(p2x, p2y); + draw_point(&context, &point_to_cga(x,y)); + context.move_to(canvas_x1, canvas_y1); + context.line_to(canvas_x2, canvas_y2); + }, } 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::, + point: (f64, f64), + //keys: HashSet, +} + +#[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::().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::().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::()?; + .dyn_into::().unwrap(); //Set up play area. context.begin_path(); @@ -188,51 +293,51 @@ 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. + let point = point_to_cga(0.,0.); + draw_point(&context, &point); - //Testing example lines and circles. - let point = point_to_cga(0.,0.); - draw_point(&context, &point); + let p1 = point_to_cga(0.9, 0.0); + draw_point(&context, &p1); + let p2 = point_to_cga(0.0, 0.9); + draw_point(&context, &p2); + let p3 = point_to_cga(0.7, 0.6); + draw_point(&context, &p3); + let circle = &p1 ^ &p2 ^ &p3 ^ &CGA::e3(); //wedge e3 to force into the plane + draw_line(&context, &circle); - let p1 = point_to_cga(0.9, 0.0); - draw_point(&context, &p1); - let p2 = point_to_cga(0.0, 0.9); - draw_point(&context, &p2); - let p3 = point_to_cga(0.7, 0.6); - draw_point(&context, &p3); - let circle = &p1 ^ &p2 ^ &p3 ^ &CGA::e3(); //wedge e3 to force into the plane - draw_line(&context, &circle); + let p1 = point_to_cga(0.9, 0.2); + draw_point(&context, &p1); + let p2 = point_to_cga(-0.9, -0.); + draw_point(&context, &p2); + let p3 = point_to_cga(0., 0.1); + draw_point(&context, &p3); + let circle = &p1 ^ &p2 ^ &p3 ^ &CGA::e3(); + draw_line(&context, &circle); - let p1 = point_to_cga(0.9, 0.2); - draw_point(&context, &p1); - let p2 = point_to_cga(-0.9, -0.); - draw_point(&context, &p2); - let p3 = point_to_cga(0., 0.1); - draw_point(&context, &p3); - let circle = &p1 ^ &p2 ^ &p3 ^ &CGA::e3(); - draw_line(&context, &circle); + let p1 = point_to_cga(0.9, 0.1); + draw_point(&context, &p1); + let p2 = point_to_cga(-0.9, -0.1); + draw_point(&context, &p2); + let p3 = point_to_cga(0., 0.0); + draw_point(&context, &p3); + let circle = &p1 ^ &p2 ^ &p3 ^ &CGA::e3(); + draw_line(&context, &circle); - let p1 = point_to_cga(0.9, 0.1); - draw_point(&context, &p1); - let p2 = point_to_cga(-0.9, -0.1); - draw_point(&context, &p2); - let p3 = point_to_cga(0., 0.0); - draw_point(&context, &p3); - let circle = &p1 ^ &p2 ^ &p3 ^ &CGA::e3(); - draw_line(&context, &circle); + let p1 = point_to_cga(0.9, 0.); + draw_point(&context, &p1); + let p2 = point_to_cga(0.9, -0.1); + draw_point(&context, &p2); + let circle = &p1 ^ &p2 ^ &CGA::e4() ^ &CGA::e3(); //Wedge e4 to create a circle through p1 and p1 that is tangent to the unit circle. + draw_line(&context, &circle); - let p1 = point_to_cga(0.9, 0.); - draw_point(&context, &p1); - let p2 = point_to_cga(0.9, -0.1); - draw_point(&context, &p2); - let circle = &p1 ^ &p2 ^ &CGA::e4() ^ &CGA::e3(); //Wedge e4 to create a circle through p1 and p1 that is tangent to the unit circle. - draw_line(&context, &circle); - - let p1 = point_to_cga(0.9, 0.); - draw_point(&context, &p1); - 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); + let p1 = point_to_cga(0.9, 0.); + draw_point(&context, &p1); + 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);*/ Ok(()) }