diff --git a/src/lib.rs b/src/lib.rs index df1b02c..396f874 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -87,6 +87,70 @@ struct Ship { orientation: CGA, } +impl Ship { + fn update(&mut self, dt_s: f64, keys: &HashSet) { + let vel = self.vel.clone(); //Velocity at beginning of frame + let mut vel_2 = self.vel.clone(); + + let mut a_vec = - DRAG * &vel_2; + + if keys.contains("w") { + let orient = &self.orientation; //Transforms body frame to local frame + let pos = &self.com_rotor; //Transforms local frame to world frame + let accel_body = ACCEL_STR * CGA::e15(); //The acceleration in the body frame. + let accel_local = orient * accel_body * orient.Reverse(); //The acceleration in the local frame. + let accel_world = pos * accel_local * pos.Reverse(); //The acceleration in the world frame. + a_vec = a_vec - accel_world; //Sum of drag and thrust. + } + + if keys.contains("q") { + self.orientation = bivector_exponential(&(dt_s * CGA::e12())) * &self.orientation; + } + + if keys.contains("e") { + self.orientation = bivector_exponential(&(-dt_s * CGA::e12())) * &self.orientation; + } + + + vel_2 = vel_2 + a_vec*dt_s; //Velocity at end of frame + let vel_3 = 0.5*(vel+&vel_2); + let delta = vel_3 * dt_s; + let pos = bivector_exponential(&delta)*&self.com_rotor; //Update position. + self.vel = vel_2; + self.com_rotor = pos; + + } + + fn draw(&self, context: &CanvasRenderingContext2d) { + let origin = gen_hyperbolic_point(&CGA::zero()); //Origin in the body frame. + let orient_rotor = &self.orientation; //Transforms body frame to local frame. + let com = &self.com_rotor; //Transforms local frame to world frame. + let v0_rotor = com*orient_rotor*bivector_exponential(&self.verts.0); //Combined transformation to locate a vertex of the ship in the world frame. + let v1_rotor = com*orient_rotor*bivector_exponential(&self.verts.1); //Combined transformation ... + let v2_rotor = com*orient_rotor*bivector_exponential(&self.verts.2); //Combined transformation ... + let p0 = &v0_rotor*&origin*&v0_rotor.Reverse(); //Produce a vertex of the ship in the world frame. + let p1 = &v1_rotor*&origin*&v1_rotor.Reverse(); //... + let p2 = &v2_rotor*&origin*&v2_rotor.Reverse(); //... + + draw_point(context, &(com*&origin*com.Reverse())); + draw_point(context, &p0); + draw_point(context, &p1); + draw_point(context, &p2); + draw_line_between(context, &p0, &p1); + draw_line_between(context, &p1, &p2); + draw_line_between(context, &p2, &p0); + + //Construct and draw line pointing straight ahead, to help orient the player. + let com_p = com * gen_hyperbolic_point(&CGA::zero()) * com.Reverse(); + let delta_gen = com * orient_rotor * CGA::e14() * &orient_rotor.Reverse() * com.Reverse(); + let dot = delta_gen | &com_p; + let line = CGA::e4() ^ com_p ^ dot ^ CGA::e3(); + draw_line(context, &line); + + + } +} + enum Geometry { Circle(f64, f64, f64), //x,y,r Line(f64, f64, f64), //x,r,theta @@ -94,7 +158,7 @@ enum Geometry { } /* Translation of a Euclidean Point. Need to use hyperbolic*/ -fn _point_to_cga(x: f64, y: f64) -> CGA { +fn point_to_cga(x: f64, y: f64) -> CGA { let x_vec = CGA::e1(); let y_vec = CGA::e2(); let _z_vec =CGA::e3(); //This game assumes everything takes place in the plane. @@ -327,14 +391,48 @@ fn bivector_exponential(bivector: &CGA) -> CGA { } } -struct _Asteroid { +struct Asteroid { + circle: CGA, + vel: CGA, +} + +impl Asteroid { + fn new() -> Asteroid { + let v = 0.1; + let (v_x, v_y) = (v * 1.0_f64.cos(), v*1.0_f64.sin()); + let vel = v_x*CGA::e15() + v_y*CGA::e25(); + Self::new_from_coords(0.0_f64, 0.0_f64, 0.1_f64, vel) + } + + fn new_from_coords(x: f64, y: f64, r: f64, vel: CGA) -> Asteroid { + let (a_x, a_y) = (x + r * 0.0_f64.cos(), y + r * 0.0_f64.sin()); + let (b_x, b_y) = (x + r * 1.0_f64.cos(), y + r * 1.0_f64.sin()); + let (c_x, c_y) = (x + r * 2.0_f64.cos(), y + r * 2.0_f64.sin()); + let a = point_to_cga(a_x, a_y); + let b = point_to_cga(b_x, b_y); + let c = point_to_cga(c_x, c_y); + let circle = a^b^c^CGA::e3(); + Asteroid { circle, vel } + } + + fn update(&mut self, dt_s: f64) { + let vel = &self.vel; + let delta = vel * dt_s; + let vel_rotor = bivector_exponential(&delta); + let circle = &vel_rotor*&self.circle*&vel_rotor.Reverse(); + self.circle = circle; + } + + fn draw(&self, context: &CanvasRenderingContext2d) { + draw_line(context, &self.circle); + } } #[wasm_bindgen] pub struct Game { context: CanvasRenderingContext2d, ship: Ship, - //asteroids: Vec::, + asteroids: Vec::, keys: HashSet, } @@ -367,7 +465,8 @@ impl Game { Game { context: context, - ship, + ship, + asteroids: vec![Asteroid::new()], keys: HashSet::new(), } } @@ -380,31 +479,10 @@ impl Game { self.context.set_stroke_style_str(BLACK); self.context.arc(CENTER_X, CENTER_Y, RADIUS, 0., TWO_PI).unwrap(); self.context.stroke(); - - let origin = gen_hyperbolic_point(&CGA::zero()); //Origin in the body frame. - let orient_rotor = &self.ship.orientation; //Transforms body frame to local frame. - let com = &self.ship.com_rotor; //Transforms local frame to world frame. - let v0_rotor = com*orient_rotor*bivector_exponential(&self.ship.verts.0); //Combined transformation to locate a vertex of the ship in the world frame. - let v1_rotor = com*orient_rotor*bivector_exponential(&self.ship.verts.1); //Combined transformation ... - let v2_rotor = com*orient_rotor*bivector_exponential(&self.ship.verts.2); //Combined transformation ... - let p0 = &v0_rotor*&origin*&v0_rotor.Reverse(); //Produce a vertex of the ship in the world frame. - let p1 = &v1_rotor*&origin*&v1_rotor.Reverse(); //... - let p2 = &v2_rotor*&origin*&v2_rotor.Reverse(); //... - - draw_point(&self.context, &(com*&origin*com.Reverse())); - draw_point(&self.context, &p0); - draw_point(&self.context, &p1); - draw_point(&self.context, &p2); - draw_line_between(&self.context, &p0, &p1); - draw_line_between(&self.context, &p1, &p2); - draw_line_between(&self.context, &p2, &p0); - - //Construct and draw line pointing straight ahead, to help orient the player. - let com_p = com * gen_hyperbolic_point(&CGA::zero()) * com.Reverse(); - let delta_gen = com * orient_rotor * CGA::e14() * &orient_rotor.Reverse() * com.Reverse(); - let dot = delta_gen | &com_p; - let line = CGA::e4() ^ com_p ^ dot ^ CGA::e3(); - draw_line(&self.context, &line); + self.ship.draw(&self.context); + for asteroid in &self.asteroids { + asteroid.draw(&self.context); + } } pub fn update(&mut self, dt_m: f64) { @@ -413,35 +491,12 @@ impl Game { } else { dt_m / 1000. }; - let vel = self.ship.vel.clone(); //Velocity at beginning of frame - let mut vel_2 = self.ship.vel.clone(); - let mut a_vec = - DRAG * &vel_2; - - if self.keys.contains("w") { - let orient = &self.ship.orientation; //Transforms body frame to local frame - let pos = &self.ship.com_rotor; //Transforms local frame to world frame - let accel_body = ACCEL_STR * CGA::e15(); //The acceleration in the body frame. - let accel_local = orient * accel_body * orient.Reverse(); //The acceleration in the local frame. - let accel_world = pos * accel_local * pos.Reverse(); //The acceleration in the world frame. - a_vec = a_vec - accel_world; //Sum of drag and thrust. + for asteroid in &mut self.asteroids { + asteroid.update(dt_s); } - if self.keys.contains("q") { - self.ship.orientation = bivector_exponential(&(dt_s * CGA::e12())) * &self.ship.orientation; - } - - if self.keys.contains("e") { - self.ship.orientation = bivector_exponential(&(-dt_s * CGA::e12())) * &self.ship.orientation; - } - - - vel_2 = vel_2 + a_vec*dt_s; //Velocity at end of frame - let vel_3 = 0.5*(vel+&vel_2); - let delta = vel_3 * dt_s; - let pos = bivector_exponential(&delta)*&self.ship.com_rotor; //Update position. - self.ship.vel = vel_2; - self.ship.com_rotor = pos; + self.ship.update(dt_s, &self.keys); } pub fn key_down(&mut self, key: String) {