Commit 3c618630 authored by DEBATY Thomas's avatar DEBATY Thomas
Browse files

Init git !

parents
Blue_F1.png

38.5 KB

File added
# Instructions pour le Projet NEAT et Configuration des Cartes et Voitures
## Création de l'environnement virtuel
### Sous Windows
```bash
python3 -m venv env
.\env\Scripts\activate
```
### Sous Linux
```bash
python3 -m venv env
source ./env/bin/activate
```
### Installation des dépendances
```bash
pip install -r requirements.txt
```
---
## Variables Modifiables
### Fichier `road_maker.py`
- **Nom de la carte à sauvegarder ou à charger :**
```python
map_save_or_load_name = "nom_de_la_map" # Ne pas inclure l'extension (.png ou .json)
```
- **Dimensions de la fenêtre :**
```python
WIDTH = 1400
HEIGHT = 700 # Largeur x Hauteur en pixels
```
- **Couleurs personnalisables :**
```python
ROAD_COLOR = (128, 128, 128) # Gris pour la route
GRASS_COLOR = (0, 200, 0) # Vert pour l'herbe
CHECKPOINT_COLOR = (255, 255, 0) # Jaune pour les checkpoints
START_COLOR = (0, 0, 255) # Bleu pour la position de départ
```
- **Paramètres du pinceau :**
```python
BRUSH_COLOR = ROAD_COLOR # Couleur du pinceau (par défaut : route)
BRUSH_SIZE = 30 # Taille du pinceau en pixels
```
---
### Fichier `main_neat_code_here.py`
- **Nom de la carte à charger :**
```python
map_load_name = "nom_de_la_map" # Ne pas inclure l'extension (.png ou .json)
```
- **Configuration de la voiture :**
```python
CAR_MAX_SPEED = 175 # Vitesse maximale de la voiture
CAR_MIN_SPEED = 0 # Vitesse minimale de la voiture
CAR_ACCELERATION = 75 # Accélération de la voiture
```
- **Angles pour le raycasting (en degrés) :**
```python
Raycast_angles = [-67.5, -45, -22.5, 0, 22.5, 45, 67.5] # Angles des rayons de détection
```
- **Personnalisation de l'image de la voiture :**
```python
image_path = "Blue_F1.png" # Chemin vers l'image de la voiture
```
- **Nom de l'équipe :**
```python
team_name = "nom_d'équipe" # Remplacez par le nom de votre équipe
```
- **Temps par génération :**
```python
max_time = 1000 # Temps maximum avant la fin de la génération
```
- **Nombre max de générations :**
```python
nb_generation = 50 # Nombre maximum de générations
```
---
### Fichier `map.py`
- **Couleur de l'herbe dans la carte (il faut mettre la même que sur l'image !) :**
```python
grass_color = (0, 200, 0) # Vert pour l'herbe
```
---
### Fichier `config-feedfoward.txt`
- **Ne pas modifier le nombre de sorties !** Il doit rester à 2.
- Le reste est librement modifiable.
---
## Fonction fitness
Pour que les réseaux soient classés, il faut leur attribuer une valeur. Cela est fait par une fonction de fitness.
Pour accéder à la valeur de fitness, il faut utiliser : `ge[i].fitness`, où `i` est l'index de la voiture dans sa liste.
Exemples :
```python
ge[i].fitness -= 0.001 # Perte de fitness au fil du temps
```
ou
```python
if lap_counters[i].laps_completed > previous_laps:
ge[i].fitness += 10000 # Très grande récompense pour un tour complété
```
---
## Résultat final
Une fois l'entraînement terminé, c'est-à-dire :
- **Option 1** : l'objectif de fitness est atteint (`fitness_threshold` dans `config-feedfoward.txt`).
- **Option 2** : le nombre maximum de générations est atteint (`nb_generation = 50` dans `main_neat_code_here.py`).
Tout est enregistré automatiquement dans un dossier "final_result" qu'il faudra compresser (zip) et nous envoyer.
\ No newline at end of file
import math
import pygame
class Car:
def __init__(self, x, y, image_path= "Car_red_Frong.png", width=20, height=40, max_speed=200, acceleration=200, turn_speed=180, min_speed=0):
"""
Initialise une voiture avec sa position, ses caractéristiques de mouvement et son image.
:param x: Position initiale en x.
:param y: Position initiale en y.
:param image_path: Chemin de l'image de la voiture.
:param width: Largeur de l'image de la voiture.
:param height: Hauteur de l'image de la voiture.
:param max_speed: Vitesse maximale de la voiture.
:param acceleration: Accélération de la voiture.
:param turn_speed: Vitesse de rotation de la voiture.
"""
self.width = width # Largeur de la voiture
self.height = height # Hauteur de la voiture
self.position = pygame.Vector2(x, y) # Position de la voiture (vecteur 2D)
self.velocity = pygame.Vector2(0, 0) # Vitesse actuelle (vecteur 2D)
self.lateral_velocity = 0 # Vitesse latérale pour simuler les dérapages
self.angle = -90 # Angle initial de la voiture en degrés
self.speed = 0 # Vitesse initiale
self.max_speed = max_speed # Vitesse maximale réglable
self.min_speed = min_speed # Vitesse minimal réglable
self.acceleration = acceleration # Accélération réglable
self.deceleration = acceleration # Utilisation de la même valeur pour la décélération
self.turn_speed = turn_speed # Vitesse de rotation réglable
self.drift_factor = 0.8 # Facteur de dérapage (contrôle l'intensité du dérapage)
# Chargement et préparation de l'image de la voiture
self.surface = pygame.image.load(image_path).convert_alpha() # Chargement de l'image avec transparence
self.surface = pygame.transform.scale(self.surface, (self.width, self.height)) # Mise à l'échelle de l'image
self.surface = pygame.transform.rotate(self.surface, 180) # Rotation initiale de l'image
self.active = True # Indique si la voiture est toujours en course (active)
def update(self, dt):
"""
Met à jour la position et la vitesse de la voiture en fonction de la vitesse actuelle, de l'angle, et du dérapage.
:param dt: Temps écoulé depuis la dernière mise à jour (delta time).
"""
# Limiter la vitesse
self.speed = max(min(self.speed, self.max_speed), -self.max_speed / 2)
# Effet de dérapage : la vitesse latérale est influencée par la vitesse et l'angle de rotation
if abs(self.speed) > self.max_speed * 0.5 and abs(self.lateral_velocity) < 20: # Seuil pour activer le dérapage
self.lateral_velocity += (self.turn_speed * dt) * self.drift_factor
# Réduction progressive de la vitesse latérale (friction)
self.lateral_velocity *= 0.95
# Mise à jour de la position
rad_angle = math.radians(self.angle) # Conversion de l'angle en radians
# Mouvement vers l'avant
self.velocity.x = -self.speed * math.sin(rad_angle) # Calcul de la composante x de la vitesse
self.velocity.y = -self.speed * math.cos(rad_angle) # Calcul de la composante y de la vitesse
# Mouvement latéral (pendant le dérapage)
drift_vector = pygame.Vector2(self.lateral_velocity * math.cos(rad_angle),
self.lateral_velocity * math.sin(rad_angle))
# Mise à jour de la position avec les mouvements vers l'avant et latéral (dérapage)
self.position += (self.velocity + drift_vector) * dt
def draw(self, screen):
"""
Dessine la voiture sur l'écran.
:param screen: Surface de l'écran sur laquelle la voiture sera dessinée.
"""
# Rotation de l'image de la voiture
rotated_surface = pygame.transform.rotate(self.surface, self.angle)
rect = rotated_surface.get_rect(center=self.position) # Création d'un rectangle centré sur la position actuelle
screen.blit(rotated_surface, rect) # Dessiner l'image de la voiture sur l'écran
def check_collision(self, map_instance):
"""
Vérifie les collisions pixel par pixel avec les zones d'herbe sur la carte à l'aide de masques.
:param map_instance: Instance de la carte avec laquelle la voiture peut entrer en collision.
:return: True si une collision est détectée, sinon False.
"""
# Rotation de l'image de la voiture et création d'un masque
rotated_surface = pygame.transform.rotate(self.surface, self.angle)
rotated_mask = pygame.mask.from_surface(rotated_surface) # Création d'un masque à partir de l'image
rect = rotated_surface.get_rect(center=self.position)
# Décalage pour la vérification de chevauchement des masques
offset = (int(rect.left), int(rect.top))
# Vérifier le chevauchement entre le masque de la voiture et le masque de l'herbe de la carte
if map_instance.grass_mask.overlap(rotated_mask, offset):
return True # Collision détectée
return False
def reset(self, start_position):
"""
Réinitialise la voiture à la position de départ et remet à zéro la vitesse, l'angle, et la vitesse latérale.
:param start_position: Position de départ (vecteur 2D).
"""
self.position = pygame.Vector2(start_position) # Réinitialiser la position
self.velocity = pygame.Vector2(0, 0) # Réinitialiser la vitesse
self.lateral_velocity = 0 # Réinitialiser la vitesse latérale
self.speed = 0 # Réinitialiser la vitesse
self.angle = -90 # Réinitialiser l'angle de la voiture
\ No newline at end of file
[NEAT]
fitness_criterion = max
fitness_threshold = 100000000
pop_size = 200
reset_on_extinction = True
[DefaultGenome]
# node activation options
activation_default = tanh
activation_mutate_rate = 0.01
activation_options = tanh sigmoid relu
# node aggregation options
aggregation_default = sum
aggregation_mutate_rate = 0.01
aggregation_options = sum mean max
# node bias options
bias_init_mean = 0.0
bias_init_stdev = 1.0
bias_init_type = gaussian
bias_max_value = 30.0
bias_min_value = -30.0
bias_mutate_power = 0.5
bias_mutate_rate = 0.7
bias_replace_rate = 0.1
# genome compatibility options
compatibility_disjoint_coefficient = 1.0
compatibility_weight_coefficient = 0.5
# connection add/remove rates
conn_add_prob = 0.5
conn_delete_prob = 0.5
# connection enable options
enabled_default = True
enabled_mutate_rate = 0.01
feed_forward = True
initial_connection = full
# node add/remove rates
node_add_prob = 0.2
node_delete_prob = 0.2
# network parameters
num_hidden = 0
num_inputs = 9
num_outputs = 2
# node response options
response_init_mean = 1.0
response_init_stdev = 0.0
response_init_type = gaussian
response_max_value = 30.0
response_min_value = -30.0
response_mutate_power = 0.0
response_mutate_rate = 0.0
response_replace_rate = 0.0
# connection weight options
weight_init_mean = 0.0
weight_init_stdev = 1.0
weight_max_value = 20
weight_min_value = -20
weight_mutate_power = 0.5
weight_mutate_rate = 0.8
weight_replace_rate = 0.1
[DefaultSpeciesSet]
compatibility_threshold = 2.0
[DefaultStagnation]
species_fitness_func = max
max_stagnation = 6
species_elitism = 2
[DefaultReproduction]
elitism = 3
survival_threshold = 0.2
\ No newline at end of file
import pygame
def line_intersect(a1, a2, b1, b2):
"""
Détermine si les segments de droite a1a2 et b1b2 se croisent.
Paramètres :
a1, a2 : tuples ou listes (float, float)
Les points définissant le premier segment de droite.
b1, b2 : tuples ou listes (float, float)
Les points définissant le deuxième segment de droite.
Retourne :
bool : True si les segments se croisent, sinon False.
"""
# Définition d'une fonction interne pour vérifier l'orientation des points
def ccw(A, B, C):
# Retourne True si les points A, B, C sont dans le sens anti-horaire
return (C.y - A.y) * (B.x - A.x) > (B.y - A.y) * (C.x - A.x)
# Conversion des points en vecteurs Pygame
A = pygame.Vector2(a1)
B = pygame.Vector2(a2)
C = pygame.Vector2(b1)
D = pygame.Vector2(b2)
# Vérifie si les segments se croisent en utilisant les orientations
return (ccw(A, C, D) != ccw(B, C, D)) and (ccw(A, B, C) != ccw(A, B, D))
class LapCounter:
def __init__(self, checkpoints):
"""
Initialise le compteur de tours avec une liste de checkpoints.
Paramètres :
checkpoints : list
Liste de dictionnaires contenant les checkpoints avec des clés 'start', 'end', et 'order'.
"""
# Trie les checkpoints en fonction de leur ordre
self.checkpoints = sorted(checkpoints, key=lambda x: x['order'])
# Initialise l'indice du checkpoint actuel
self.current_checkpoint = 0
# Initialise le nombre de tours complétés
self.laps_completed = 0
def check_checkpoint(self, old_pos, new_pos):
"""
Vérifie si le joueur a passé un checkpoint en se déplaçant de l'ancienne position à la nouvelle position.
Paramètres :
old_pos : tuple ou liste (float, float)
Position précédente du joueur.
new_pos : tuple ou liste (float, float)
Nouvelle position du joueur.
"""
# Vérifie si tous les checkpoints ont été franchis
if self.current_checkpoint >= len(self.checkpoints):
# Tous les checkpoints ont été franchis, commence un nouveau tour
self.current_checkpoint = 0
self.laps_completed += 1
#print(f"Tour complété ! Total des tours : {self.laps_completed}")
# Récupère le checkpoint actuel
checkpoint = self.checkpoints[self.current_checkpoint]
start = checkpoint['start']
end = checkpoint['end']
# Vérifie si la trajectoire entre l'ancienne et la nouvelle position croise le checkpoint
if line_intersect(old_pos, new_pos, start, end):
# Incrémente l'indice du checkpoint actuel
self.current_checkpoint += 1
#print(f"Checkpoint {checkpoint['order']} franchi !")
\ No newline at end of file
import pygame
import sys
from car_neat import Car
from raycast import Raycast
from map import Map
from lap_counter import LapCounter
from PIL import Image
# Initialise Pygame
pygame.init()
# Charge l'image de la carte et récupère ses dimensions
map_path = "road.png"
with Image.open(map_path) as map:
width, height = map.size
# Définition des dimensions de la fenêtre du jeu
WIDTH, HEIGHT = width, height
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Contrôle Manuel de la Voiture")
# Horloge pour contrôler le taux de rafraîchissement
clock = pygame.time.Clock()
# Variables de configuration de la voiture
CAR_WIDTH = 13 # Largeur de la voiture
CAR_HEIGHT = 23 # Hauteur de la voiture
CAR_TURN_SPEED = 150 # Vitesse de rotation de la voiture
CAR_MAX_SPEED = 175 # Vitesse maximale de la voiture
CAR_MIN_SPEED = 0 # Vitesse minimale de la voiture
CAR_ACCELERATION = 75 # Accélération de la voiture
image_path = "Red_Car.png" # Chemin vers l'image de la voiture
# Création de l'objet voiture
# Utilise la position de départ de la carte pour initialiser la voiture
game_map = Map()
car = Car(game_map.start_position[0], game_map.start_position[1],
width=CAR_WIDTH, height=CAR_HEIGHT,
max_speed=CAR_MAX_SPEED, acceleration=CAR_ACCELERATION,
turn_speed=CAR_TURN_SPEED, image_path=image_path)
# Variable pour indiquer si le jeu est en cours
running = True
# Boucle principale du jeu
while running:
# Rafraîchit l'affichage de Pygame
pygame.display.flip()
# Dessine l'environnement de jeu
game_map.draw(screen)
# Calcul du delta temps réel en utilisant l'horloge
dt = clock.tick(60) / 1000 # Delta temps en secondes (temps réel)
# Limite le delta temps pour éviter des sauts trop grands (utile quand les FPS chutent)
dt = min(dt, 1 / 30) # Limite dt à un maximum de 1/30 de seconde
# Gestion des événements
for event in pygame.event.get():
if event.type == pygame.QUIT: # Si l'utilisateur ferme la fenêtre
running = False
pygame.quit()
sys.exit()
# Récupère les touches enfoncées
keys = pygame.key.get_pressed()
# Logique d'accélération/décélération
if keys[pygame.K_UP]:
car.speed += CAR_ACCELERATION * dt # Accélère la voiture
car.speed = min(car.speed, CAR_MAX_SPEED) # Limite la vitesse maximale
elif keys[pygame.K_DOWN]:
car.speed -= CAR_ACCELERATION * dt # Décélère la voiture
car.speed = max(car.speed, CAR_MIN_SPEED) # Limite la vitesse minimale
# Logique de rotation
if keys[pygame.K_RIGHT] and abs(car.speed) > 0:
car.angle -= CAR_TURN_SPEED * dt # Tourne à droite
elif keys[pygame.K_LEFT] and abs(car.speed) > 0:
car.angle += CAR_TURN_SPEED * dt # Tourne à gauche
# Mise à jour de la voiture avec les nouvelles valeurs
car.update(dt)
# Dessine la voiture sur l'écran
car.draw(screen)
# Vérifie la collision avec la carte
if car.check_collision(game_map):
print("Collision détectée ! Réinitialisation de la position de la voiture.")
car.reset(game_map.start_position) # Réinitialise la position de la voiture
car.speed = 0 # Réinitialise la vitesse à 0
# Point d'entrée du script
if __name__ == "__main__":
pass
\ No newline at end of file
import pygame
import neat
import sys
import os
import pickle
#from FINAL_CAR_RACE import car_min_speed
from car_neat import Car
from raycast import Raycast
from map import Map
from lap_counter import LapCounter
from PIL import Image
# Initialise Pygame
pygame.init()
map_load_name="Thomas road"
# Charge l'image de la carte et récupère ses dimensions
map_path = f"{map_load_name}.png"
with Image.open(map_path) as map:
width, height = map.size
# Définition des dimensions de la fenêtre du jeu
WIDTH, HEIGHT = width, height
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Course des Meilleures Voitures")
# Horloge pour contrôler le taux de rafraîchissement
clock = pygame.time.Clock()
# Variables de configuration de la voiture
CAR_WIDTH = 13 # Largeur de la voiture
CAR_HEIGHT = 23 # Hauteur de la voiture
CAR_TURN_SPEED = 150 # Vitesse de rotation de la voiture
# Variables modifiables pour la configuration de la voiture
CAR_MAX_SPEED = 175 # Vitesse maximale de la voiture
CAR_MIN_SPEED = 0 # Vitesse minimale de la voiture
CAR_ACCELERATION = 75 # Accélération de la voiture
Raycast_angles = [-67.5, -45, -22.5, 0, 22.5, 45, 67.5] # Angles des rayons pour la détection
image_path = "Blue_F1.png" # Chemin vers l'image de la voiture
team_name = "Arthur F1" # Nom de l'équipe
nb_generation = 50 # Nombre max de générations
# Variables pour NEAT
GENERATION = 0 # Génération actuelle
# Charge la configuration de NEAT
def load_config(config_path):
"""
Charge le fichier de configuration pour NEAT.
Paramètres :
config_path : str
Chemin vers le fichier de configuration.
Retourne :
neat.Config : L'objet de configuration chargé.
"""
return neat.Config(
neat.DefaultGenome,
neat.DefaultReproduction,
neat.DefaultSpeciesSet,
neat.DefaultStagnation,
config_path
)
# Exécute l'algorithme NEAT et sauvegarde la meilleure configuration de voiture
def run_neat(config_file, checkpoint_path=None):
"""
Exécute l'algorithme NEAT et sauvegarde la meilleure configuration de voiture.
Paramètres :
config_file : str
Chemin vers le fichier de configuration.
checkpoint_path : str, optionnel
Chemin vers le fichier de checkpoint pour charger la progression précédente.
"""
global team_name, nb_generation
if checkpoint_path and os.path.exists(checkpoint_path):
# Charge la population depuis un checkpoint
population = neat.Checkpointer.restore_checkpoint(checkpoint_path)
else:
# Crée une nouvelle population
config = load_config(config_file)
population = neat.Population(config)
# Ajoute des reporters pour afficher les informations
population.add_reporter(neat.StdOutReporter(True))
stats = neat.StatisticsReporter()
population.add_reporter(stats)
# Ajoute un Checkpointer pour sauvegarder la progression toutes les 5 générations
checkpoint_dir = "checkpoint"
if not os.path.exists(checkpoint_dir):
os.makedirs(checkpoint_dir)
population.add_reporter(neat.Checkpointer(5, filename_prefix=os.path.join(checkpoint_dir, "neat-checkpoint-")))
# Exécute l'algorithme NEAT
winner = population.run(eval_genomes, nb_generation) # 50 générations
# Sauvegarde le meilleur génome et sa configuration
final_result_dir = "final_result"
if not os.path.exists(final_result_dir):
os.makedirs(final_result_dir)
car_name = team_name
with open(os.path.join(final_result_dir, f"{car_name}.pkl"), "wb") as f:
pickle.dump(winner, f)
with open(os.path.join(final_result_dir, f"config-{car_name}.txt"), "w") as f:
with open(config_file, "r") as config_f:
f.write(config_f.read())
with open(os.path.join(final_result_dir, f"parameters-{car_name}.txt"), "w") as f:
f.write(f"{CAR_MAX_SPEED}\n{CAR_MIN_SPEED}\n{CAR_ACCELERATION}\n{','.join([str(angle) for angle in Raycast_angles])}")
# Sauvegarde l'image de la voiture
if image_path:
with open(os.path.join(final_result_dir, f"{car_name}.png"), "wb") as f:
with open(image_path, "rb") as img_f:
f.write(img_f.read())
print(f"Meilleur génome sauvegardé dans {final_result_dir}/{car_name}.pkl")
# Variable pour afficher ou masquer les rayons
raycast_visible = False
# Fonction d'évaluation des génomes
def eval_genomes(genomes, config):
"""
Évalue chaque génome dans la population pour déterminer la meilleure voiture.
Paramètres :
genomes : list
Liste des génomes à évaluer.
config : neat.Config
Configuration utilisée pour le réseau neuronal.
"""
global GENERATION, raycast_visible, Raycast_angles, CAR_MAX_SPEED, CAR_MIN_SPEED, CAR_ACCELERATION, image_path
GENERATION += 1
nets = []
ge = []
cars = []
# Charge la carte
game_map = Map(map_file=f"{map_load_name}.json")
for genome_id, genome in genomes:
genome.fitness = 0 # Fitness initiale
net = neat.nn.FeedForwardNetwork.create(genome, config)
nets.append(net)
# Crée une nouvelle voiture pour chaque génome
car = Car(game_map.start_position[0], game_map.start_position[1],
width=CAR_WIDTH, height=CAR_HEIGHT,
max_speed=CAR_MAX_SPEED, acceleration=CAR_ACCELERATION,
turn_speed=CAR_TURN_SPEED, image_path=image_path, min_speed=CAR_MIN_SPEED)
cars.append(car)
ge.append(genome)
# Crée l'objet Raycast avec des angles personnalisés
angles = Raycast_angles # Angles modulables des rayons
raycast = Raycast(angles)
# Compteur de tours pour toutes les voitures
lap_counters = [LapCounter(game_map.checkpoints) for _ in range(len(cars))]
previous_positions = [car.position.copy() for car in cars]
running = True
max_time = 1000 # Temps maximum avant la fin de la génération
current_time = 0
while running and len(cars) > 0 and current_time < max_time:
pygame.display.flip()
# Dessine l'environnement
game_map.draw(screen)
# Calcul du delta temps réel en utilisant l'horloge
dt = clock.tick(60) / 1000 # Delta temps en secondes (temps réel)
# Limite le delta temps pour éviter des sauts trop grands (utile quand les FPS chutent)
dt = min(dt, 1 / 30) # Limite dt à un maximum de 1/30 de seconde
current_time += 1 # Incrémente le temps
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
raycast_visible = not raycast_visible # Affiche ou masque les rayons
for i, car in enumerate(cars):
if not car.active:
continue # Ignore les voitures inactives
# Mise à jour de la voiture
distances, endpoints = raycast.cast_rays(car.position, car.angle, game_map.road_surface)
car.draw(screen)
if raycast_visible:
raycast.draw_rays(screen, car.position, endpoints)
# Normalise les distances pour le réseau neuronal
inputs = [distance / 200 for distance in distances] # Supposons une distance maximale de 200 pixels
inputs.append(car.speed / CAR_MAX_SPEED) # Normalise la vitesse
inputs.append(car.angle / 360) # Normalise l'angle
# Donne les entrées au réseau
output = nets[i].activate(inputs)
# Contrôle par le réseau neuronal :
# output[0] = accélérer ou décélérer
# output[1] = tourner à gauche ou à droite
# Logique d'accélération/décélération
if output[0] > 0.5:
car.speed += CAR_ACCELERATION * dt # Accélère la voiture
elif output[0] <= 0.5:
car.speed -= CAR_ACCELERATION * dt # Décélère la voiture
car.speed = max(car.speed, CAR_MIN_SPEED)
# Logique de rotation
if output[1] > 0.5 and abs(car.speed) > 0:
car.angle -= CAR_TURN_SPEED * dt # Tourne à droite
elif output[1] <= 0.5 and abs(car.speed) > 0:
car.angle += CAR_TURN_SPEED * dt # Tourne à gauche
car.update(dt) # Mise à jour de la voiture
# Vérifie le passage des checkpoints
previous_laps = lap_counters[i].laps_completed
previous_checkpoints = lap_counters[i].current_checkpoint
lap_counters[i].check_checkpoint(previous_positions[i], car.position)
previous_positions[i] = car.position.copy()
#CODER A PARTIR D'ICI POUR LA FITNESS !!
#exemple :
#ge[i].fitness -= 0.001 #perte dans le temps
# Point d'entrée du script
if __name__ == "__main__":
# Chemin vers le fichier de configuration NEAT
config_path = "config-feedforward.txt"
# Vérifie si un fichier de checkpoint doit être chargé
checkpoint_path = "checkpoint/neat-checkpoint-499" # Définit le chemin du fichier de checkpoint à charger
if len(sys.argv) > 1:
checkpoint_path = sys.argv[1]
run_neat(config_path, checkpoint_path)
import pygame
import json
class Map:
def __init__(self, map_file="map.json"):
"""
Initialise la carte à partir d'un fichier JSON.
Paramètres :
map_file : str, optionnel
Chemin vers le fichier JSON contenant les informations de la carte (par défaut 'map.json').
"""
# Charge les données de la carte à partir d'un fichier JSON
with open(map_file, 'r') as f:
data = json.load(f)
# Charge l'image de la route
road_image_path = data.get('road_image')
self.road_surface = pygame.image.load(road_image_path).convert()
self.road_surface = self.road_surface.convert()
# Charge les checkpoints
self.checkpoints = data.get('checkpoints', [])
# Chaque checkpoint est un dictionnaire avec les clés 'start', 'end', 'order'
# Charge la position de départ
self.start_position = data.get('start_position', [100, 100])
# Crée un masque uniquement pour l'herbe (zones vertes)
self.grass_mask = self.create_grass_mask()
def create_grass_mask(self):
"""
Crée un masque où les zones d'herbe (vertes) sont considérées comme solides.
Retourne :
pygame.mask.Mask : Le masque représentant les zones solides de l'herbe.
"""
# Crée un masque de la même taille que la surface de la route
grass_mask = pygame.mask.Mask((self.road_surface.get_width(), self.road_surface.get_height()))
grass_color = (0, 200, 0) # Couleur de l'herbe (vert)
# Parcourt chaque pixel de l'image de la route
for x in range(self.road_surface.get_width()):
for y in range(self.road_surface.get_height()):
# Obtient la couleur du pixel actuel
color = self.road_surface.get_at((x, y))
# Si la couleur correspond à celle de l'herbe, marque le pixel comme solide dans le masque
if color[:3] == grass_color: # Ignore le canal alpha s'il est présent
grass_mask.set_at((x, y), 1) # Marque les zones d'herbe comme solides
return grass_mask
def draw(self, screen):
"""
Dessine la surface de la route sur l'écran.
Paramètres :
screen : pygame.Surface
L'écran sur lequel la surface de la route doit être dessinée.
"""
screen.blit(self.road_surface, (0, 0))
\ No newline at end of file
import pygame
import math
class Raycast:
def __init__(self, angles):
"""
Initialise l'objet Raycast avec une liste d'angles.
Paramètres :
angles : list
Liste des angles en degrés pour les rayons.
"""
self.angles = angles # Liste des angles en degrés
def cast_rays(self, car_position, car_angle, map_surface):
"""
Lance des rayons à partir de la position de la voiture pour détecter les obstacles.
Paramètres :
car_position : tuple (float, float)
La position actuelle de la voiture (x, y).
car_angle : float
L'angle actuel de la voiture en degrés.
map_surface : pygame.Surface
La surface de la carte sur laquelle les rayons sont projetés.
Retourne :
tuple : (list, list)
distances : Liste des distances pour chaque rayon.
end_points : Liste des points d'extrémité pour chaque rayon.
"""
distances = []
end_points = []
for angle in self.angles:
# Calcule l'angle total en ajoutant l'angle du rayon à l'angle de la voiture
total_angle = car_angle + angle
rad_angle = math.radians(total_angle) # Convertit l'angle en radians
# Point de départ du rayon
x0, y0 = car_position
# Vecteur de direction
dx = -math.sin(rad_angle)
dy = -math.cos(rad_angle)
distance = 0
max_distance = 200 # Distance maximale pour vérifier les obstacles
step = 1 # Taille de l'étape en pixels
# Parcours le rayon jusqu'à la distance maximale
while distance < max_distance:
x = x0 + dx * distance
y = y0 + dy * distance
# Vérifie si le rayon sort des limites de la carte
if x < 0 or x >= map_surface.get_width() or y < 0 or y >= map_surface.get_height():
break
# Obtient la couleur du pixel à la position actuelle
color = map_surface.get_at((int(x), int(y)))
# Suppose que l'herbe est verte (0, 200, 0), arrête si le rayon touche l'herbe
if color == (0, 200, 0, 255): # Inclut le canal alpha
break
distance += step
# Ajoute la distance trouvée et le point d'extrémité du rayon
distances.append(distance)
end_point = (x0 + dx * distance, y0 + dy * distance)
end_points.append(end_point)
return distances, end_points
def draw_rays(self, screen, car_position, end_points):
"""
Dessine les rayons sur l'écran à partir de la position de la voiture jusqu'aux points d'extrémité.
Paramètres :
screen : pygame.Surface
L'écran sur lequel les rayons doivent être dessinés.
car_position : tuple (float, float)
La position actuelle de la voiture (x, y).
end_points : list
Liste des points d'extrémité pour chaque rayon.
"""
for end_point in end_points:
# Dessine une ligne entre la position de la voiture et le point d'extrémité du rayon
pygame.draw.line(screen, (24, 196, 201), car_position, end_point, 1)
\ No newline at end of file
import pygame
import sys
import json
import os
# Initialise Pygame
pygame.init()
map_save_or_load_name="Thomas road" # vous pouvez renommer en ce que vous voulez !
# Constantes
WIDTH, HEIGHT = 1400, 700 # Dimensions de la fenêtre
MAP_FILE = f"{map_save_or_load_name}.json" # Fichier de la carte
ROAD_COLOR = (128, 128, 128) # Couleur des routes (gris)
GRASS_COLOR = (0, 200, 0) # Couleur de l'herbe (vert)
CHECKPOINT_COLOR = (255, 255, 0) # Couleur des checkpoints (jaune)
START_COLOR = (0, 0, 255) # Couleur de la position de départ (bleu)
BRUSH_COLOR = ROAD_COLOR # Couleur actuelle du pinceau
BRUSH_SIZE = 30 # Taille initiale du pinceau
CHECKPOINT_LINE_WIDTH = 3 # Épaisseur des lignes des checkpoints
CHECKPOINT_FONT_SIZE = 20 # Taille de la police pour les numéros des checkpoints
# Configuration de l'écran
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Éditeur de Carte de Jeu de Course")
clock = pygame.time.Clock()
# Polices
font = pygame.font.SysFont(None, CHECKPOINT_FONT_SIZE)
# Modes
MODE_DRAW = 'draw'
MODE_CHECKPOINT = 'checkpoint'
MODE_START = 'start'
class MapEditor:
def __init__(self):
"""
Initialise l'éditeur de carte.
"""
# Initialise la surface de la route avec de l'herbe
self.road_surface = pygame.Surface((WIDTH, HEIGHT))
self.road_surface.fill(GRASS_COLOR)
# Initialise la surface de la carte
self.map_surface = pygame.Surface((WIDTH, HEIGHT))
self.map_surface.fill(GRASS_COLOR)
# Structures de données pour les checkpoints et la position de départ
self.checkpoints = [] # Liste des dictionnaires : {'start': (x, y), 'end': (x, y), 'order': int}
self.start_position = None # Tuple (x, y) pour la position de départ
# Mode actuel
self.mode = MODE_DRAW
# Paramètres du pinceau
self.brush_size = BRUSH_SIZE
self.brush_color = BRUSH_COLOR
# État du dessin de checkpoint
self.drawing_checkpoint = False
self.checkpoint_start = None
self.next_checkpoint_order = 1 # Numéro d'ordre pour les checkpoints
def draw_brush(self, pos, color):
"""
Dessine un cercle sur la surface de la route pour simuler l'action du pinceau.
Paramètres :
pos : tuple (int, int)
Position (x, y) du pinceau.
color : tuple (int, int, int)
Couleur à dessiner.
"""
pygame.draw.circle(self.road_surface, color, pos, self.brush_size)
def start_checkpoint_drawing(self, pos):
"""
Démarre le dessin d'une ligne de checkpoint.
Paramètres :
pos : tuple (int, int)
Position (x, y) de départ du checkpoint.
"""
self.drawing_checkpoint = True
self.checkpoint_start = pos
def finish_checkpoint_drawing(self, pos):
"""
Termine le dessin d'une ligne de checkpoint et l'enregistre avec un numéro d'ordre.
Paramètres :
pos : tuple (int, int)
Position (x, y) de fin du checkpoint.
"""
if self.drawing_checkpoint and self.checkpoint_start:
checkpoint = {
'start': self.checkpoint_start,
'end': pos,
'order': self.next_checkpoint_order
}
self.checkpoints.append(checkpoint)
self.next_checkpoint_order += 1
self.drawing_checkpoint = False
self.checkpoint_start = None
print(f"Checkpoint {checkpoint['order']} placé de {checkpoint['start']} à {checkpoint['end']}.")
def delete_last_checkpoint(self):
"""
Supprime le dernier checkpoint s'il en existe un.
"""
if self.checkpoints:
removed_checkpoint = self.checkpoints.pop()
self.next_checkpoint_order -= 1
print(f"Checkpoint {removed_checkpoint['order']} supprimé de {removed_checkpoint['start']} à {removed_checkpoint['end']}.")
else:
print("Aucun checkpoint à supprimer.")
def render_checkpoint(self, checkpoint):
"""
Dessine un checkpoint avec son numéro d'ordre.
Paramètres :
checkpoint : dict
Dictionnaire contenant les informations du checkpoint ('start', 'end', 'order').
"""
start = checkpoint['start']
end = checkpoint['end']
order = checkpoint['order']
pygame.draw.line(self.map_surface, CHECKPOINT_COLOR, start, end, CHECKPOINT_LINE_WIDTH)
midpoint = ((start[0] + end[0]) // 2, (start[1] + end[1]) // 2)
order_text = font.render(str(order), True, (255, 255, 255))
text_rect = order_text.get_rect(center=midpoint)
self.map_surface.blit(order_text, text_rect)
def render_all_checkpoints(self):
"""
Dessine tous les checkpoints de la liste des checkpoints.
"""
for checkpoint in self.checkpoints:
self.render_checkpoint(checkpoint)
def set_start_position(self, pos):
"""
Définit la position de départ du joueur.
Paramètres :
pos : tuple (int, int)
Position (x, y) de départ.
"""
self.start_position = pos
print(f"Position de départ définie à {pos}.")
def render_start_position(self):
"""
Dessine la position de départ sur la surface de la carte.
"""
if self.start_position:
pygame.draw.circle(self.map_surface, START_COLOR, self.start_position, 8, 2)
start_text = font.render("Départ", True, (255, 255, 255))
text_rect = start_text.get_rect(center=(self.start_position[0], self.start_position[1] - 15))
self.map_surface.blit(start_text, text_rect)
def save_map(self):
"""
Sauvegarde la carte actuelle dans 'road.png' et 'map.json'.
"""
global map_save_or_load_name
data = {
'checkpoints': self.checkpoints,
'start_position': self.start_position
}
pygame.image.save(self.road_surface, f"{map_save_or_load_name}.png")
data['road_image'] = f"{map_save_or_load_name}.png"
with open(MAP_FILE, 'w') as f:
json.dump(data, f, indent=4)
print("Carte sauvegardée avec succès.")
def load_map(self):
"""
Charge la carte depuis 'road.png' et 'map.json'.
"""
if not os.path.exists(MAP_FILE):
print("Aucun fichier de carte trouvé à charger.")
return
with open(MAP_FILE, 'r') as f:
data = json.load(f)
road_image_path = data.get('road_image')
if road_image_path and os.path.exists(road_image_path):
road_image = pygame.image.load(road_image_path).convert()
self.road_surface.blit(road_image, (0, 0))
else:
self.road_surface.fill(GRASS_COLOR)
self.map_surface.fill(GRASS_COLOR)
self.map_surface.blit(self.road_surface, (0, 0))
self.checkpoints = data.get('checkpoints', [])
self.next_checkpoint_order = len(self.checkpoints) + 1
self.render_all_checkpoints()
self.start_position = data.get('start_position')
if self.start_position:
self.render_start_position()
print("Carte chargée avec succès.")
def handle_event(self, event):
"""
Gère les événements Pygame entrants.
Paramètres :
event : pygame.event.Event
Événement Pygame à gérer.
"""
if event.type == pygame.MOUSEBUTTONDOWN:
pos = pygame.mouse.get_pos()
if self.mode == MODE_DRAW:
if event.button == 1: # Clic gauche pour dessiner les routes
self.draw_brush(pos, ROAD_COLOR)
elif event.button == 3: # Clic droit pour effacer (dessiner de l'herbe)
self.draw_brush(pos, GRASS_COLOR)
elif self.mode == MODE_CHECKPOINT:
if event.button == 1: # Clic gauche pour commencer à dessiner un checkpoint
self.start_checkpoint_drawing(pos)
elif event.button == 3: # Clic droit pour supprimer le dernier checkpoint
self.delete_last_checkpoint()
elif self.mode == MODE_START:
if event.button == 1: # Clic gauche pour définir la position de départ
self.set_start_position(pos)
elif event.type == pygame.MOUSEBUTTONUP:
pos = pygame.mouse.get_pos()
if self.mode == MODE_CHECKPOINT:
if event.button == 1 and self.drawing_checkpoint:
self.finish_checkpoint_drawing(pos)
elif event.type == pygame.MOUSEMOTION:
pos = pygame.mouse.get_pos()
if self.mode == MODE_DRAW:
if pygame.mouse.get_pressed()[0]:
self.draw_brush(pos, ROAD_COLOR)
elif pygame.mouse.get_pressed()[2]:
self.draw_brush(pos, GRASS_COLOR)
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_1:
self.mode = MODE_DRAW
print("Mode Dessin activé.")
elif event.key == pygame.K_2:
self.mode = MODE_CHECKPOINT
print("Mode Checkpoint activé.")
elif event.key == pygame.K_3:
self.mode = MODE_START
print("Mode Position de Départ activé.")
elif event.key in [pygame.K_EQUALS, pygame.K_PLUS]:
self.brush_size += 1
print(f"Taille du pinceau augmentée à {self.brush_size}")
elif event.key in [pygame.K_MINUS, pygame.K_RIGHTPAREN]:
self.brush_size = max(1, self.brush_size - 1)
print(f"Taille du pinceau diminuée à {self.brush_size}")
elif event.key == pygame.K_s:
self.save_map()
elif event.key == pygame.K_l:
self.load_map()
def render(self, surface):
"""
Rend la carte et l'interface utilisateur sur la surface donnée.
Paramètres :
surface : pygame.Surface
Surface sur laquelle la carte et l'interface utilisateur doivent être dessinées.
"""
self.map_surface.fill(GRASS_COLOR)
self.map_surface.blit(self.road_surface, (0, 0))
self.render_all_checkpoints()
if self.start_position:
self.render_start_position()
surface.blit(self.map_surface, (0, 0))
if self.mode == MODE_DRAW:
mouse_pos = pygame.mouse.get_pos()
pygame.draw.circle(surface, (255, 255, 255), mouse_pos, self.brush_size, 1)
self.display_ui(surface)
def display_ui(self, surface):
"""
Affiche les éléments de l'interface utilisateur.
Paramètres :
surface : pygame.Surface
Surface sur laquelle les éléments de l'interface utilisateur doivent être affichés.
"""
mode_text = f"Mode : {self.mode.capitalize()}"
img = font.render(mode_text, True, (255, 255, 255))
surface.blit(img, (10, HEIGHT - 200))
brush_text = f"Taille du pinceau : {self.brush_size}"
img = font.render(brush_text, True, (255, 255, 255))
surface.blit(img, (10, HEIGHT - 180))
instructions = [
"1 : Dessiner des routes",
"2 : Placer des checkpoints",
"3 : Définir la position de départ",
"S : Sauvegarder la carte",
"L : Charger la carte",
"+/- : Augmenter/Diminuer la taille du pinceau",
"Clic gauche : Action selon le mode",
"Clic droit (Mode Dessin) : Effacer (Dessiner de l'herbe)",
"Clic droit (Mode Checkpoint) : Supprimer le dernier checkpoint"
]
for i, text in enumerate(instructions):
img = font.render(text, True, (255, 255, 255))
surface.blit(img, (10, HEIGHT - 160 + i * 20))
def main():
editor = MapEditor()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
editor.handle_event(event)
editor.render(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
sys.exit()
if __name__ == "__main__":
main()
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment