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;
|
2022-04-30 10:10:44 -05:00
|
|
|
use std::time::Duration;
|
|
|
|
|
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::new("snakecell.png", x * 37, y * 37).unwrap();
|
|
|
|
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::new("apple.png", x * 37, y * 37).unwrap()
|
|
|
|
};
|
|
|
|
|
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;
|
|
|
|
|
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 12:40:18 -05:00
|
|
|
use Direction::*;
|
2022-04-30 10:10:44 -05:00
|
|
|
match key {
|
2022-04-30 17:15:22 -05:00
|
|
|
Scancode::Q | Scancode::Escape => {
|
|
|
|
println!("Game over!");
|
|
|
|
println!("Your score was: {}", score);
|
|
|
|
game.terminate();
|
|
|
|
}
|
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
|
|
|
_ => (),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-04-30 10:50:48 -05:00
|
|
|
{
|
|
|
|
let mut last_part = snake[0].position();
|
|
|
|
|
|
|
|
for s in snake.iter().skip(1) {
|
|
|
|
let (lastx, lasty) = last_part;
|
|
|
|
let (x, y) = s.position();
|
|
|
|
let (xdiff, ydiff) = (lastx - x, y - lasty);
|
|
|
|
last_part = s.position();
|
2022-04-30 12:19:40 -05:00
|
|
|
s.translate((xdiff, ydiff));
|
2022-04-30 10:50:48 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// The snake head needs to be moved after the body or else the body will just collapse into the head
|
2022-04-30 10:10:44 -05:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-04-30 17:15:22 -05:00
|
|
|
{
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-30 12:40:18 -05:00
|
|
|
if !cat_box::physics::check_for_collision_with_collection(&apple, &snake).is_empty() {
|
2022-04-30 11:17:34 -05:00
|
|
|
let x = thread_rng().gen_range(0..=27) * 37;
|
|
|
|
let y = thread_rng().gen_range(0..=27) * 37;
|
|
|
|
|
|
|
|
let (currx, curry) = apple.position();
|
|
|
|
let (xdiff, ydiff) = (x - currx, curry - y);
|
|
|
|
apple.translate((xdiff, ydiff));
|
2022-04-30 12:19:40 -05:00
|
|
|
let second_to_last = snake[snake.len() - 2].position();
|
|
|
|
let last = snake[snake.len() - 1].position();
|
|
|
|
|
|
|
|
let direc = check_direction(last, second_to_last);
|
|
|
|
|
|
|
|
let (newx, newy) = match direc {
|
|
|
|
Direction::Left => (last.0 - 37, last.1),
|
|
|
|
Direction::Right => (last.0 + 37, last.1),
|
|
|
|
Direction::Up => (last.0, last.1 - 37),
|
|
|
|
Direction::Down => (last.0, last.1 + 37),
|
|
|
|
};
|
|
|
|
|
|
|
|
let s = Sprite::new("snakecell.png", newx, newy).unwrap();
|
|
|
|
snake.push(s);
|
2022-04-30 16:10:10 -05:00
|
|
|
|
|
|
|
score += 1;
|
2022-04-30 11:17:34 -05:00
|
|
|
}
|
|
|
|
|
2022-04-30 12:47:42 -05:00
|
|
|
{
|
|
|
|
let (mut x, mut y) = snake[0].position();
|
|
|
|
x /= 37;
|
|
|
|
y /= 37;
|
|
|
|
|
2022-04-30 16:21:04 -05:00
|
|
|
if dir == Direction::Left || dir == Direction::Right {
|
2022-04-30 17:02:08 -05:00
|
|
|
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 16:21:04 -05:00
|
|
|
}
|
|
|
|
}
|
2022-04-30 12:47:42 -05:00
|
|
|
|
2022-04-30 16:21:04 -05:00
|
|
|
if dir == Direction::Up || dir == Direction::Down {
|
2022-04-30 17:02:08 -05:00
|
|
|
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 16:21:04 -05:00
|
|
|
}
|
2022-04-30 12:47:42 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-30 10:50:48 -05:00
|
|
|
// So that the snake doesn't move at super speed
|
2022-04-30 10:10:44 -05:00
|
|
|
std::thread::sleep(Duration::from_millis(125));
|
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 {
|
|
|
|
if square1.0 < square2.0 {
|
|
|
|
return Direction::Left;
|
|
|
|
} else if square1.0 > square2.0 {
|
|
|
|
return Direction::Right;
|
|
|
|
};
|
|
|
|
if square1.1 > square2.1 {
|
|
|
|
return Direction::Up;
|
|
|
|
} else if square1.1 < square2.1 {
|
|
|
|
return Direction::Down;
|
|
|
|
};
|
|
|
|
|
2022-04-30 17:29:10 -05:00
|
|
|
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
|
|
|
}
|