Un pauvre hérisson s’est perdu dans une série de jardins enchantés… À vous de le retrouver !
Incarnez un jardinier courageux et partez à l’aventure à travers des cartes pleines de surprises. Ramassez les carottes pour ouvrir les portes, évitez les guêpes (elles piquent fort mais ne survivent pas) et méfiez-vous des frelons (plus résistants et encore plus redoutables).
Chaque pas vous coûte de l’énergie selon le terrain. Restez immobile quelques instants et vous récupérerez un peu de jus. Mais attention : si vous vous faites piquer sans avoir assez d’énergie pour encaisser le coup, c’est la fin.
Alors, prêt·e à braver les jardins et sauver votre ami à piquants ?
MapLevelDefaultStart
. La classe MapLevelDefault
peut être supprimée de l’archive.Chaque jardin est une carte rectangulaire composée de cellules.
Certaines cellules sont traversables, d’autres non. Le jardinier, les guêpes et les frelons se déplacent sur cette grille. Les portes permettent de passer d’un jardin à l’autre — à condition qu’elles soient ouvertes. Les guêpes et les frelons, eux, n’empruntent jamais les portes : ils ont une peur panique des courants d’air et refusent d’y poser les pattes, qu’elles soient ouvertes ou fermées.
Pour ouvrir les portes, il faut ramasser toutes les carottes. Mais attention : les jardins sont peuplés de guêpes et de frelons… et vous êtes allergique aux piqûres !
Les guêpes meurent après vous avoir piqué. Les frelons, eux, peuvent piquer deux fois avant de rendre l’âme. Les piqûres coûtent cher : -20 d’énergie pour une guêpe, -30 pour un frelon. Si vous n’avez plus d’énergie au moment d’une piqûre, la partie est perdue.
Heureusement, des bombes insecticides sont là pour vous aider. Chaque bombe tue une guêpe ; deux bombes sont nécessaires pour un frelon. Les insectes peuvent aussi marcher sur les bombes — ce n’est pas bon pour leur santé.
Côté terrain :
energyRecoverDuration
), il regagne de l’énergie (dans la limite de son maximum initial gardenerEnergy
).Ramassez automatiquement les bonus sur votre route :
energyBoost
, dans la limite de votre énergie maximale (gardenerEnergy
),
et vous guérit de toutes les maladies (diseaseLevel
est remis à 1).diseaseLevel
+1 pendant diseaseDuration
). Si vous en ramassez plusieurs, les effets se chevauchent : chaque trognon augmente le niveau de fatigue pour une durée propre.
Le diseaseLevel reflète donc le nombre de trognons encore actifs à un instant donné.Le niveau d’énergie, le degré de fatigue (diseaseLevel
) et le nombre de bombes sont affichés en permanence dans la barre d’état.
Voici les éléments que vous rencontrerez dans le jeu :
Image | Nom | Description |
---|---|---|
![]() |
Herbe | Coût de déplacement du jardinier : 1 x diseaseLevel |
![]() |
Terre | Coût de déplacement du jardinier : 2 x diseaseLevel |
![]() |
Bosquet de fleurs | Franchissable uniquement par les guêpes et frelons |
![]() |
Nid de guêpes | Génère une guêpe + une bombe insecticide toutes les 5 secondes |
![]() |
Nid de frelons | Génère un frelon + deux bombes insecticides toutes les 10 secondes |
![]() |
Hérisson | Hérisson apeuré à retrouver de toute urgence |
![]() |
Porte fermée | Infranchissable tant que toutes les carottes ne sont pas ramassées |
![]() |
Porte ouverte | Permet de passer dans un autre jardin |
![]() |
Carottes | Toutes les ramasser pour ouvrir les portes |
![]() |
Pomme empoisonnée | Maladie temporaire, fatigue augmentée |
![]() |
Pomme | Guérison + regain d’énergie |
![]() |
Bombe insecticide | Tue une guêpe ou blesse un frelon |
![]() |
Guêpe | Meurt après une piqûre ou en touchant une bombe |
![]() |
Frelon | Peut piquer deux fois; blesse sévèrement et nécessite deux bombes insecticide |
![]() |
Jardinier | C’est vous ! |
Nous pouvons classer les éléments de la manière suivante :
Nous vous fournissons une première ébauche du jeu.
Au lancement, une carte simple (MapLevelDefaultStart
) est chargée : le jardinier peut s’y déplacer librement, quelle que soit la nature des cellules.
Les paramètres du jeu sont stockés dans un fichier .properties, très simple à modifier.
Les fichiers properties en Java permettent de stocker facilement des couples clé/valeur.
Paramètres | Valeur par défaut | Commentaire | |
---|---|---|---|
waspMoveFrequency | 1 / s | Vitesse de déplacement des guêpes | |
hornetMoveFrequency | 2 / s | Vitesse de déplacement des frelons | |
gardenerEnergy | 100 | Énergie max du jardinier | |
energyBoost | 50 | Gain d’énergie avec une pomme | |
energyRecoverDuration | 1000 ms | Temps d’inactivité pour regagner 1 point d’énergie | |
diseaseDuration | 5000 ms | Durée de la maladie après un avoir mangé un trognon |
Archive du jeu de base : UBGarden-student-2025.zip
MapLevelDefaultStart
diseaseLevel
)waspMoveFrequency
hornetMoveFrequency
Lorsque le jardinier marche sur un bonus, il doit pouvoir le ramasser. Imaginons que les classes Apple
et PoisonedApple
soient des sous-classes de la classe Bonus
. On aimerait pouvoir écrire dans le code de la classe Gardener
quelque chose comme ceci :
class Gardener {
void pickUp(Apple apple) { ... }
void pickUp(PoisonedApple poisonedApple) { ... }
void doMove(Direction direction) {
Position nextPos = direction.nextPosition(getPosition());
Decor next = game.world().getGrid().get(nextPos);
setPosition(nextPos);
if (next != null)
pickUp(next);
}
}
Mais en Java, il n’est pas possible de faire un dispatch dynamique en fonction du type du paramètre passé à une méthode (ici, le type du bonus). Java ne fait qu’un dispatch dynamique sur l’objet appelant, pas sur les arguments.
Pour contourner cela, on inverse la dépendance : au lieu que ce soit le jardinier qui “ramasse” le bonus, c’est le bonus qui “se fait ramasser” par le jardinier.
Avec ce mécanisme, on bénéficie du dispatch dynamique sur le type réel du bonus, puis du dispatch statique sur la méthode pickUp(...)
côté jardinier.
class Gardener {
void pickUp(Apple apple) { ... }
void pickUp(PoisonedApple poisonedApple) { ... }
void doMove(Direction direction) {
// ...
if (next != null)
next.pickUpBy(this);
}
}
public interface Pickupabke {
default void pickUpBy(Gardener gardener) {}
}
public abstract class Bonus implements Pickupabke {}
public class Apple extends Bonus {
@Override
public void pickUpBy(Gardener gardener) {
gardener.pickUp(this);
}
}
public class PoisonedApple extends Bonus {
@Override
public void pickUpByBy(Gardener gardener) {
gardener.pickUp(this);
}
}
Dans ce cas, c’est bien la bonne méthode pickUp(Apple)
ou pickUp(PoisonedApple)
du jardinier qui sera appelée, grâce au double dispatch :
pickUpBy
)pickUp(...)
du jardinier