Voici un tutoriel rapide pour créer un jeu minimaliste de type "tower-defense" en OCaml.

Étape 1 : Définir les types de données

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 :

Étape 2 : Fonctions utilitaires

let 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 :

Étape 3 : Boucle de jeu

let 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 :

Étape 4 : Lancer le 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.


Affichage en Mode Console

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 :

  1. La fonction 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 :
  2. La fonction afficher_jeu récupère les dimensions de la carte (hauteur et largeur) à partir de jeu.carte.
  3. Elle utilise ensuite deux boucles for imbriquées pour parcourir toutes les cases de la carte, en appelant afficher_case pour chaque case.
  4. Après avoir affiché une ligne complète, 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