From ab12cef511d51ec01d9b3c3f2931b885c8cd8eb3 Mon Sep 17 00:00:00 2001 From: Rodion Chachura Date: Mon, 30 Dec 2019 17:47:22 +0300 Subject: [PATCH] Chaning snake direction --- src/lib.rs | 75 +++++++++++++++++++++++++++++++++++++++-- www/src/controller.js | 24 +++++++++++++ www/src/game-manager.js | 26 +++++++++++--- 3 files changed, 117 insertions(+), 8 deletions(-) create mode 100644 www/src/controller.js diff --git a/src/lib.rs b/src/lib.rs index 9378238..1290ed4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,6 +58,15 @@ impl Vector { pub fn normalize(&self) -> Vector { self.scale_by(1_f64 / self.length()) } + + pub fn equal_to(&self, other: &Vector) -> bool { + are_equal(self.x, other.x) && are_equal(self.y, other.y) + } + + pub fn is_opposite(&self, other: &Vector) -> bool { + let sum = self.add(other); + sum.equal_to(&Vector::new(0_f64, 0_f64)) + } } pub struct Segment<'a> { @@ -107,6 +116,14 @@ fn get_food(width: i32, height: i32, snake: &[Vector]) -> Vector { free_positions[index] } +#[wasm_bindgen] +pub enum Movement { + TOP, + RIGHT, + DOWN, + LEFT, +} + #[wasm_bindgen] pub struct Game { pub width: i32, @@ -141,7 +158,7 @@ impl Game { } } - fn process_movement(&mut self, timespan: f64) { + fn process_movement(&mut self, timespan: f64, movement: Option) { let distance = self.speed * timespan; let mut tail: Vec = Vec::new(); let mut snake_distance = distance; @@ -162,11 +179,63 @@ impl Game { self.snake = tail; let old_head = self.snake.pop().unwrap(); let new_head = old_head.add(&self.direction.scale_by(distance)); + if movement.is_some() { + let new_direction = match movement.unwrap() { + Movement::TOP => Vector { + x: 0_f64, + y: -1_f64, + }, + Movement::RIGHT => Vector { x: 1_f64, y: 0_f64 }, + Movement::DOWN => Vector { x: 0_f64, y: 1_f64 }, + Movement::LEFT => Vector { + x: -1_f64, + y: 0_f64, + }, + }; + if !self.direction.is_opposite(&new_direction) + && !self.direction.equal_to(&new_direction) + { + let Vector { x: old_x, y: old_y } = old_head; + let old_x_rounded = old_x.round(); + let old_y_rounded = old_y.round(); + let new_x_rounded = new_head.x.round(); + let new_y_rounded = new_head.y.round(); + + let rounded_x_changed = !are_equal(old_x_rounded, new_x_rounded); + let rounded_y_changed = !are_equal(old_y_rounded, new_y_rounded); + if rounded_x_changed || rounded_y_changed { + let (old, old_rounded, new_rounded) = if rounded_x_changed { + (old_x, old_x_rounded, new_x_rounded) + } else { + (old_y, old_y_rounded, new_y_rounded) + }; + let breakpoint_component = old_rounded + + (if new_rounded > old_rounded { + 0.5_f64 + } else { + -0.5_f64 + }); + let breakpoint = if rounded_x_changed { + Vector::new(breakpoint_component, old_y) + } else { + Vector::new(old_x, breakpoint_component) + }; + let vector = + new_direction.scale_by(distance - (old - breakpoint_component).abs()); + let head = breakpoint.add(&vector); + + self.snake.push(breakpoint); + self.snake.push(head); + self.direction = new_direction; + return; + } + } + } self.snake.push(new_head); } - pub fn process(&mut self, timespan: f64) { - self.process_movement(timespan); + pub fn process(&mut self, timespan: f64, movement: Option) { + self.process_movement(timespan, movement); } pub fn get_snake(&self) -> Array { diff --git a/www/src/controller.js b/www/src/controller.js new file mode 100644 index 0000000..7e01c24 --- /dev/null +++ b/www/src/controller.js @@ -0,0 +1,24 @@ +import { Movement } from "wasm-snake-game"; + +const MOVEMENT_KEYS = { + [Movement.TOP]: [87, 38], + [Movement.RIGHT]: [68, 39], + [Movement.DOWN]: [83, 40], + [Movement.LEFT]: [65, 37] +} + +const STOP_KEY = 32 + +export class Controller { + constructor(onStop = () => {}) { + window.addEventListener('keydown', ({ which }) => { + this.movement = Object.keys(MOVEMENT_KEYS).find(key => MOVEMENT_KEYS[key].includes(which)) + }) + window.addEventListener('keyup', ({ which }) => { + this.movement = undefined + if (which === STOP_KEY) { + onStop() + } + }) + } +} \ No newline at end of file diff --git a/www/src/game-manager.js b/www/src/game-manager.js index 9606805..3ae97bd 100644 --- a/www/src/game-manager.js +++ b/www/src/game-manager.js @@ -2,6 +2,7 @@ import { Game, Vector } from 'wasm-snake-game' import CONFIG from './config' import { View } from './view' +import { Controller } from './controller' export class GameManager { constructor() { @@ -11,6 +12,9 @@ export class GameManager { this.game.height, this.render.bind(this) ) + this.controller = new Controller( + this.onStop.bind(this) + ) } restart() { @@ -27,6 +31,16 @@ export class GameManager { console.log(this.game) } + onStop() { + const now = Date.now() + if (this.stopTime) { + this.stopTime = undefined + this.lastUpdate = this.time + now - this.lastUpdate + } else { + this.stopTime = now + } + } + render() { this.view.render( this.game.food, @@ -38,12 +52,14 @@ export class GameManager { } tick() { - const lastUpdate = Date.now() - if (this.lastUpdate) { - this.game.process(lastUpdate - this.lastUpdate) + if (!this.stopTime) { + const lastUpdate = Date.now() + if (this.lastUpdate) { + this.game.process(lastUpdate - this.lastUpdate, this.controller.movement) + } + this.lastUpdate = lastUpdate + this.render() } - this.lastUpdate = lastUpdate - this.render() } run() {