Skip to content

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

timeLeft signifie littéralement "Temps restant avant la fin automatique de la charge". Le moteur de Minecraft part de la valeur maximale fournie par getUseDuration() (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 timeLeft reç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.