185 lines
4.1 KiB
Rust
185 lines
4.1 KiB
Rust
extern crate glutin_window;
|
|
extern crate graphics;
|
|
extern crate opengl_graphics;
|
|
extern crate piston;
|
|
|
|
use piston::window::WindowSettings;
|
|
use piston::input::*;
|
|
use piston::event_loop::*;
|
|
use glutin_window::GlutinWindow;
|
|
use opengl_graphics::{GlGraphics, OpenGL};
|
|
|
|
const PIXEL_SIZE: i32 = 20;
|
|
const FIELD_SIZE_X: i32 = 30;
|
|
const FIELD_SIZE_Y: i32 = 30;
|
|
|
|
#[derive(Clone, PartialEq)]
|
|
enum Direction {
|
|
Up,
|
|
Down,
|
|
Left,
|
|
Right,
|
|
}
|
|
|
|
struct Game {
|
|
gl: GlGraphics,
|
|
snake: Snake,
|
|
food: Food,
|
|
}
|
|
|
|
impl Game {
|
|
fn render(&mut self, args: &RenderArgs) {
|
|
|
|
const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
|
|
|
|
self.gl.draw(args.viewport(), |_c, gl| {
|
|
graphics::clear(BLACK, gl);
|
|
});
|
|
|
|
self.snake.render(&mut self.gl, args);
|
|
|
|
self.food.render(&mut self.gl, args);
|
|
}
|
|
|
|
fn update(&mut self) {
|
|
self.snake.update();
|
|
}
|
|
|
|
fn button_press(&mut self, button: &Button) {
|
|
self.snake.change_direction(&button);
|
|
}
|
|
}
|
|
|
|
struct Snake {
|
|
pos_x: i32,
|
|
pos_y: i32,
|
|
direction: Direction,
|
|
}
|
|
|
|
impl Snake {
|
|
fn render(&self, gl: &mut GlGraphics, args: &RenderArgs) {
|
|
|
|
const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0];
|
|
|
|
let square = graphics::rectangle::square(
|
|
(self.pos_x * PIXEL_SIZE) as f64,
|
|
(self.pos_y * PIXEL_SIZE) as f64,
|
|
PIXEL_SIZE as f64);
|
|
|
|
gl.draw(args.viewport(), |c, gl| {
|
|
let transform = c.transform;
|
|
|
|
graphics::rectangle(GREEN, square, transform, gl);
|
|
});
|
|
}
|
|
|
|
fn update(&mut self) {
|
|
match self.direction {
|
|
Direction::Up => self.pos_y -=1,
|
|
Direction::Down => self.pos_y +=1,
|
|
Direction::Left => self.pos_x -=1,
|
|
Direction::Right => self.pos_x +=1,
|
|
}
|
|
|
|
if self.pos_x > FIELD_SIZE_X {
|
|
self.pos_x = 0;
|
|
} else if self.pos_x < 0 {
|
|
self.pos_x = FIELD_SIZE_X;
|
|
}
|
|
|
|
if self.pos_y > FIELD_SIZE_Y {
|
|
self.pos_y = 0;
|
|
} else if self.pos_y < 0 {
|
|
self.pos_y = FIELD_SIZE_Y;
|
|
}
|
|
|
|
}
|
|
|
|
fn change_direction(&mut self, button: &Button) {
|
|
let last_direction = self.direction.clone();
|
|
|
|
self.direction = match button {
|
|
Button::Keyboard(Key::W) => Direction::Up,
|
|
Button::Keyboard(Key::S) => Direction::Down,
|
|
Button::Keyboard(Key::A) => Direction::Left,
|
|
Button::Keyboard(Key::D) => Direction::Right,
|
|
_ => last_direction,
|
|
}
|
|
}
|
|
}
|
|
|
|
struct Food {
|
|
pos_x: i32,
|
|
pos_y: i32,
|
|
}
|
|
|
|
impl Food {
|
|
fn new() -> Food {
|
|
let random_x: i32 = 3;
|
|
let random_y: i32 = 3;
|
|
|
|
Food { pos_x: random_x, pos_y: random_y }
|
|
}
|
|
|
|
fn render(&self, gl: &mut GlGraphics, args: &RenderArgs) {
|
|
|
|
const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
|
|
|
|
let square = graphics::rectangle::square(
|
|
(self.pos_x * PIXEL_SIZE) as f64,
|
|
(self.pos_y * PIXEL_SIZE) as f64,
|
|
PIXEL_SIZE as f64);
|
|
|
|
gl.draw(args.viewport(), |c, gl| {
|
|
let transform = c.transform;
|
|
|
|
graphics::rectangle(RED, square, transform, gl);
|
|
});
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
let opengl = OpenGL::V3_2;
|
|
|
|
let mut window: GlutinWindow = WindowSettings::new(
|
|
"snake-rs",
|
|
[(FIELD_SIZE_X * PIXEL_SIZE) as f64,
|
|
(FIELD_SIZE_Y * PIXEL_SIZE) as f64])
|
|
.graphics_api(opengl)
|
|
.exit_on_esc(true)
|
|
.build()
|
|
.unwrap();
|
|
|
|
let mut game = Game {
|
|
gl: GlGraphics::new(opengl),
|
|
snake: Snake {
|
|
pos_x: 0,
|
|
pos_y: 0,
|
|
direction: Direction::Right,
|
|
},
|
|
food: Food::new(),
|
|
};
|
|
|
|
|
|
let mut events = Events::new(EventSettings::new())
|
|
.max_fps(60)
|
|
.ups(10);
|
|
while let Some(e) = events.next(&mut window) {
|
|
|
|
if let Some(r) = e.render_args() {
|
|
game.render(&r);
|
|
}
|
|
|
|
if let Some(_u) = e.update_args() {
|
|
game.update();
|
|
}
|
|
|
|
if let Some(b) = e.button_args() {
|
|
if b.state == ButtonState::Press {
|
|
game.button_press(&b.button);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|