--- title: Particules type: docs weight: 1 --- Le système de particules de Hytale fournit des effets visuels riches à travers des émetteurs et renderers configurables. Créez des explosions, traînées, auras et effets visuels complexes avec un contrôle précis sur le comportement et l'apparence. **Package :** `com.hypixel.hytale.server.core.asset.type.particle` {{< cards cols="3" >}} {{< card link="#générer-des-particules" title="Génération" subtitle="Créer des effets de particules" icon="sparkles" >}} {{< card link="#configuration-du-système-de-particules" title="Configuration" subtitle="Config système et spawner" icon="adjustments" >}} {{< card link="#attracteurs-de-particules" title="Attracteurs" subtitle="Forces et mouvement" icon="arrow-circle-right" >}} {{< /cards >}} --- ## Générer des Particules ### Méthodes ParticleUtil {{< tabs items="Basique,Avancé,WorldParticle" >}} {{< tab >}} ```java import com.hypixel.hytale.server.core.universe.world.ParticleUtil; // Génération basique à une position (trouve auto les joueurs proches) ParticleUtil.spawnParticleEffect( "explosion_small", // ID du système de particules position, // Position Vector3d componentAccessor ); // Générer pour des joueurs spécifiques ParticleUtil.spawnParticleEffect( "magic_trail", position, playerRefs, // List> componentAccessor ); ``` **Distance de Diffusion :** `DEFAULT_PARTICLE_DISTANCE = 75` blocs {{< /tab >}} {{< tab >}} ```java // Avec référence à l'entité source ParticleUtil.spawnParticleEffect( "attack_swing", position, sourceEntityRef, // Entité qui a généré ceci playerRefs, componentAccessor ); // Avec contrôle de rotation ParticleUtil.spawnParticleEffect( "directional_beam", position, yaw, pitch, roll, // Angles de rotation sourceEntityRef, playerRefs, componentAccessor ); // Avec échelle et couleur ParticleUtil.spawnParticleEffect( "colored_burst", position, yaw, pitch, roll, 2.0f, // Multiplicateur d'échelle new Color(255, 100, 50, 255), // Couleur RGBA playerRefs, componentAccessor ); ``` {{< /tab >}} {{< tab >}} ```java import com.hypixel.hytale.server.core.asset.type.particle.config.WorldParticle; // Contrôle complet avec le wrapper WorldParticle WorldParticle worldParticle = new WorldParticle( "my_particle_system", new Color(255, 100, 50, 255), // Override couleur RGBA 1.5f, // Multiplicateur d'échelle new Vector3f(0, 1, 0), // Offset de position new Direction(0, 0, 0) // Offset de rotation ); ParticleUtil.spawnParticleEffect( worldParticle, position, sourceRef, playerRefs, componentAccessor ); ``` {{< /tab >}} {{< /tabs >}} --- ## Configuration du Système de Particules ### Classe ParticleSystem La configuration racine pour un effet de particules : ```java public class ParticleSystem { protected String id; // Identifiant unique protected ParticleSpawnerGroup[] spawners; // Configurations de spawners protected float lifeSpan; // Durée de vie du système (secondes) protected float cullDistance; // Distance avant culling protected float boundingRadius; // Boîte englobante de collision protected boolean isImportant; // Flag de priorité réseau } ``` | Champ | Type | Description | |-------|------|-------------| | `id` | String | Identifiant unique du système de particules | | `spawners` | ParticleSpawnerGroup[] | Tableau de configurations de spawners | | `lifeSpan` | float | Durée de vie du système (secondes) | | `cullDistance` | float | Distance à laquelle les particules sont culled | | `boundingRadius` | float | Sphère englobante pour les calculs de culling | | `isImportant` | boolean | Si vrai, prioritisé dans la sync réseau | ### Configuration ParticleSpawner Contrôle comment les particules individuelles sont émises : {{< tabs items="Propriétés,Émission,Mouvement,Rendu" >}} {{< tab >}} ```java public class ParticleSpawner { protected String id; protected EmitShape shape; protected RangeVector3f emitOffset; protected boolean useEmitDirection; protected Range totalParticles; protected float lifeSpan; protected int maxConcurrentParticles; protected Rangef particleLifeSpan; protected Rangef spawnRate; protected boolean spawnBurst; protected InitialVelocity initialVelocity; protected ParticleAttractor[] attractors; protected FXRenderMode renderMode; protected float lightInfluence; protected Particle particle; } ``` {{< /tab >}} {{< tab >}} **Propriétés d'Émission :** | Propriété | Type | Description | |-----------|------|-------------| | `shape` | EmitShape | Forme d'émission Sphere ou Cube | | `emitOffset` | RangeVector3f | Plage d'offset aléatoire depuis l'origine | | `useEmitDirection` | boolean | Utiliser la direction de spawn pour la vélocité | | `totalParticles` | Range | Nombre min/max total de particules à émettre | | `spawnRate` | Rangef | Particules par seconde | | `spawnBurst` | boolean | Émettre tout d'un coup vs sur la durée | **Exemple de config d'émission :** ```java // Explosion burst - tout d'un coup spawner.setSpawnBurst(true); spawner.setTotalParticles(new Range(50, 100)); // Flux continu spawner.setSpawnBurst(false); spawner.setSpawnRate(new Rangef(10, 20)); // 10-20 par seconde spawner.setLifeSpan(5.0f); // Émettre pendant 5 secondes ``` {{< /tab >}} {{< tab >}} **Propriétés de Mouvement :** | Propriété | Type | Description | |-----------|------|-------------| | `initialVelocity` | InitialVelocity | Configuration de vélocité initiale | | `attractors` | ParticleAttractor[] | Forces appliquées aux particules | **Vélocité Initiale :** ```java public class InitialVelocity { protected float speed; // Vitesse de base protected float speedVariance; // Variance aléatoire protected Vector3f direction; // Direction de base protected float coneAngle; // Angle de dispersion (degrés) } ``` {{< /tab >}} {{< tab >}} **Propriétés de Rendu :** | Propriété | Type | Description | |-----------|------|-------------| | `renderMode` | FXRenderMode | Comment les particules sont blendées | | `lightInfluence` | float | Influence de l'éclairage sur les particules | | `particle` | Particle | Config texture et animation | {{< /tab >}} {{< /tabs >}} --- ## Formes d'Émission Contrôle le volume depuis lequel les particules apparaissent : ```java public enum EmitShape { Sphere, // Émettre depuis un volume sphérique Cube // Émettre depuis un volume cubique } ``` {{< tabs items="Sphere,Cube" >}} {{< tab >}} **Émission Sphérique :** Les particules apparaissent dans un volume sphérique, avec la direction pointant vers l'extérieur du centre : ```java // Configurer l'émission sphérique spawner.setShape(EmitShape.Sphere); spawner.setEmitOffset(new RangeVector3f( new Rangef(-1, 1), // Plage X (rayon) new Rangef(-1, 1), // Plage Y (rayon) new Rangef(-1, 1) // Plage Z (rayon) )); // Utiliser la direction d'émission pour la vélocité vers l'extérieur spawner.setUseEmitDirection(true); ``` Idéal pour : Explosions, bursts, effets radiaux {{< /tab >}} {{< tab >}} **Émission Cubique :** Les particules apparaissent dans un volume de boîte aligné sur les axes : ```java // Configurer l'émission cubique spawner.setShape(EmitShape.Cube); spawner.setEmitOffset(new RangeVector3f( new Rangef(-2, 2), // Plage X new Rangef(0, 3), // Plage Y (au-dessus du sol) new Rangef(-2, 2) // Plage Z )); ``` Idéal pour : Effets de zone, pluie, effets au sol {{< /tab >}} {{< /tabs >}} --- ## Modes de Rendu Détermine comment les particules se mélangent avec la scène : ```java public enum FXRenderMode { BlendLinear, // Blending de transparence standard BlendAdd, // Blending additif (brillant/lumineux) Erosion, // Effet d'érosion/dissolution Distortion // Effet de distorsion/réfraction } ``` {{< tabs items="BlendLinear,BlendAdd,Erosion,Distortion" >}} {{< tab >}} ### BlendLinear Blending alpha standard. Idéal pour : - Fumée - Poussière - Nuages - Particules d'apparence solide ```java spawner.setRenderMode(FXRenderMode.BlendLinear); ``` {{< /tab >}} {{< tab >}} ### BlendAdd Blending additif - les particules ajoutent de la lumière à la scène. Idéal pour : - Feu - Étincelles - Effets magiques - Particules lumineuses - Rayons de lumière ```java spawner.setRenderMode(FXRenderMode.BlendAdd); ``` {{< callout type="info" >}} Utilisez `BlendAdd` pour tout effet lumineux ou brillant. Plusieurs particules superposées créeront des zones plus lumineuses. {{< /callout >}} {{< /tab >}} {{< tab >}} ### Erosion Crée un effet visuel de dissolution/érosion. Idéal pour : - Désintégration - Transitions de dissolution - Dissipation d'énergie ```java spawner.setRenderMode(FXRenderMode.Erosion); ``` {{< /tab >}} {{< tab >}} ### Distortion Réfracte l'arrière-plan, créant des effets de miroitement de chaleur. Idéal pour : - Vagues de chaleur - Portails - Champs d'énergie - Effets sous-marins ```java spawner.setRenderMode(FXRenderMode.Distortion); ``` {{< callout type="warning" >}} Les effets de distorsion sont plus intensifs en GPU. Utilisez avec parcimonie. {{< /callout >}} {{< /tab >}} {{< /tabs >}} --- ## Attracteurs de Particules Applique des forces aux particules pour un mouvement dynamique : ```java public class ParticleAttractor { protected Vector3f position; // Position locale de l'attracteur protected Vector3f radialAxis; // Direction de la force radiale protected float radius; // Rayon d'influence // Accélérations (forces continues) protected float radialAcceleration; // Accélération vers l'extérieur/intérieur protected float radialTangentAcceleration; // Accélération tangentielle (orbite) protected Vector3f linearAcceleration; // Accélération linéaire directe // Impulsions (forces ponctuelles) protected float radialImpulse; // Impulsion vers l'extérieur/intérieur protected float radialTangentImpulse; // Impulsion tangentielle protected Vector3f linearImpulse; // Impulsion linéaire directe // Amortissement protected Vector3f dampingMultiplier; // Réduction de vélocité par frame } ``` ### Types de Forces {{< tabs items="Radiale,Tangentielle,Linéaire,Amortissement" >}} {{< tab >}} **Forces Radiales :** Pousse les particules vers ou loin de la position de l'attracteur : ```java ParticleAttractor attractor = new ParticleAttractor(); attractor.setPosition(new Vector3f(0, 0, 0)); // Centre du système // Explosion vers l'extérieur attractor.setRadialAcceleration(10.0f); // Positif = vers l'extérieur // Attraction vers l'intérieur (effet trou noir) attractor.setRadialAcceleration(-5.0f); // Négatif = vers l'intérieur // Burst instantané vers l'extérieur attractor.setRadialImpulse(20.0f); ``` {{< /tab >}} {{< tab >}} **Forces Tangentielles :** Crée un mouvement tourbillonnant/orbital autour de l'attracteur : ```java ParticleAttractor attractor = new ParticleAttractor(); attractor.setPosition(new Vector3f(0, 0, 0)); attractor.setRadialAxis(new Vector3f(0, 1, 0)); // Orbite autour de l'axe Y // Tourbillon horaire attractor.setRadialTangentAcceleration(5.0f); // Anti-horaire attractor.setRadialTangentAcceleration(-5.0f); ``` {{< /tab >}} {{< tab >}} **Forces Linéaires :** Applique une force directionnelle constante (comme la gravité ou le vent) : ```java ParticleAttractor attractor = new ParticleAttractor(); // Gravité (vers le bas) attractor.setLinearAcceleration(new Vector3f(0, -9.8f, 0)); // Vent (horizontal) attractor.setLinearAcceleration(new Vector3f(2.0f, 0, 0)); // Flottabilité vers le haut attractor.setLinearAcceleration(new Vector3f(0, 3.0f, 0)); ``` {{< /tab >}} {{< tab >}} **Amortissement :** Ralentit les particules au fil du temps : ```java ParticleAttractor attractor = new ParticleAttractor(); // Amortissement uniforme (résistance de l'air) attractor.setDampingMultiplier(new Vector3f(0.98f, 0.98f, 0.98f)); // Fort amortissement horizontal, faible vertical attractor.setDampingMultiplier(new Vector3f(0.9f, 0.99f, 0.9f)); // Pas d'amortissement (particules maintiennent leur vélocité) attractor.setDampingMultiplier(new Vector3f(1.0f, 1.0f, 1.0f)); ``` {{< callout type="info" >}} Les valeurs d'amortissement < 1.0 ralentissent les particules. Des valeurs de 0.98-0.99 donnent une résistance de l'air réaliste. {{< /callout >}} {{< /tab >}} {{< /tabs >}} --- ## Configuration Visuelle des Particules Configure l'apparence et l'animation des particules : ```java public class Particle { protected String texture; // Chemin de l'atlas de texture protected Size frameSize; // Dimensions du frame protected ParticleUVOption uvOption; // None, Animated, Random protected SoftParticle softParticle; // Blending soft particle protected float softParticlesFadeFactor; // 0.1 à 2.0 // Animation protected ParticleAnimationFrame initialAnimationFrame; protected Map animation; } ``` ### Options d'Animation ```java public enum ParticleUVOption { None, // Frame unique statique Animated, // Jouer les frames en séquence Random // Frame aléatoire par particule } ``` ### Frames d'Animation ```java public class ParticleAnimationFrame { protected int frame; // Numéro de frame dans l'atlas protected Rangef scale; // Plage de taille protected Rangef alpha; // Plage de transparence (0-1) protected Color color; // Teinte de couleur protected Rangef rotation; // Plage de rotation (degrés) } ``` --- ## Accéder aux Assets de Particules ```java // Obtenir un système de particules par ID ParticleSystem system = ParticleSystem.getAssetMap().getAsset("explosion_large"); // Obtenir la configuration d'un spawner ParticleSpawner spawner = ParticleSpawner.getAssetMap().getAsset("fire_spawner"); // Utiliser dans les arguments de commande // ArgTypes.PARTICLE_SYSTEM pour les paramètres de commande ``` --- ## Patterns Courants ### Particules Basées sur les Événements {{< callout type="warning" >}} **Note :** Les exemples ci-dessous sont simplifiés. Entity n'a pas de méthode `getPosition()` directe. Dans le code réel, obtenez la position via `TransformComponent` depuis le store de l'entité. Exemple : ```java TransformComponent transform = store.getComponent(entityRef, TransformComponent.getComponentType()); Vector3d position = transform.getPosition(); ``` {{< /callout >}} {{< tabs items="Destruction Bloc,Combat,Mort" >}} {{< tab >}} ```java @Subscribe public void onBlockBreak(BreakBlockEvent event) { // Utiliser getTargetBlock() - pas getPosition() Vector3i blockPos = event.getTargetBlock(); Vector3d pos = new Vector3d( blockPos.x + 0.5, blockPos.y + 0.5, blockPos.z + 0.5 ); // Générer des particules de destruction au centre du bloc ParticleUtil.spawnParticleEffect( "block_break_particles", pos, componentAccessor ); } ``` {{< /tab >}} {{< tab >}} ```java @Subscribe public void onEntityDamage(EntityDamageEvent event) { Entity target = event.getTarget(); Vector3d hitPos = target.getPosition().add(0, 1, 0); // Effet de sang/dégâts ParticleUtil.spawnParticleEffect( "damage_hit", hitPos, componentAccessor ); // Effet spécial coup critique if (event.isCritical()) { ParticleUtil.spawnParticleEffect( "critical_hit_sparks", hitPos, 0, 0, 0, // rotation 1.5f, // échelle plus grande new Color(255, 215, 0, 255), // couleur or getNearbyPlayers(hitPos, 50), componentAccessor ); } } ``` {{< /tab >}} {{< tab >}} ```java @Subscribe public void onEntityDeath(EntityDeathEvent event) { Entity entity = event.getEntity(); Vector3d deathPos = entity.getPosition(); // Particules de mort ParticleUtil.spawnParticleEffect( "entity_death_poof", deathPos, componentAccessor ); // Effet d'âme qui monte pour les joueurs if (entity instanceof Player) { ParticleUtil.spawnParticleEffect( "soul_ascend", deathPos.add(0, 0.5, 0), componentAccessor ); } } ``` {{< /tab >}} {{< /tabs >}} ### Effets Continus {{< tabs items="Traînée Joueur,Aura,Effet de Zone" >}} {{< tab >}} ```java // Générer une traînée de particules à la position du joueur public void spawnTrailEffect(Player player, Store store, ComponentAccessor componentAccessor) { if (hasTrailEffect(player)) { // Obtenir la position via TransformComponent Ref entityRef = player.getReference(); TransformComponent transform = store.getComponent(entityRef, TransformComponent.getComponentType()); if (transform != null) { Vector3d position = transform.getPosition(); ParticleUtil.spawnParticleEffect( "magic_trail", position, componentAccessor ); } } } ``` {{< callout type="warning" >}} **Note :** Player n'a pas de méthode `getPosition()`. Obtenez la position via `TransformComponent` depuis le store d'entités. {{< /callout >}} {{< /tab >}} {{< tab >}} ```java // Aura persistante autour du joueur public class AuraManager { private final Map activeAuras = new HashMap<>(); private Store store; private ComponentAccessor componentAccessor; public void enableAura(Player player) { // Utiliser player.getPlayerRef().getUuid() - pas player.getUuid() activeAuras.put(player.getPlayerRef().getUuid(), true); } @Subscribe public void onTick(ServerTickEvent event) { for (Map.Entry entry : activeAuras.entrySet()) { if (entry.getValue()) { Player player = getPlayer(entry.getKey()); if (player != null) { // Obtenir la position via TransformComponent Ref entityRef = player.getReference(); TransformComponent transform = store.getComponent( entityRef, TransformComponent.getComponentType()); if (transform != null) { Vector3d pos = transform.getPosition(); ParticleUtil.spawnParticleEffect( "magic_aura", new Vector3d(pos.getX(), pos.getY() + 1, pos.getZ()), componentAccessor ); } } } } } } ``` {{< /tab >}} {{< tab >}} ```java // Effet de zone de soin public void createHealingZone(Vector3d center, double radius, int durationTicks) { // Générer des particules en anneau for (int i = 0; i < 16; i++) { double angle = (2 * Math.PI * i) / 16; Vector3d pos = center.add( Math.cos(angle) * radius, 0.1, Math.sin(angle) * radius ); ParticleUtil.spawnParticleEffect( "healing_sparkle", pos, componentAccessor ); } // Effet pilier central ParticleUtil.spawnParticleEffect( "healing_pillar", center, componentAccessor ); } ``` {{< /tab >}} {{< /tabs >}} --- ## Directives de Performance {{< callout type="warning" >}} **Notes de Performance :** - Distance de diffusion par défaut : **75 blocs** (`DEFAULT_PARTICLE_DISTANCE`) - Les particules utilisent le paquet `SpawnParticleSystem` (ID : 152) - Définissez `isImportant = true` pour les feedbacks visuels critiques - Limitez le nombre de particules pour les performances client - Utilisez `maxConcurrentParticles` pour limiter les particules actives {{< /callout >}} ### Conseils d'Optimisation | Conseil | Description | |---------|-------------| | Limiter le total de particules | Gardez sous 100-200 pour les effets burst | | Utiliser une `cullDistance` appropriée | Ne pas rendre les particules trop éloignées | | Grouper les spawns | Générer plusieurs particules dans le même tick | | Utiliser `spawnBurst` judicieusement | Les bursts sont moins coûteux que le continu | | Considérer le nombre de joueurs | Plus de joueurs = plus de trafic réseau | ```java // Bon : Génération de particules efficace public void spawnEfficiently(Vector3d position) { // Générer seulement pour les joueurs proches List nearbyPlayers = getNearbyPlayers(position, 50); if (!nearbyPlayers.isEmpty()) { ParticleUtil.spawnParticleEffect( "my_effect", position, nearbyPlayers, // Audience limitée componentAccessor ); } } ``` --- ## Sujets Connexes - [Effets d'Entité]({{< relref "entity-effects" >}}) - Effets de statut avec composants visuels - [Réseau]({{< relref "/advanced/networking" >}}) - Comment les particules sont diffusées - [Événements]({{< relref "/core-concepts/events" >}}) - Déclencher des particules depuis les événements