---
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<Ref<EntityStore>>
    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<Integer, ParticleAnimationFrame> 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<EntityStore> store,
                              ComponentAccessor<EntityStore> componentAccessor) {
    if (hasTrailEffect(player)) {
        // Obtenir la position via TransformComponent
        Ref<EntityStore> 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<UUID, Boolean> activeAuras = new HashMap<>();
    private Store<EntityStore> store;
    private ComponentAccessor<EntityStore> 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<UUID, Boolean> entry : activeAuras.entrySet()) {
            if (entry.getValue()) {
                Player player = getPlayer(entry.getKey());
                if (player != null) {
                    // Obtenir la position via TransformComponent
                    Ref<EntityStore> 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<PlayerRef> 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
