diff --git a/Cargo.lock b/Cargo.lock index e29169d..1c91003 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -294,6 +294,17 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "getrandom" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "wasi", +] + [[package]] name = "gif" version = "0.11.1" @@ -868,6 +879,12 @@ dependencies = [ "miniz_oxide 0.3.7", ] +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + [[package]] name = "proc-macro2" version = "0.4.30" @@ -904,6 +921,47 @@ dependencies = [ "proc-macro2 1.0.24", ] +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core", +] + [[package]] name = "raw-window-handle" version = "0.3.3" @@ -1091,6 +1149,7 @@ dependencies = [ "piston2d-graphics", "piston2d-opengl_graphics", "pistoncore-glutin_window", + "rand", ] [[package]] @@ -1162,6 +1221,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[package]] name = "wayland-client" version = "0.21.13" diff --git a/Cargo.toml b/Cargo.toml index 0bcdeb3..4d14027 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,10 +6,10 @@ edition = "2018" [lib] name="lib" -src = "src/lib.rs" [dependencies] piston = "0.52.0" piston2d-graphics = "0.37.0" pistoncore-glutin_window = "0.67.0" piston2d-opengl_graphics = "0.74.0" +rand = "0.7.3" diff --git a/assets/comfortaa.ttf b/assets/comfortaa.ttf new file mode 100644 index 0000000..dea4cec Binary files /dev/null and b/assets/comfortaa.ttf differ diff --git a/src/lib.rs b/src/lib.rs index 39af40e..00ce054 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ mod snake; +mod renderable; -pub use snake::{Snake, Direction}; +pub use renderable::Renderable; +pub use snake::{Snake, Direction, Square}; diff --git a/src/main.rs b/src/main.rs index 372e6fd..13dd9a3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,33 +8,59 @@ use glutin_window::GlutinWindow; // SHAPES, COLORS AND ALL THAT STUFF use opengl_graphics::{GlGraphics, OpenGL}; // EVENTS, WE NEED A WINDOW CONTROLLER FOR THAT -use piston::event_loop::{EventSettings, Events}; +use piston::event_loop::{EventLoop, EventSettings, Events}; // EVENT ARGUMENTS FOR RENDERING, DONT WORRY JUST USE IT -use piston::input::{ - Button, ButtonEvent, ButtonState, RenderArgs, RenderEvent, UpdateArgs, UpdateEvent, -}; +use piston::input::{Button, ButtonEvent, ButtonState, Key, RenderArgs, RenderEvent, UpdateEvent}; // WINDOW SETTINGS, TO CREATE THE WINDOW CONTROLLER use piston::window::WindowSettings; +use rand::{thread_rng, Rng}; -use lib::{Direction, Snake}; +use lib::{Direction, Renderable, Snake, Square}; + +const SCREEN_SIZE: f64 = 800.0; +const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0]; +const WHITE: [f32; 4] = [1.0; 4]; +const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0]; struct Game { gl: GlGraphics, snake: Snake, + apple: Square, } impl Game { - fn render(&mut self, args: &RenderArgs) {} + fn render(&mut self, args: &RenderArgs) { + use graphics::*; + clear(BLACK, &mut self.gl); + self.snake.render(&mut self.gl, &args, WHITE); + self.apple.render(&mut self.gl, &args, RED); + } - fn update(&mut self, args: &UpdateArgs) {} + fn update(&mut self) { + self.snake.move_forwards(); + let head = self.snake.head(); + if head.collision(&self.apple) { + self.apple.x = thread_rng().gen_range(0.0 + 20.0, SCREEN_SIZE - 20.0); + self.apple.y = thread_rng().gen_range(0.0 + 20.0, SCREEN_SIZE - 20.0); + self.snake.add_square(); + } + } - fn key_press(&mut self, key: Button) {} + fn key_press(&mut self, key: Button) { + match key { + Button::Keyboard(Key::D) => self.snake.rotate(Direction::Right), + Button::Keyboard(Key::A) => self.snake.rotate(Direction::Left), + Button::Keyboard(Key::W) => self.snake.rotate(Direction::Up), + Button::Keyboard(Key::S) => self.snake.rotate(Direction::Down), + _ => (), + } + } } fn main() { let opengl = OpenGL::V3_1; - let mut window: GlutinWindow = WindowSettings::new("Snake Game", [400, 400]) + let mut window: GlutinWindow = WindowSettings::new("Snake Game", [SCREEN_SIZE; 2]) .fullscreen(true) .exit_on_esc(true) .resizable(false) @@ -43,15 +69,24 @@ fn main() { let mut game = Game { gl: GlGraphics::new(opengl), - snake: Snake::new(0.0, 0.0), + snake: Snake::new(200.0, 200.0), + apple: Square { + x: thread_rng().gen_range(0.0 + 20.0, SCREEN_SIZE - 20.0), + y: thread_rng().gen_range(0.0 + 20.0, SCREEN_SIZE - 20.0), + size: 20.0, + }, }; - let mut events = Events::new(EventSettings::new()); + let mut events = Events::new(EventSettings::new()).ups(20); while let Some(e) = events.next(&mut window) { - if let Some(arg) = e.render_args() {} + if let Some(_) = e.update_args() { + game.update(); + } - if let Some(arg) = e.update_args() {} + if let Some(arg) = e.render_args() { + game.render(&arg); + } if let Some(arg) = e.button_args() { if let ButtonState::Press = arg.state { diff --git a/src/renderable/mod.rs b/src/renderable/mod.rs new file mode 100644 index 0000000..2cae91a --- /dev/null +++ b/src/renderable/mod.rs @@ -0,0 +1,7 @@ +use opengl_graphics::GlGraphics; +use piston::input::RenderArgs; +use graphics::types::Color; +pub trait Renderable{ + fn render(&mut self, gl: &mut GlGraphics, args: &RenderArgs, color: Color); +} + diff --git a/src/snake/mod.rs b/src/snake/mod.rs index f4bb623..eae4573 100644 --- a/src/snake/mod.rs +++ b/src/snake/mod.rs @@ -1,6 +1,26 @@ +use crate::renderable::Renderable; +use graphics::types::Color; +use opengl_graphics::GlGraphics; +use piston::input::RenderArgs; use std::collections::LinkedList; use std::iter::FromIterator; +#[derive(PartialEq, Clone, Debug)] +pub struct Square { + pub x: f64, + pub y: f64, + pub size: f64, +} + +impl Square { + pub fn collision(&self, other: &Square) -> bool { + self.x + self.size >= other.x + && self.x <= other.x + other.size + && self.y + self.size >= other.y + && self.y <= other.y + self.size + } +} + #[derive(PartialEq, Clone)] pub enum Direction { Up, @@ -10,16 +30,19 @@ pub enum Direction { } pub struct Snake { - pub body: LinkedList<(f64, f64)>, + pub body: LinkedList, direction: Direction, } impl Snake { - pub const VELOCITY: f64 = 8.0; pub const SIZE: f64 = 20.0; pub fn new(x: f64, y: f64) -> Self { - let body: LinkedList<(f64, f64)> = LinkedList::from_iter(vec![(x, y)].into_iter()); + let body = LinkedList::from_iter(vec![Square { + x, + y, + size: Self::SIZE, + }]); Snake { body, direction: Direction::Right, @@ -32,29 +55,56 @@ impl Snake { Direction::Down if self.direction != Direction::Up => self.direction = direction, Direction::Left if self.direction != Direction::Right => self.direction = direction, Direction::Right if self.direction != Direction::Left => self.direction = direction, - _ => () + _ => (), } } pub fn move_forwards(&mut self) { - let mut head: (f64, f64) = self - .body - .front() - .expect("Cannot move an empty snake") - .clone(); + let mut head: Square = self.body.front().unwrap().clone(); + match self.direction { - Direction::Up => head.1 -= Snake::VELOCITY, - Direction::Down => head.1 += Snake::VELOCITY, - Direction::Left => head.0 -= Snake::VELOCITY, - Direction::Right => head.0 += Snake::VELOCITY, + Direction::Up => head.y -= Snake::SIZE, + Direction::Down => head.y += Snake::SIZE, + Direction::Left => head.x -= Snake::SIZE, + Direction::Right => head.x += Snake::SIZE, } + self.body.pop_back(); self.body.push_front(head); } pub fn add_square(&mut self) { - let back = self.body.back().unwrap(); - let new_part = (back.0, back.1); + let tail = self.body.back().unwrap(); + let new_part = Square { + x: tail.x, + y: tail.y, + size: Self::SIZE, + }; self.body.push_back(new_part); } + + pub fn head(&self) -> &Square { + self.body.front().unwrap() + } +} + +impl Renderable for Square { + fn render(&mut self, gl: &mut GlGraphics, args: &RenderArgs, color: Color) { + gl.draw(args.viewport(), |c, gl| { + use graphics::*; + let square = rectangle::square(self.x, self.y, self.size); + let transform = c.transform.trans(-self.size / 2.0, -self.size / 2.0); + rectangle(color, square, transform, gl); + }); + } +} + +impl Renderable for Snake { + fn render(&mut self, gl: &mut GlGraphics, args: &RenderArgs, color: Color) { + gl.draw(args.viewport(), |_, gl| { + self.body + .iter_mut() + .for_each(|square| square.render(gl, args, color)); + }); + } }