Voici un tutoriel rapide pour créer un jeu minimaliste de type "tower-defense" en OCaml.
type position = int * int
type ennemi = {
pos : position;
pv : int;
}
type tour = {
pos : position;
portee : int;
dommages : int;
}
type jeu = {
carte : bool array array;
ennemis : ennemi list;
tours : tour list;
}
Nous définissons d'abord les types de données nécessaires :
position
pour représenter les coordonnées (x, y)ennemi
avec une position et des points de vie (pv)tour
avec une position, une portée et des dommagesjeu
avec une carte (grille booléenne), une liste d'ennemis et une liste de tourslet distance (x1, y1) (x2, y2) =
sqrt (float (x1 - x2) ** 2. +. float (y1 - y2) ** 2.)
let dans_portee tour ennemi =
distance tour.pos ennemi.pos < float tour.portee
Nous définissons deux fonctions utilitaires :
distance
pour calculer la distance euclidienne entre deux positionsdans_portee
pour vérifier si un ennemi est dans la portée d'une tourlet rec game_loop game =
(* Déplacer les ennemis *)
let ennemis = List.map (fun e -> {e with pos = deplacer e.pos}) game.ennemis in
(* Attaquer les ennemis dans la portée des tours *)
let tours, ennemis =
List.fold_left
(fun (tours, ennemis) tour ->
let ennemis_vises, autres_ennemis = List.partition (dans_portee tour) ennemis in
let ennemis_vises = List.map (fun e -> {e with pv = e.pv - tour.dommages}) ennemis_vises in
(tour :: tours, ennemis_vises @ autres_ennemis))
([], []) game.tours
in
(* Retirer les ennemis atteints *)
let ennemis = List.filter (fun e -> e.pv > 0) ennemis in
(* Conditions de fin de partie *)
if ennemis = [] then
print_endline "Vous avez gagné !"
else if List.exists (fun e -> atteint_destination e.pos) ennemis then
print_endline "Vous avez perdu !"
else
game_loop {game with ennemis; tours}
Voici la boucle principale du jeu :
let carte = Array.make_matrix 10 10 false
let ennemis_initiaux = [
{pos = (0, 0); pv = 100};
{pos = (0, 1); pv = 50};
]
let tours_initiales = [
{pos = (5, 5); portee = 3; dommages = 10};
]
let jeu_initial = {carte; ennemis = ennemis_initiaux; tours = tours_initiales}
let () = game_loop jeu_initial
Finalement, nous créons un état de jeu initial avec une carte 10x10, quelques
ennemis et une tour. Nous appelons ensuite la fonction game_loop
avec cet état
initial pour lancer le jeu.
Ce tutoriel vous donne un aperçu des bases pour créer un jeu de type "tower defense" en OCaml. Bien sûr, il manque encore de nombreuses fonctionnalités comme l'affichage graphique, la gestion des entrées utilisateur, l'ajout de nouvelles vagues d'ennemis, etc. Mais cela vous donne un point de départ pour comprendre la logique de base d'un tel jeu.
N'hésitez pas si vous avez d'autres questions ou si vous souhaitez approfondir certains aspects de cette implémentation.
Et voici une fonction d'affichage en mode console pour notre jeu de type "tower-defense" en OCaml :
let afficher_jeu jeu =
let afficher_case x y =
let position = (x, y) in
if List.exists (fun e -> e.pos = position) jeu.ennemis then
print_string "E"
else if List.exists (fun t -> t.pos = position) jeu.tours then
print_string "T"
else if jeu.carte.(y).(x) then
print_string "#"
else
print_string "."
in
let hauteur = Array.length jeu.carte in
let largeur = Array.length jeu.carte.(0) in
for y = 0 to hauteur - 1 do
for x = 0 to largeur - 1 do
afficher_case x y
done;
print_newline ()
done
Cette fonction afficher_jeu
prend l'état actuel du jeu en entrée et affiche
une représentation de la carte, des tours et des ennemis dans le terminal.
Voici comment elle fonctionne :
afficher_case
prend les coordonnées x et y d'une case et
affiche le caractère approprié en fonction de ce qui se trouve dans cette
case :
'E'
si un ennemi est présent à cette position'T'
si une tour est présente à cette position'#'
si c'est un obstacle (case de la carte à true
)'.'
pour une case videafficher_jeu
récupère les dimensions de la carte (hauteur et
largeur) à partir de jeu.carte.print_newline ()
est appelée pour
passer à la ligne suivante.Vous pouvez intégrer cette fonction dans votre boucle de jeu principale pour afficher l'état actuel du jeu à chaque itération. Par exemple :
let rec game_loop game =
(* ... code existant ... *)
afficher_jeu game;
(* Conditions de fin de partie *)
if ennemis = [] then
print_endline "Vous avez gagné !"
else if List.exists (fun e -> atteint_destination e.pos) ennemis then
print_endline "Vous avez perdu !"
else
game_loop {game with ennemis; tours}
Avec cette modification, le jeu affichera la carte, les tours et les ennemis dans le terminal à chaque tour.
N'hésitez pas si vous avez d'autres questions ou si vous souhaitez ajouter d'autres fonctionnalités à votre jeu de type "tower-defense".
See the result: "td.ml"
Created with: Claude-3-Sonnet