1 use core::controller::Controller;
2 use core::object::boll::Boll;
3 use core::level::{Level, Wall, IntersectResult::Intersection};
4 use core::object::{Object, Objects, ObjectState};
5 use core::render::Renderer;
9 use sprites::SpriteManager;
10 use std::cell::RefCell;
14 ////////// STATE ///////////////////////////////////////////////////////////////
19 fn update(&mut self, body: &mut Body, ctrl: &Controller, objects: &mut Objects, lvl: &Level, dt: Duration) -> Option<Box<dyn State>>;
22 ////////// CHARACTER ///////////////////////////////////////////////////////////
27 pub standing_on: Option<Wall>,
30 struct StateHolder(Box<dyn State>);
33 pub fn get(&mut self) -> &mut Box<dyn State> {
37 pub fn set(&mut self, state: Box<dyn State>) {
44 pub struct Character {
45 ctrl: Rc<RefCell<Controller>>,
47 state: StateHolder, // Plays well with the borrow checker
51 pub fn new(ctrl: Rc<RefCell<Controller>>) -> Self {
55 pos: point!(300.0, 300.0),
56 vel: point!(0.0, 0.0),
59 state: StateHolder(Box::new(FallState)),
64 impl Object for Character {
65 fn update(&mut self, objects: &mut Objects, lvl: &Level, dt: Duration) -> ObjectState {
66 let ctrl = self.ctrl.borrow();
68 if let Some(state) = self.state.get().update(&mut self.body, &ctrl, objects, lvl, dt) {
69 self.state.set(state);
72 match &self.body.standing_on {
76 if let Intersection(wall, pos) = lvl.intersect_walls(self.body.pos - self.body.vel, self.body.pos) {
77 self.body.standing_on = Some(wall);
79 self.body.vel = point!(0.0, 0.0);
80 self.state.set(Box::new(StandState));
85 if ctrl.shoot.is_pressed {
86 use rand::distributions::{Distribution, Normal};
87 let normal = Normal::new(0.0, 0.1);
88 let direction = if ctrl.aim.to_point().length() > 0.1 { ctrl.aim.to_point() } else { ctrl.mov.to_point() };
90 objects.push(Box::new(Boll::new(
91 self.body.pos + point!(0.0, -16.0), // half the height of mario
92 direction * (10.0 + rand::random::<f64>()) + point!(normal.sample(&mut rand::thread_rng()), normal.sample(&mut rand::thread_rng())) + self.body.vel,
97 self.body.vel -= direction * 0.1;
103 fn render(&self, renderer: &mut Renderer, sprites: &SpriteManager) {
104 let block = sprites.get("mario");
106 renderer.blit(block, None, Rect::new(self.body.pos.x as i32 - size as i32 / 2, self.body.pos.y as i32 - size as i32, size, size));
108 let ctrl = &self.ctrl.borrow();
110 let pos = (self.body.pos.x as i32, self.body.pos.y as i32);
112 // let p = (self.body.pos + ctrl.aim.to_axis_point() * l).to_i32().into();
113 // renderer.draw_line(pos, p, (0, 255, 0));
114 // draw_cross(renderer, p);
115 // values limited to unit vector
116 let p = (self.body.pos + ctrl.aim.to_point() * l).to_i32().into();
117 renderer.draw_line(pos, p, (255, 0, 0));
118 draw_cross(renderer, p);
119 let p = (self.body.pos + ctrl.mov.to_point() * l).to_i32().into();
120 renderer.draw_line(pos, p, (0, 255, 0));
121 draw_cross(renderer, p);
123 // let p = (self.body.pos + Point::from(ctrl.aim.a) * l).to_i32().into();
124 // renderer.draw_line(pos, p, (0, 0, 255));
125 // draw_cross(renderer, p);
129 fn draw_cross(renderer: &mut Renderer, p: (i32, i32)) {
130 renderer.canvas().draw_line((p.0 - 5, p.1), (p.0 + 5, p.1)).unwrap();
131 renderer.canvas().draw_line((p.0, p.1 - 5), (p.0, p.1 + 5)).unwrap();
134 ////////// FALLING /////////////////////////////////////////////////////////////
138 impl State for FallState {
139 fn update(&mut self, body: &mut Body, ctrl: &Controller, _objects: &mut Objects, lvl: &Level, _dt: Duration) -> Option<Box<dyn State>> {
140 body.vel += lvl.gravity;
141 body.pos += body.vel;
144 v if v < -0.9 && body.vel.x > -5.0 => { body.vel.x -= 0.5 }
145 v if v > 0.9 && body.vel.x < 5.0 => { body.vel.x += 0.5 }
153 ////////// STANDING /////////////////////////////////////////////////////////////
157 impl State for StandState {
158 fn update(&mut self, body: &mut Body, ctrl: &Controller, _objects: &mut Objects, _lvl: &Level, _dt: Duration) -> Option<Box<dyn State>> {
159 if let Some(wall) = &body.standing_on {
160 if ctrl.jump.is_pressed && !ctrl.jump.was_pressed {
161 if ctrl.mov.to_point().length() < 0.1 {
162 body.vel = wall.normal().into();
164 body.vel = ctrl.mov.to_point();
167 body.pos += body.vel * 0.1;
168 body.standing_on = None;
169 return Some(Box::new(FallState))