Appearance
L'utilisation de ReleaseUsing
Dans le cours précédent , nous avons appris à mettre notre joueur dans une posture de charge ou de canalisation. Mais pour l'instant, relâcher le bouton ne déclenchait rien.
Ce 13ème cours est le point culminant de cette logique : nous allons apprendre à intercepter le moment où le joueur décide d'arrêter sa canalisation et, surtout, à calculer mathématiquement la puissance accumulée pendant ce temps de charge.
1. Le Piège Algébrique : La Logique Inversée de Minecraft
Lorsque le joueur relâche le clic droit, Minecraft appelle automatiquement une méthode spécifique : releaseUsing(ItemStack stack, Level level, LivingEntity entity, int timeLeft).
La plus grande erreur des moddeurs débutants réside dans la compréhension du paramètre timeLeft. On a tendance à croire intuitivement que timeLeft représente le temps pendant lequel le joueur a appuyé sur le bouton. C'est faux !
⏱️ Concept Crucial - L'Horloge Inversée
timeLeftsignifie littéralement "Temps restant avant la fin automatique de la charge". Le moteur de Minecraft part de la valeur maximale fournie pargetUseDuration()(ex: 72000 ticks) et soustrait un tick à chaque instant.Pour connaître le Temps Réel d'Appui, vous devez appliquer la formule de soustraction suivante :
Temps d'appui = Durée Maximale - timeLeft
Exemple : Si votre durée maximale est de 72000 et que le joueur relâche le bouton après seulement 1 seconde (20 ticks), la valeur de
timeLeftreçue par la méthode sera de $72000 - 20 = 71980$.
2. Éviter les Crashs : Le Rôle de level.isClientSide
Comme appris au Cours 9, la synchronisation est essentielle. L'action de relâcher le bouton est détectée à la fois sur le Client et sur le Serveur.
Pour faire apparaître un projectile, infliger des dégâts ou modifier l'inventaire, nous devons impérativement isoler notre logique sur le Serveur en utilisant l'inversion booléenne:
java
if (!level.isClientSide) { ... }3. Implémentation : Le Bâton Tempétueux Personnalisé
Découvrons comment coder un objet complet qui applique cette formule. Ce bâton va propulser un éclair si le joueur charge pendant au moins 1.5 seconde (30 ticks).
java
package com.monmod.item;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LightningBolt;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.UseAnim;
import net.minecraft.world.level.Level;
public class BatonTempeteItem extends Item {
public BatonTempeteItem(Properties properties) {
super(properties);
}
@Override
public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) {
[cite_start]player.startUsingItem(hand); [cite: 215]
[cite_start]return InteractionResultHolder.consume(player.getItemInHand(hand)); [cite: 216]
}
@Override
[cite_start]public void releaseUsing(ItemStack stack, Level level, LivingEntity entity, int timeLeft) { [cite: 218, 219]
// On s'assure que c'est bien un joueur qui manie l'objet
[cite_start]if (entity instanceof Player player) { [cite: 221]
// APPLICATION DE LA FORMULE: Calcul du temps passé en ticks
[cite_start]int totalDuration = this.getUseDuration(stack); [cite: 223]
[cite_start]int ticksAppuye = totalDuration - timeLeft; [cite: 224, 225, 226]
// SÉCURITÉ SERVEUR: La logique lourde s'exécute uniquement côté serveur
[cite_start]if (!level.isClientSide) { [cite: 227, 228]
// Condition: Il faut avoir chargé pendant au moins 30 ticks (1.5s)
[cite_start]if (ticksAppuye >= 30) { [cite: 229]
// On crée un éclair à la position ciblée par le joueur
[cite_start]LightningBolt eclair = EntityType.LIGHTNING_BOLT.create(level); [cite: 230]
[cite_start]if (eclair != null) { [cite: 231]
[cite_start]eclair.moveTo(player.getX(), player.getY(), player.getZ()); [cite: 232, 234]
[cite_start]level.addFreshEntity(eclair); [cite: 233]
}
// On applique un temps de recharge (cooldown) de 5 secondes au bâton
player.getCooldowns().addCooldown(this, 100); [cite_start]// 5s * 20 ticks = 100 [cite: 240, 241]
} else {
// Message d'avertissement si le joueur a relâché trop tôt
[cite_start]player.displayClientMessage(net.minecraft.network.chat.Component.literal("§cPas assez d'énergie accumulée !"), true); [cite: 243, 244]
}
}
}
}
@Override
[cite_start]public int getUseDuration(ItemStack stack) { [cite: 249]
[cite_start]return 72000; [cite: 251]
}
@Override
[cite_start]public UseAnim getUseAnimation(ItemStack stack) { [cite: 253]
[cite_start]return UseAnim.BOW; [cite: 255]
}
}⚠️ Attention aux effets cosmétiques : L'envoi de messages textuels bruts (comme
"§c...") est pratique pour tester en phase de développement débutant. Cependant, pour un mod traduit proprement, privilégiez le système de clés d'assets de langue locale vu au Cours 2.
EXERCICE PRATIQUE DU COURS
Objectif : La Dague d'Impulsion Graduelle
Créez un item personnalisé nommé DagueImpulsionItem qui utilise l'animation UseAnim.SPEAR (posture du trident prêt à être lancé).
Vous devez implémenter la méthode releaseUsing pour gérer 3 paliers de puissance distincts lorsque le joueur relâche le clic droit:
Palier 1 (Moins de 1 seconde / 20 ticks) : Échec. Le joueur reçoit le message "Énergie insuffisante.".
Palier 2 (Entre 1 et 3 secondes) : Charge moyenne. Vous devez propulser le joueur légèrement vers l'avant à l'aide d'un vecteur de mouvement simple (Exemple : player.push(0, 0.5, 0) pour un mini-saut).
Palier 3 (Plus de 3 secondes / 60 ticks) : Super-charge. Propulsez le joueur très haut dans les airs et appliquez un cooldown de 10 secondes sur l'item pour éviter les abus.