ajout du programme

This commit is contained in:
2025-10-17 00:08:17 +02:00
parent ca279031f1
commit 62e6fa11c3
12 changed files with 5534 additions and 0 deletions

2
.gitignore vendored Executable file
View File

@@ -0,0 +1,2 @@
/target
fonctions.ods

5106
Cargo.lock generated Executable file

File diff suppressed because it is too large Load Diff

14
Cargo.toml Executable file
View File

@@ -0,0 +1,14 @@
[package]
name = "snake-game"
version = "0.1.0"
edition = "2024"
[dependencies]
bevy = "0.16.1"
rand = "0.9.2"
[profile.dev]
opt-level = 1
[profile.dev.package."*"]
opt-level = 3

88
src/collision.rs Normal file
View File

@@ -0,0 +1,88 @@
use bevy::prelude::*;
/*
on enumere les differents type de collision (il en existe un nombre fini de type)
et on implement une fonction pour creer une variable capable de stocker un type de collision
*/
enum Collision {
No,
Food,
Body,
Border,
}
impl Collision {
fn new() -> Self {
Collision::No
}
}
/*
Systeme de collision entre les differentes entites
*/
fn collision_checker(
head_query: Query<&GridPosition, With<Head>>,
body_query: Query<&GridPosition, With<Body>>,
food_query: Query<&GridPosition, With<Food>>,
) -> Collision {
let mut collision_type = Collision::new();
if food_collision(head_query, food_query) {
collision_type = Collision::Food;
}
if body_collision(head_query, body_query) {
collision_type = Collision::Body;
}
if border_collision(head_query) {
collision_type = Collision::Border;
}
collision_type
}
fn food_collision(
head_query: Query<&GridPosition, With<Head>>,
food_query: Query<&GridPosition, With<Food>>,
) -> bool {
// on balaie parmis les entites qui possedent le composant food (ici un seul) pour tester la collision
for food in &food_query {
for head in &head_query {
if head.x == food.x && head.y == food.y {
return true;
}
}
}
}
fn body_collision(
head_query: Query<&GridPosition, With<Head>>,
body_query: Query<&GridPosition, With<Body>>,
) -> bool {
// on balaie parmis les entites qui possedent le composant body pour tester la collision
for body in &body_query {
for head in &head_query {
if body.x == head.x && body.y == head.y {
// on modifie la valeur retournee par la fonction pour correspondre au type d'entite rencontree
return true;
}
}
}
}
fn border_collision(head_query: Query<&GridPosition, With<Head>>) -> bool {
// teste la position du composant head pour voir si celui-ci sort de la grille
for head in &head_query {
if head.x > 190 || head.x < -190 {
// on modifie la valeur retournee par la fonction pour correspondre au type de collision rencontree
return true;
}
if head.y > 190 || head.y < -190 {
// on modifie la valeur retournee par la fonction pour correspondre au type de collision rencontree
return true;
}
}
}

64
src/components.rs Normal file
View File

@@ -0,0 +1,64 @@
use bevy::prelude::*;
/*
Composant de position sur la grille pour les differentes entites
*/
#[derive(Component)]
pub struct GridPosition {
pub x: i32,
pub y: i32,
}
impl GridPosition {
pub fn new(x: i32, y: i32) -> Self {
Self { x, y }
}
}
/*
Composants qui distinguent les entites entre-elles
*/
#[derive(Component)]
pub struct Head;
#[derive(Component)]
pub struct Body;
#[derive(Component)]
pub struct Food;
#[derive(Component, PartialEq)]
pub enum Direction {
Up,
Down,
Right,
Left,
}
impl Direction {
pub fn new(direction: Direction) -> Self {
direction
}
pub fn change_direction(&mut self, direction: Direction) {
*self = direction;
}
}
#[derive(Component)]
pub struct PreviousPosition {
pub x: i32,
pub y: i32,
}
impl PreviousPosition {
pub fn new(x: i32, y: i32) -> Self {
Self { x, y }
}
}

66
src/food_gen.rs Normal file
View File

