snake/src/main.rs

197 lines
6.2 KiB
Rust
Raw Normal View History

2023-01-19 16:11:02 -06:00
#![warn(clippy::pedantic)]
#![allow(clippy::similar_names, clippy::too_many_lines, clippy::enum_glob_use)]
2022-04-30 16:10:10 -05:00
use cat_box::{draw_text, get_keyboard_state, Game, Sprite, SpriteCollection};
2022-04-30 11:08:08 -05:00
use rand::thread_rng;
use rand::Rng;
2022-04-29 11:10:54 -05:00
use sdl2::keyboard::Scancode;
2023-01-19 16:02:19 -06:00
use std::time::Instant;
2022-04-30 10:10:44 -05:00
2022-04-30 12:40:18 -05:00
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
2022-04-30 10:10:44 -05:00
enum Direction {
Up,
Down,
Left,
Right,
}
2022-04-29 11:10:54 -05:00
2022-04-30 12:40:18 -05:00
macro_rules! set_if_not_opp {
($i:ident, $e:expr, $opp:expr) => {
if $i != $opp {
$i = $e
}
};
}
2022-04-29 10:58:56 -05:00
fn main() {
2022-04-29 11:10:54 -05:00
let game = Game::new("Snake", 1000, 1000);
2022-04-29 11:30:14 -05:00
let snake_boxes: Vec<(i32, i32)> = vec![(13, 13), (14, 13)];
let mut snake = SpriteCollection::with_capacity(snake_boxes.len());
for (x, y) in snake_boxes {
let s = Sprite::from_bytes(include_bytes!("../snakecell.png"), x * 37, y * 37).unwrap();
2022-04-29 11:30:14 -05:00
snake.push(s);
}
2022-04-29 11:10:54 -05:00
2022-04-30 11:08:08 -05:00
let mut apple = {
let x = thread_rng().gen_range(0..=27);
let y = thread_rng().gen_range(0..=27);
Sprite::from_bytes(include_bytes!("../apple.png"), x * 37, y * 37).unwrap()
2022-04-30 11:08:08 -05:00
};
2022-04-30 10:10:44 -05:00
let mut dir = Direction::Left;
2022-04-30 16:10:10 -05:00
let mut score = 0u64;
2023-01-19 16:02:19 -06:00
let mut time = Instant::now();
2023-02-28 18:51:41 -06:00
let mut last_pressed = Scancode::A;
2022-04-29 11:10:54 -05:00
game.run(|ctx| {
2022-04-30 16:10:10 -05:00
draw_text(
ctx,
format!("Score: {}", score),
"ibm_bios-2y.ttf",
36,
(100, 100),
cat_box::TextMode::Transparent {
colour: (255, 255, 255),
},
)
.unwrap();
2022-04-29 11:10:54 -05:00
let keys = get_keyboard_state(ctx).keys;
for key in keys {
2022-04-30 10:10:44 -05:00
match key {
Scancode::Q | Scancode::Escape => {
println!("Game over!");
println!("Your score was: {}", score);
game.terminate();
}
2023-02-28 18:51:41 -06:00
s => last_pressed = s,
};
}
if time.elapsed().as_millis() >= 125 {
use Direction::*;
match last_pressed {
2022-04-30 12:40:18 -05:00
Scancode::W | Scancode::Up => set_if_not_opp!(dir, Up, Down),
Scancode::A | Scancode::Left => set_if_not_opp!(dir, Left, Right),
Scancode::S | Scancode::Down => set_if_not_opp!(dir, Down, Up),
Scancode::D | Scancode::Right => set_if_not_opp!(dir, Right, Left),
2022-04-30 10:10:44 -05:00
_ => (),
2023-02-28 18:51:41 -06:00
}
2023-01-19 16:02:19 -06:00
{
let mut last_part = snake[0].position();
2022-04-30 10:50:48 -05:00
2023-01-19 16:02:19 -06:00
for s in snake.iter().skip(1) {
let (lastx, lasty) = last_part.into();
let (x, y) = s.position().into();
2023-01-19 16:02:19 -06:00
let (xdiff, ydiff) = (lastx - x, y - lasty);
last_part = s.position();
s.translate((xdiff, ydiff));
}
2022-04-30 10:50:48 -05:00
}
2023-01-19 16:02:19 -06:00
// The snake head needs to be moved after the body or else the body will just collapse into the head
match dir {
Direction::Up => {
snake[0].translate((0, 37));
}
Direction::Left => {
snake[0].translate((-37, 0));
}
Direction::Down => {
snake[0].translate((0, -37));
}
Direction::Right => {
snake[0].translate((37, 0));
}
};
{
let hitted =
cat_box::physics::check_for_collision_with_collection(&snake[0], &snake);
if hitted.len() > 1 {
println!("Game over!");
println!("Your score was: {}", score);
game.terminate();
}
}
2023-01-19 16:02:19 -06:00
if !cat_box::physics::check_for_collision_with_collection(&apple, &snake).is_empty() {
let x = thread_rng().gen_range(0..=27) * 37;
let y = thread_rng().gen_range(0..=27) * 37;
2022-04-30 11:17:34 -05:00
let (currx, curry) = apple.position().into();
2023-01-19 16:02:19 -06:00
let (xdiff, ydiff) = (x - currx, curry - y);
apple.translate((xdiff, ydiff));
let second_to_last = snake[snake.len() - 2].position();
let last = snake[snake.len() - 1].position();
2022-04-30 12:19:40 -05:00
let direc = check_direction(last.into(), second_to_last.into());
2022-04-30 12:19:40 -05:00
2023-01-19 16:02:19 -06:00
let (newx, newy) = match direc {
Direction::Left => (last.x - 37, last.y),
Direction::Right => (last.x + 37, last.y),
Direction::Up => (last.x, last.y - 37),
Direction::Down => (last.x, last.y + 37),
2023-01-19 16:02:19 -06:00
};
2022-04-30 12:19:40 -05:00
2023-01-19 16:02:19 -06:00
let s = Sprite::new("snakecell.png", newx, newy).unwrap();
snake.push(s);
2022-04-30 16:10:10 -05:00
2023-01-19 16:02:19 -06:00
score += 1;
}
2022-04-30 11:17:34 -05:00
2023-01-19 16:02:19 -06:00
{
let (mut x, mut y) = snake[0].position().into();
2023-01-19 16:02:19 -06:00
x /= 37;
y /= 37;
if dir == Direction::Left || dir == Direction::Right {
if x <= 0 {
let diff = (27 * 37) - (x * 37);
snake[0].translate((diff, 0));
} else if x >= 27 {
let diff = 0 - (x * 37);
snake[0].translate((diff, 0));
}
}
2022-04-30 12:47:42 -05:00
2023-01-19 16:02:19 -06:00
if dir == Direction::Up || dir == Direction::Down {
if y <= 0 {
let diff = (y * 37) - (27 * 37);
snake[0].translate((0, diff));
} else if y >= 27 {
snake[0].translate((0, (y * 37)));
}
}
2022-04-30 12:47:42 -05:00
}
2023-01-19 16:02:19 -06:00
time = Instant::now();
}
2022-04-30 11:08:08 -05:00
apple.draw(ctx).unwrap();
2022-04-29 11:30:14 -05:00
snake.draw(ctx).unwrap();
2022-04-29 11:10:54 -05:00
})
.unwrap();
2022-04-29 10:58:56 -05:00
}
2022-04-30 12:19:40 -05:00
fn check_direction(square1: (i32, i32), square2: (i32, i32)) -> Direction {
2023-01-19 16:11:02 -06:00
use std::cmp::Ordering::*;
use Direction::*;
match square1.0.cmp(&square2.0) {
Less => Left,
Greater => Right,
Equal => match square1.1.cmp(&square2.1) {
Less => Down,
Greater => Up,
Equal => unreachable!(
"why are we still here? just to suffer? (this should never ever ever happen, by the way)"
),
},
}
2022-04-30 12:19:40 -05:00
}