Monstre d'horreur Minecraft · un monstre conscient du terrain qui se tient debout, se faufile et rampe pour te traquer dans n'importe quel espace · un seul par monde, imposé via le fichier de sauvegarde · Java · Forge
Architecture
Le moteur de spawn vanilla choisit le walker dans le pool de spawn du biome modifier et interroge la grille de spawn, dont le canSpawnHere lit la donnée monde singleton : si un walker existe déjà quelque part dans la sauvegarde, le spawn est refusé. Une fois vivant, TheCreepyWalkerEntity sonde le terrain à chaque tick serveur, bascule entre debout, faufilé et rampant, redimensionne sa hitbox, et envoie les drapeaux de posture aux clients via SynchedEntityData. Le renderer d'entité lit ces drapeaux à chaque frame et le modèle hiérarchique échantillonne les clips de keyframes correspondants, y compris une chorégraphie en deux temps pour les transitions rampant vers debout.
Déploiement : Jar du mod → Forge client + serveur · Règles de spawn → JSON de datapack, aucun rechargement de code nécessaire
Résultats
- 3 postures · la hitbox rétrécit de 2.7 à 1.7 à 0.7 blocs
- 1 par monde · singleton imposé via le fichier de sauvegarde
- 14 clips · animations Blockbench faites main en keyframes
- 0 paquet · netcode custom · toute la synchro passe par les données d'entité vanilla
Compétences démontrées : synchro d'état serveur-client · machines à états finis · gestion de hitbox + collisions · enregistrement piloté par événements · persistance monde NBT · conception d'IA de jeu
Problèmes et solutions
Une seule contrainte guide tout : un unique monstre qui doit paraître vivant et pouvoir suivre le joueur dans n'importe quel espace.
█ Machine à postures consciente du terrain
Problème : Un monstre de 2.7 blocs de haut ne peut pas poursuivre les joueurs dans des passages d'un bloc. Les mobs vanilla contournent simplement les ouvertures basses ou se coincent à l'entrée, ce qui tue la prémisse d'horreur d'une chose qui te suit partout.
À chaque tick serveur, l'entité sonde les blocs au-dessus et devant elle (y compris une marche vers le haut face à un mur) et choisit une posture. Debout, faufilé et rampant portent chacun leur propre hitbox : 2.7, 1.7 et 0.7 blocs de haut, appliqués via getDimensions et refreshDimensions.
- Rejeté la nage/l'accroupissement des Pose vanilla : ils ne couvrent que les hitbox à forme de joueur et ne donnent aucun contrôle sur le moment du changement
- Accepté jusqu'à 8 lectures de block-state par tick ; un cooldown de 20 ticks après chaque changement empêche le battement de posture aux rebords
- Obtenu un mob qui tient physiquement partout où le joueur peut aller, ce qu'aucun réglage de pathfinding seul ne fournit
▚ Synchro de posture sans paquets custom
Problème : La posture est décidée sur le serveur, mais les animations n'existent que sur le client. De simples champs Java se désynchronisent silencieusement en multijoueur : chaque client devinerait sa propre posture et jouerait le mauvais clip.
La posture actuelle, la posture précédente et un code numérique de changement de posture vivent tous dans des accessors SynchedEntityData, le canal d'état d'entité répliqué de Minecraft. Le client lit le code de changement et démarre le clip de transition correspondant, puis le code se remet à zéro.
- Rejeté un canal réseau custom : plus de code, de gestion de versions et d'ordonnancement pour des données qui tiennent dans des booléens et un int
- Accepté dix accessors synchronisés sur une entité, plus bavards qu'un paquet fait main mais répliqués et sans race condition gratuitement
- Obtenu des animations correctes pour tout observateur, y compris les joueurs qui entrent dans la distance de rendu en pleine transition
▞ Chorégraphie de transition en deux temps
Problème : Passer d'un coup de rampant à debout ressemble à une téléportation. Les clips de transition n'étaient créés qu'entre postures adjacentes, donc rampant vers debout n'avait aucune animation du tout.
Sauter une posture met deux clips en file : rampant vers faufilé joue d'abord, un drapeau d'attente arme la suite, et faufilé vers debout démarre le tick où le timeout du premier clip atteint zéro. Des timeouts comptés en ticks sur le client pilotent toute la séquence.
- Rejeté la création de clips dédiés au saut de niveau : deux animations Blockbench de plus à construire et maintenir pour un cas rare
- Accepté environ 16 ticks de latence de transition avant que la nouvelle posture bouge à pleine vitesse
- Obtenu un mouvement fluide sur chaque chemin de posture avec seulement quatre clips de transition créés
▓ Un walker par monde, imposé deux fois
Problème : Un mob d'horreur perd toute sa menace si le moteur de spawn produit des dizaines de copies. Les plafonds de spawn vanilla fonctionnent par catégorie et par chunk, donc ils ne peuvent pas exprimer 'exactement un, à jamais, dans tout le monde'.
Un booléen SavedData dans la sauvegarde du monde est la source de vérité : canSpawnHere refuse tout spawn tant qu'il est activé, et les événements join/leave de Forge le basculent. Un poids de spawn de 100 dans chaque biome de l'overworld fait arriver vite le seul spawn autorisé.
- Rejeté le comptage des entités chargées : les chunks déchargés cachent le walker et le compte autoriserait un doublon
- Accepté un drapeau à l'échelle du monde plutôt qu'une comptabilité par dimension, un seul walker au total est le design, pas une limitation
- Obtenu un comportement singleton qui survit aux redémarrages du serveur car le drapeau persiste en NBT
▒ Mêlée synchronisée sur l'animation, pas sur le tick
Problème : Le MeleeAttackGoal vanilla applique les dégâts dès que la cible est à portée, mais l'animation de charge prend plusieurs ticks pour atteindre la cible. Les joueurs se font toucher par un monstre dont les bras n'ont pas encore bougé.
Un goal d'attaque custom fait tourner un compteur de préparation : le drapeau d'attaque bascule tôt pour que le client démarre le coup, et doHurtTarget ne se déclenche que lorsque le compteur atteint la frame où les bras retombent.
- Rejeté le goal vanilla plus une estimation côté client : la latence rend l'estimation fausse exactement au moment où ça compte
- Accepté un taux d'attaque effectif plus lent (cooldown de 12 ticks) en échange de coups lisibles et esquivables
- Obtenu des coups qui touchent à la frame d'animation dans les trois postures, chacune avec son propre clip d'attaque
▧ Spawn et mort scriptés, pas de ragdoll
Problème : La séquence de mort vanilla (flash rouge, bascule à 90 degrés, disparition instantanée) se lit comme un système de jeu, pas comme une créature qui meurt, et le spawn pop-in standard gâche la première rencontre.
La mort démarre un clip d'effondrement en keyframes tandis que le renderer supprime la rotation de cadavre vanilla ; le corps reste 60 ticks et est incliquable pendant ce temps. Le spawn joue un clip d'émergence de 108 ticks durant lequel le cerveau serveur reste immobile.
- Rejeté la gestion de mort par défaut de LivingEntity : surcharger tickDeath et setupRotations était le seul moyen de garder la pose
- Accepté de mettre l'IA en pause 5 secondes au spawn, une fenêtre de vulnérabilité, pour que l'émergence ne soit jamais coupée
- Obtenu des entrées et sorties qui restent dans le personnage, tout l'intérêt d'un mod d'horreur