@@ -0,0 +1,66 @@
use crate::components::{Body, Food, GridPosition, Head};
use crate::resources::FoodInGrid;
use bevy::prelude::*;
use rand::Rng;
/*
Systeme d'apparition de food sur la grille
*/
pub fn food_spawn(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut food: ResMut<FoodInGrid>,
head_query: Query<&GridPosition, With<Head>>,
body_query: Query<&GridPosition, With<Body>>,
) {
// si il existe deja un food sur la grille, on ignore cette portion de code
if !food.exist() {
let mut result = false;
// tant que le programme de ne donne pas une position libre pour l'apparition du food, on relance la boucle
while result == false {
result = true;
// on recupere une valeur aleatoire pour chaque coordonnee de la position
let x = 10 * random_number();
let y = 10 * random_number();
// puis on compare ces coordonnees a la position actuelle de la tete
for head in &head_query {
if head.x == x && head.y == y {
result = false;
}
}
// ainsi que celle des entites de corps
for body in &body_query {
if body.x == x && body.y == y {
result = false;
}
}
// si la position sur la grille est libre on fait apparaitre un food sur la grille
if result == true {
commands.spawn((
Food,
GridPosition::new(x, y),
Sprite::from_image(asset_server.load("food.png")),
Transform::from_xyz(x as f32, y as f32, 1.0).with_scale(Vec3::splat(0.135)),
));
}
}
// on modifie la ressource FoodInGrid pour dire qu'il existe maintenant un food sur la grille
food.set();
// on joue un audio pour specifier au joueur qu'un food est apparu
commands.spawn(AudioPlayer::new(asset_server.load("i-like-trains.ogg")));
}
}
// fonction de generation de nombre pour la position d'appartition du food
fn random_number() -> i32 {
let mut rng = rand::rng();
rng.random_range(-20..=20)
}

24
src/input_handler.rs Normal file
View File

@@ -0,0 +1,24 @@
use bevy::prelude::*;
// une fonction pour effectuer des actions si un appuis sur un bouton particulier est detecte
pub fn key_pressed(key: Res<ButtonInput<KeyCode>>) -> char {
let mut result: char = '|';
// si la barre espace est appuiye, une iteration de play_train_sfx est lancee
if key.just_pressed(KeyCode::Space) {
result = ' ';
}
// dans le cas ou c'est la touche entree il n'y a encore rien de prevu
if key.just_pressed(KeyCode::KeyW) {
result = 'w';
};
if key.just_pressed(KeyCode::KeyA) {
result = 'a';
};
if key.just_pressed(KeyCode::KeyS) {
result = 's';
};
if key.just_pressed(KeyCode::KeyD) {
result = 'd';
};
result
}

54
src/main.rs Executable file
View File

@@ -0,0 +1,54 @@
// on charge les paquets necessaires au fonctionnement du jeu
// TODO se renseigner sur les plugins
// necessaires pour faire tourner ce jeu
pub mod components;
pub mod food_gen;
pub mod input_handler;
pub mod movement;
pub mod resources;
pub mod sound;
pub mod visuals;
use crate::components::{Direction, GridPosition, Head};
use crate::food_gen::food_spawn;
use crate::movement::{change_direction, move_head};
use crate::resources::{FoodInGrid, MoveTimer};
use crate::visuals::update_visuals;
use bevy::prelude::*;
// fonction main qui creer l'application graphique et execute les fonctions en fonction de la periode designer pour les executer
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.insert_resource(MoveTimer(Timer::from_seconds(1.0, TimerMode::Repeating)))
.add_systems(Startup, (setup, food_spawn).chain())
.add_systems(Update, (change_direction, move_head, update_visuals))
.run();
}
// fonction destinee a initialiser l'application avec les differentes fonctions et assets necessaire au lancement
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// on invoque une camera pour avoir un rendu observable
commands.spawn(Camera2d);
// on charge l'arriere-plan du jeu
commands.spawn((
Sprite::from_image(asset_server.load("grid.png")),
Transform::from_xyz(0.0, 0.0, 0.0),
));
// on charge la tete du serpent a la position voulu
commands.spawn((
Head,
GridPosition::new(10, 10),
Direction::new(Direction::Up),
Sprite::from_image(asset_server.load("head.png")),
Transform::from_xyz(0.0, 0.0, 1.0),
));
// on initialise les ressources
commands.insert_resource(FoodInGrid::new());
}

