added update loop and game state.
This commit is contained in:
@@ -16,6 +16,7 @@ features = [
|
|||||||
"Document",
|
"Document",
|
||||||
"HtmlCanvasElement",
|
"HtmlCanvasElement",
|
||||||
"CanvasRenderingContext2d",
|
"CanvasRenderingContext2d",
|
||||||
|
"Performance",
|
||||||
"console",
|
"console",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
41
index.html
41
index.html
@@ -1,14 +1,33 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<title>Rust WASM Game Window</title>
|
<title>Rust WASM Game Window</title>
|
||||||
</head>
|
</head>
|
||||||
<body style="margin:0; background:#222; display:flex; justify-content:center; align-items:center; height:100vh;">
|
<body style="margin:0; background:#222; display:flex; justify-content:center; align-items:center; height:100vh;">
|
||||||
<canvas id="game-canvas"></canvas>
|
<canvas id="game-canvas"></canvas>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import init from "./pkg/hyperbolic_asteroids.js";
|
import init, { Game } from "./pkg/hyperbolic_asteroids.js";
|
||||||
init();
|
async function run() {
|
||||||
</script>
|
await init();
|
||||||
</body>
|
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>
|
</html>
|
||||||
|
|||||||
217
src/lib.rs
217
src/lib.rs
@@ -3,7 +3,7 @@ use std::f64;
|
|||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement};
|
use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement};
|
||||||
//use web_sys::console;
|
use web_sys::console;
|
||||||
|
|
||||||
mod cga;
|
mod cga;
|
||||||
use cga::CGA;
|
use cga::CGA;
|
||||||
@@ -58,9 +58,9 @@ const E2: usize = 2;
|
|||||||
//const E12345: usize = 31;
|
//const E12345: usize = 31;
|
||||||
|
|
||||||
struct Ship {
|
struct Ship {
|
||||||
_pos: CGA,
|
pos: CGA,
|
||||||
_vel: CGA,
|
//_vel: CGA,
|
||||||
_orientation: CGA,
|
//_orientation: CGA,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Geometry {
|
enum Geometry {
|
||||||
@@ -97,7 +97,8 @@ fn point_to_screen_space(x: f64, y: f64) -> (f64, f64) {
|
|||||||
|
|
||||||
fn draw_point(context: &CanvasRenderingContext2d, point: &CGA) {
|
fn draw_point(context: &CanvasRenderingContext2d, point: &CGA) {
|
||||||
//Naively assume we are given a valid point
|
//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.begin_path();
|
||||||
context.set_fill_style_str(RED);
|
context.set_fill_style_str(RED);
|
||||||
@@ -105,6 +106,18 @@ fn draw_point(context: &CanvasRenderingContext2d, point: &CGA) {
|
|||||||
context.fill();
|
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 {
|
fn get_geometry(circle: &CGA) -> Geometry {
|
||||||
//Naively assume we are given a valid line/circle
|
//Naively assume we are given a valid line/circle
|
||||||
let n_bar = CGA::e4() - CGA::e5();
|
let n_bar = CGA::e4() - CGA::e5();
|
||||||
@@ -146,24 +159,116 @@ fn draw_line(context: &CanvasRenderingContext2d, line: &CGA) {
|
|||||||
let canvas_r = r*RADIUS;
|
let canvas_r = r*RADIUS;
|
||||||
context.arc(canvas_x, canvas_y, canvas_r, 0., TWO_PI).unwrap();
|
context.arc(canvas_x, canvas_y, canvas_r, 0., TWO_PI).unwrap();
|
||||||
},
|
},
|
||||||
Geometry::Line(x,y,theta) => {
|
Geometry::Line(x,y,theta) => {
|
||||||
let (p1x, p1y) = (x - theta.cos(), y - theta.sin());
|
let (p1x, p1y) = (x - theta.cos(), y - theta.sin());
|
||||||
let (p2x, p2y) = (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_x1, canvas_y1) = point_to_screen_space(p1x, p1y);
|
||||||
let (canvas_x2, canvas_y2) = point_to_screen_space(p2x, p2y);
|
let (canvas_x2, canvas_y2) = point_to_screen_space(p2x, p2y);
|
||||||
draw_point(&context, &point_to_cga(x,y));
|
draw_point(&context, &point_to_cga(x,y));
|
||||||
context.move_to(canvas_x1, canvas_y1);
|
context.move_to(canvas_x1, canvas_y1);
|
||||||
context.line_to(canvas_x2, canvas_y2);
|
context.line_to(canvas_x2, canvas_y2);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
context.stroke();
|
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
|
// Start entry point
|
||||||
#[wasm_bindgen(start)]
|
#[wasm_bindgen(start)]
|
||||||
pub fn start() -> Result<(), JsValue> {
|
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
|
// Grab document and canvas
|
||||||
let window = web_sys::window().unwrap();
|
let window = web_sys::window().unwrap();
|
||||||
let document = window.document().unwrap();
|
let document = window.document().unwrap();
|
||||||
@@ -178,7 +283,7 @@ pub fn start() -> Result<(), JsValue> {
|
|||||||
let context = canvas
|
let context = canvas
|
||||||
.get_context("2d")?
|
.get_context("2d")?
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.dyn_into::<CanvasRenderingContext2d>()?;
|
.dyn_into::<CanvasRenderingContext2d>().unwrap();
|
||||||
|
|
||||||
//Set up play area.
|
//Set up play area.
|
||||||
context.begin_path();
|
context.begin_path();
|
||||||
@@ -188,51 +293,51 @@ pub fn start() -> Result<(), JsValue> {
|
|||||||
context.set_stroke_style_str(BLACK);
|
context.set_stroke_style_str(BLACK);
|
||||||
context.arc(CENTER_X, CENTER_Y, RADIUS, 0., TWO_PI).unwrap();
|
context.arc(CENTER_X, CENTER_Y, RADIUS, 0., TWO_PI).unwrap();
|
||||||
context.stroke();
|
context.stroke();
|
||||||
|
*/
|
||||||
|
/* //Testing example lines and circles.
|
||||||
|
let point = point_to_cga(0.,0.);
|
||||||
|
draw_point(&context, &point);
|
||||||
|
|
||||||
//Testing example lines and circles.
|
let p1 = point_to_cga(0.9, 0.0);
|
||||||
let point = point_to_cga(0.,0.);
|
draw_point(&context, &p1);
|
||||||
draw_point(&context, &point);
|
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);
|
let p1 = point_to_cga(0.9, 0.2);
|
||||||
draw_point(&context, &p1);
|
draw_point(&context, &p1);
|
||||||
let p2 = point_to_cga(0.0, 0.9);
|
let p2 = point_to_cga(-0.9, -0.);
|
||||||
draw_point(&context, &p2);
|
draw_point(&context, &p2);
|
||||||
let p3 = point_to_cga(0.7, 0.6);
|
let p3 = point_to_cga(0., 0.1);
|
||||||
draw_point(&context, &p3);
|
draw_point(&context, &p3);
|
||||||
let circle = &p1 ^ &p2 ^ &p3 ^ &CGA::e3(); //wedge e3 to force into the plane
|
let circle = &p1 ^ &p2 ^ &p3 ^ &CGA::e3();
|
||||||
draw_line(&context, &circle);
|
draw_line(&context, &circle);
|
||||||
|
|
||||||
let p1 = point_to_cga(0.9, 0.2);
|
let p1 = point_to_cga(0.9, 0.1);
|
||||||
draw_point(&context, &p1);
|
draw_point(&context, &p1);
|
||||||
let p2 = point_to_cga(-0.9, -0.);
|
let p2 = point_to_cga(-0.9, -0.1);
|
||||||
draw_point(&context, &p2);
|
draw_point(&context, &p2);
|
||||||
let p3 = point_to_cga(0., 0.1);
|
let p3 = point_to_cga(0., 0.0);
|
||||||
draw_point(&context, &p3);
|
draw_point(&context, &p3);
|
||||||
let circle = &p1 ^ &p2 ^ &p3 ^ &CGA::e3();
|
let circle = &p1 ^ &p2 ^ &p3 ^ &CGA::e3();
|
||||||
draw_line(&context, &circle);
|
draw_line(&context, &circle);
|
||||||
|
|
||||||
let p1 = point_to_cga(0.9, 0.1);
|
let p1 = point_to_cga(0.9, 0.);
|
||||||
draw_point(&context, &p1);
|
draw_point(&context, &p1);
|
||||||
let p2 = point_to_cga(-0.9, -0.1);
|
let p2 = point_to_cga(0.9, -0.1);
|
||||||
draw_point(&context, &p2);
|
draw_point(&context, &p2);
|
||||||
let p3 = point_to_cga(0., 0.0);
|
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_point(&context, &p3);
|
draw_line(&context, &circle);
|
||||||
let circle = &p1 ^ &p2 ^ &p3 ^ &CGA::e3();
|
|
||||||
draw_line(&context, &circle);
|
|
||||||
|
|
||||||
let p1 = point_to_cga(0.9, 0.);
|
let p1 = point_to_cga(0.9, 0.);
|
||||||
draw_point(&context, &p1);
|
draw_point(&context, &p1);
|
||||||
let p2 = point_to_cga(0.9, -0.1);
|
let p2 = point_to_cga(0.9, -0.1);
|
||||||
draw_point(&context, &p2);
|
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.
|
let circle = &p1 ^ &p2 ^ &CGA::e5() ^ &CGA::e3(); //Orthogonal to the line at infinity
|
||||||
draw_line(&context, &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);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user