56
src/movement.rs Normal file
View File

@@ -0,0 +1,56 @@
use crate::components::{Direction, GridPosition, Head, PreviousPosition};
use crate::input_handler::key_pressed;
use crate::resources::MoveTimer;
use bevy::prelude::*;
pub fn change_direction(
key: Res<ButtonInput<KeyCode>>,
mut query_head: Query<(&mut Direction, &GridPosition, &PreviousPosition), With<Head>>,
) {
let value = key_pressed(key);
// change la direction de la tete en fonction de la touche qui a ete pressee
for (mut direction, position, previous_position) in &mut query_head {
match value {
'w' => {
if (position.y + 20) != previous_position.y {
direction.change_direction(Direction::Up);
}
}
'a' => {
if (position.x - 20) != previous_position.x {
direction.change_direction(Direction::Left);
}
}
's' => {
if (position.y - 20) != previous_position.y {
direction.change_direction(Direction::Down);
}
}
'd' => {
if (position.x + 20) != previous_position.x {
direction.change_direction(Direction::Right);
}
}
_ => (),
}
}
}
pub fn move_head(
time: Res<Time>,
mut timer: ResMut<MoveTimer>,
mut query_head: Query<(&mut GridPosition, &Direction), With<Head>>,
) {
// si le timer atteint zero, la tete avance de 20 (la taille d'une case) dans la direction actuelle de la tete
if timer.0.tick(time.delta()).just_finished() {
for (mut position, direction) in &mut query_head {
match direction {
Direction::Up => position.y += 20,
Direction::Down => position.y -= 20,
Direction::Right => position.x += 20,
Direction::Left => position.x -= 20,
}
}
}
}

28
src/resources.rs Normal file
View File

@@ -0,0 +1,28 @@
use bevy::prelude::*;
// creation d'un timer pour cadencer le mouvement de la tete
#[derive(Resource)]
pub struct MoveTimer(pub Timer);
#[derive(Resource)]
pub struct FoodInGrid {
pub state: bool,
}
impl FoodInGrid {
pub fn new() -> Self {
Self { state: false }
}
pub fn set(&mut self) {
self.state = true;
}
pub fn reset(&mut self) {
self.state = false
}
pub fn exist(&self) -> bool {
self.state
}
}

14
src/sound.rs Normal file
View File

@@ -0,0 +1,14 @@
use crate::input_handler::key_pressed;
use bevy::prelude::*;
// un fonction pour jouer l'audio "i like trains"
pub fn play_train_sfx(
key: Res<ButtonInput<KeyCode>>,
mut commands: Commands,
asset_server: Res<AssetServer>,
) {
if key_pressed(key) == ' ' {
commands.spawn(AudioPlayer::new(asset_server.load("train-sfx.ogg")));
}
}

18
src/visuals.rs Normal file
View File

@@ -0,0 +1,18 @@
use crate::components::{Direction, GridPosition, Head};
use bevy::prelude::*;
// actualisation des sprites en fonction des position et de la direction de ceux-ci
pub fn update_visuals(
mut head_query: Query<(&mut Transform, &GridPosition, &Direction), With<Head>>,
) {
for (mut transform, position, direction) in &mut head_query {
transform.translation.x = position.x as f32;
transform.translation.y = position.y as f32;
match direction {
Direction::Up => transform.rotation = Quat::from_rotation_z(0_f32.to_radians()),
Direction::Down => transform.rotation = Quat::from_rotation_z(180_f32.to_radians()),
Direction::Right => transform.rotation = Quat::from_rotation_z(270_f32.to_radians()),
Direction::Left => transform.rotation = Quat::from_rotation_z(90_f32.to_radians()),
}
}
}