789 lines
20 KiB
Markdown
789 lines
20 KiB
Markdown
---
|
|
title: Particles
|
|
type: docs
|
|
weight: 1
|
|
---
|
|
|
|
The particle system in Hytale provides rich visual effects through configurable emitters and renderers. Create explosions, trails, auras, and complex visual effects with precise control over behavior and appearance.
|
|
|
|
**Package:** `com.hypixel.hytale.server.core.asset.type.particle`
|
|
|
|
{{< cards cols="3" >}}
|
|
{{< card link="#spawning-particles" title="Spawning" subtitle="Create particle effects" icon="sparkles" >}}
|
|
{{< card link="#particle-system-configuration" title="Configuration" subtitle="System and spawner setup" icon="adjustments" >}}
|
|
{{< card link="#particle-attractors" title="Attractors" subtitle="Forces and movement" icon="arrow-circle-right" >}}
|
|
{{< /cards >}}
|
|
|
|
---
|
|
|
|
## Spawning Particles
|
|
|
|
### ParticleUtil Methods
|
|
|
|
{{< tabs items="Basic,Advanced,WorldParticle" >}}
|
|
{{< tab >}}
|
|
|
|
```java
|
|
import com.hypixel.hytale.server.core.universe.world.ParticleUtil;
|
|
|
|
// Basic spawn at position (auto-finds nearby players)
|
|
ParticleUtil.spawnParticleEffect(
|
|
"explosion_small", // Particle system ID
|
|
position, // Vector3d position
|
|
componentAccessor
|
|
);
|
|
|
|
// Spawn for specific players
|
|
ParticleUtil.spawnParticleEffect(
|
|
"magic_trail",
|
|
position,
|
|
playerRefs, // List<Ref<EntityStore>>
|
|
componentAccessor
|
|
);
|
|
```
|
|
|
|
**Broadcast Distance:** `DEFAULT_PARTICLE_DISTANCE = 75` blocks
|
|
|
|
{{< /tab >}}
|
|
{{< tab >}}
|
|
|
|
```java
|
|
// With source entity reference
|
|
ParticleUtil.spawnParticleEffect(
|
|
"attack_swing",
|
|
position,
|
|
sourceEntityRef, // Entity that spawned this
|
|
playerRefs,
|
|
componentAccessor
|
|
);
|
|
|
|
// With rotation control
|
|
ParticleUtil.spawnParticleEffect(
|
|
"directional_beam",
|
|
position,
|
|
yaw, pitch, roll, // Rotation angles
|
|
sourceEntityRef,
|
|
playerRefs,
|
|
componentAccessor
|
|
);
|
|
|
|
// With scale and color
|
|
ParticleUtil.spawnParticleEffect(
|
|
"colored_burst",
|
|
position,
|
|
yaw, pitch, roll,
|
|
2.0f, // Scale multiplier
|
|
new Color(255, 100, 50, 255), // RGBA color
|
|
playerRefs,
|
|
componentAccessor
|
|
);
|
|
```
|
|
|
|
{{< /tab >}}
|
|
{{< tab >}}
|
|
|
|
```java
|
|
import com.hypixel.hytale.server.core.asset.type.particle.config.WorldParticle;
|
|
|
|
// Full control with WorldParticle wrapper
|
|
WorldParticle worldParticle = new WorldParticle(
|
|
"my_particle_system",
|
|
new Color(255, 100, 50, 255), // RGBA color override
|
|
1.5f, // Scale multiplier
|
|
new Vector3f(0, 1, 0), // Position offset
|
|
new Direction(0, 0, 0) // Rotation offset
|
|
);
|
|
|
|
ParticleUtil.spawnParticleEffect(
|
|
worldParticle,
|
|
position,
|
|
sourceRef,
|
|
playerRefs,
|
|
componentAccessor
|
|
);
|
|
```
|
|
|
|
{{< /tab >}}
|
|
{{< /tabs >}}
|
|
|
|
---
|
|
|
|
## Particle System Configuration
|
|
|
|
### ParticleSystem Class
|
|
|
|
The root configuration for a particle effect:
|
|
|
|
```java
|
|
public class ParticleSystem {
|
|
protected String id; // Unique identifier
|
|
protected ParticleSpawnerGroup[] spawners; // Spawner configurations
|
|
protected float lifeSpan; // System lifetime (seconds)
|
|
protected float cullDistance; // Distance before culling
|
|
protected float boundingRadius; // Collision bounding box
|
|
protected boolean isImportant; // Network priority flag
|
|
}
|
|
```
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| `id` | String | Unique identifier for the particle system |
|
|
| `spawners` | ParticleSpawnerGroup[] | Array of spawner configurations |
|
|
| `lifeSpan` | float | How long the system lives (seconds) |
|
|
| `cullDistance` | float | Distance at which particles are culled |
|
|
| `boundingRadius` | float | Bounding sphere for culling calculations |
|
|
| `isImportant` | boolean | If true, prioritized in network sync |
|
|
|
|
### ParticleSpawner Configuration
|
|
|
|
Controls how individual particles are emitted:
|
|
|
|
{{< tabs items="Properties,Emission,Movement,Rendering" >}}
|
|
{{< 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 >}}
|
|
|
|
**Emission Properties:**
|
|
|
|
| Property | Type | Description |
|
|
|----------|------|-------------|
|
|
| `shape` | EmitShape | Sphere or Cube emission shape |
|
|
| `emitOffset` | RangeVector3f | Random offset range from origin |
|
|
| `useEmitDirection` | boolean | Use spawn direction for velocity |
|
|
| `totalParticles` | Range | Min/max total particles to emit |
|
|
| `spawnRate` | Rangef | Particles per second |
|
|
| `spawnBurst` | boolean | Emit all at once vs over time |
|
|
|
|
**Example emission setup:**
|
|
```java
|
|
// Burst explosion - all at once
|
|
spawner.setSpawnBurst(true);
|
|
spawner.setTotalParticles(new Range(50, 100));
|
|
|
|
// Continuous stream
|
|
spawner.setSpawnBurst(false);
|
|
spawner.setSpawnRate(new Rangef(10, 20)); // 10-20 per second
|
|
spawner.setLifeSpan(5.0f); // Emit for 5 seconds
|
|
```
|
|
|
|
{{< /tab >}}
|
|
{{< tab >}}
|
|
|
|
**Movement Properties:**
|
|
|
|
| Property | Type | Description |
|
|
|----------|------|-------------|
|
|
| `initialVelocity` | InitialVelocity | Starting velocity configuration |
|
|
| `attractors` | ParticleAttractor[] | Forces applied to particles |
|
|
|
|
**Initial Velocity:**
|
|
```java
|
|
public class InitialVelocity {
|
|
protected float speed; // Base speed
|
|
protected float speedVariance; // Random variance
|
|
protected Vector3f direction; // Base direction
|
|
protected float coneAngle; // Spread angle (degrees)
|
|
}
|
|
```
|
|
|
|
{{< /tab >}}
|
|
{{< tab >}}
|
|
|
|
**Rendering Properties:**
|
|
|
|
| Property | Type | Description |
|
|
|----------|------|-------------|
|
|
| `renderMode` | FXRenderMode | How particles are blended |
|
|
| `lightInfluence` | float | How much lighting affects particles |
|
|
| `particle` | Particle | Texture and animation config |
|
|
|
|
{{< /tab >}}
|
|
{{< /tabs >}}
|
|
|
|
---
|
|
|
|
## Emit Shapes
|
|
|
|
Control the volume from which particles spawn:
|
|
|
|
```java
|
|
public enum EmitShape {
|
|
Sphere, // Emit from spherical volume
|
|
Cube // Emit from cubic volume
|
|
}
|
|
```
|
|
|
|
{{< tabs items="Sphere,Cube" >}}
|
|
{{< tab >}}
|
|
|
|
**Spherical Emission:**
|
|
|
|
Particles spawn within a spherical volume, with direction pointing outward from center:
|
|
|
|
```java
|
|
// Configure spherical emission
|
|
spawner.setShape(EmitShape.Sphere);
|
|
spawner.setEmitOffset(new RangeVector3f(
|
|
new Rangef(-1, 1), // X range (radius)
|
|
new Rangef(-1, 1), // Y range (radius)
|
|
new Rangef(-1, 1) // Z range (radius)
|
|
));
|
|
|
|
// Use emit direction for outward velocity
|
|
spawner.setUseEmitDirection(true);
|
|
```
|
|
|
|
Best for: Explosions, bursts, radial effects
|
|
|
|
{{< /tab >}}
|
|
{{< tab >}}
|
|
|
|
**Cubic Emission:**
|
|
|
|
Particles spawn within an axis-aligned box volume:
|
|
|
|
```java
|
|
// Configure cubic emission
|
|
spawner.setShape(EmitShape.Cube);
|
|
spawner.setEmitOffset(new RangeVector3f(
|
|
new Rangef(-2, 2), // X range
|
|
new Rangef(0, 3), // Y range (above ground)
|
|
new Rangef(-2, 2) // Z range
|
|
));
|
|
```
|
|
|
|
Best for: Area effects, rain, ground effects
|
|
|
|
{{< /tab >}}
|
|
{{< /tabs >}}
|
|
|
|
---
|
|
|
|
## Render Modes
|
|
|
|
Determine how particles blend with the scene:
|
|
|
|
```java
|
|
public enum FXRenderMode {
|
|
BlendLinear, // Standard transparency blending
|
|
BlendAdd, // Additive blending (bright/glowing)
|
|
Erosion, // Erosion/dissolve effect
|
|
Distortion // Distortion/refraction effect
|
|
}
|
|
```
|
|
|
|
{{< tabs items="BlendLinear,BlendAdd,Erosion,Distortion" >}}
|
|
{{< tab >}}
|
|
|
|
### BlendLinear
|
|
|
|
Standard alpha blending. Best for:
|
|
- Smoke
|
|
- Dust
|
|
- Clouds
|
|
- Solid-looking particles
|
|
|
|
```java
|
|
spawner.setRenderMode(FXRenderMode.BlendLinear);
|
|
```
|
|
|
|
{{< /tab >}}
|
|
{{< tab >}}
|
|
|
|
### BlendAdd
|
|
|
|
Additive blending - particles add light to the scene. Best for:
|
|
- Fire
|
|
- Sparks
|
|
- Magic effects
|
|
- Glowing particles
|
|
- Light beams
|
|
|
|
```java
|
|
spawner.setRenderMode(FXRenderMode.BlendAdd);
|
|
```
|
|
|
|
{{< callout type="info" >}}
|
|
Use `BlendAdd` for any glowing or luminous effects. Multiple overlapping particles will create brighter spots.
|
|
{{< /callout >}}
|
|
|
|
{{< /tab >}}
|
|
{{< tab >}}
|
|
|
|
### Erosion
|
|
|
|
Creates dissolving/eroding visual effect. Best for:
|
|
- Disintegration
|
|
- Dissolve transitions
|
|
- Energy dissipation
|
|
|
|
```java
|
|
spawner.setRenderMode(FXRenderMode.Erosion);
|
|
```
|
|
|
|
{{< /tab >}}
|
|
{{< tab >}}
|
|
|
|
### Distortion
|
|
|
|
Refracts the background, creating heat-shimmer effects. Best for:
|
|
- Heat waves
|
|
- Portals
|
|
- Energy fields
|
|
- Underwater effects
|
|
|
|
```java
|
|
spawner.setRenderMode(FXRenderMode.Distortion);
|
|
```
|
|
|
|
{{< callout type="warning" >}}
|
|
Distortion effects are more GPU-intensive. Use sparingly.
|
|
{{< /callout >}}
|
|
|
|
{{< /tab >}}
|
|
{{< /tabs >}}
|
|
|
|
---
|
|
|
|
## Particle Attractors
|
|
|
|
Apply forces to particles for dynamic movement:
|
|
|
|
```java
|
|
public class ParticleAttractor {
|
|
protected Vector3f position; // Local attractor position
|
|
protected Vector3f radialAxis; // Radial force direction
|
|
protected float radius; // Influence radius
|
|
|
|
// Accelerations (continuous forces)
|
|
protected float radialAcceleration; // Outward/inward acceleration
|
|
protected float radialTangentAcceleration; // Tangential (orbit) acceleration
|
|
protected Vector3f linearAcceleration; // Direct linear acceleration
|
|
|
|
// Impulses (one-time forces)
|
|
protected float radialImpulse; // Outward/inward impulse
|
|
protected float radialTangentImpulse; // Tangential impulse
|
|
protected Vector3f linearImpulse; // Direct linear impulse
|
|
|
|
// Damping
|
|
protected Vector3f dampingMultiplier; // Velocity reduction per frame
|
|
}
|
|
```
|
|
|
|
### Force Types
|
|
|
|
{{< tabs items="Radial,Tangential,Linear,Damping" >}}
|
|
{{< tab >}}
|
|
|
|
**Radial Forces:**
|
|
|
|
Push particles toward or away from the attractor position:
|
|
|
|
```java
|
|
ParticleAttractor attractor = new ParticleAttractor();
|
|
attractor.setPosition(new Vector3f(0, 0, 0)); // Center of system
|
|
|
|
// Outward explosion
|
|
attractor.setRadialAcceleration(10.0f); // Positive = outward
|
|
|
|
// Inward pull (black hole effect)
|
|
attractor.setRadialAcceleration(-5.0f); // Negative = inward
|
|
|
|
// Instant outward burst
|
|
attractor.setRadialImpulse(20.0f);
|
|
```
|
|
|
|
{{< /tab >}}
|
|
{{< tab >}}
|
|
|
|
**Tangential Forces:**
|
|
|
|
Create swirling/orbiting motion around the attractor:
|
|
|
|
```java
|
|
ParticleAttractor attractor = new ParticleAttractor();
|
|
attractor.setPosition(new Vector3f(0, 0, 0));
|
|
attractor.setRadialAxis(new Vector3f(0, 1, 0)); // Orbit around Y axis
|
|
|
|
// Clockwise swirl
|
|
attractor.setRadialTangentAcceleration(5.0f);
|
|
|
|
// Counter-clockwise
|
|
attractor.setRadialTangentAcceleration(-5.0f);
|
|
```
|
|
|
|
{{< /tab >}}
|
|
{{< tab >}}
|
|
|
|
**Linear Forces:**
|
|
|
|
Apply constant directional force (like gravity or wind):
|
|
|
|
```java
|
|
ParticleAttractor attractor = new ParticleAttractor();
|
|
|
|
// Gravity (downward)
|
|
attractor.setLinearAcceleration(new Vector3f(0, -9.8f, 0));
|
|
|
|
// Wind (horizontal)
|
|
attractor.setLinearAcceleration(new Vector3f(2.0f, 0, 0));
|
|
|
|
// Upward buoyancy
|
|
attractor.setLinearAcceleration(new Vector3f(0, 3.0f, 0));
|
|
```
|
|
|
|
{{< /tab >}}
|
|
{{< tab >}}
|
|
|
|
**Damping:**
|
|
|
|
Slow particles down over time:
|
|
|
|
```java
|
|
ParticleAttractor attractor = new ParticleAttractor();
|
|
|
|
// Uniform damping (air resistance)
|
|
attractor.setDampingMultiplier(new Vector3f(0.98f, 0.98f, 0.98f));
|
|
|
|
// Strong horizontal damping, weak vertical
|
|
attractor.setDampingMultiplier(new Vector3f(0.9f, 0.99f, 0.9f));
|
|
|
|
// No damping (particles maintain velocity)
|
|
attractor.setDampingMultiplier(new Vector3f(1.0f, 1.0f, 1.0f));
|
|
```
|
|
|
|
{{< callout type="info" >}}
|
|
Damping values < 1.0 slow particles. Values of 0.98-0.99 give realistic air resistance.
|
|
{{< /callout >}}
|
|
|
|
{{< /tab >}}
|
|
{{< /tabs >}}
|
|
|
|
---
|
|
|
|
## Particle Visual Configuration
|
|
|
|
Configure particle appearance and animation:
|
|
|
|
```java
|
|
public class Particle {
|
|
protected String texture; // Texture atlas path
|
|
protected Size frameSize; // Frame dimensions
|
|
|
|
protected ParticleUVOption uvOption; // None, Animated, Random
|
|
protected SoftParticle softParticle; // Soft particle blending
|
|
protected float softParticlesFadeFactor; // 0.1 to 2.0
|
|
|
|
// Animation
|
|
protected ParticleAnimationFrame initialAnimationFrame;
|
|
protected Map<Integer, ParticleAnimationFrame> animation;
|
|
}
|
|
```
|
|
|
|
### Animation Options
|
|
|
|
```java
|
|
public enum ParticleUVOption {
|
|
None, // Single static frame
|
|
Animated, // Play through frames in sequence
|
|
Random // Random frame per particle
|
|
}
|
|
```
|
|
|
|
### Animation Frames
|
|
|
|
```java
|
|
public class ParticleAnimationFrame {
|
|
protected int frame; // Frame number in atlas
|
|
protected Rangef scale; // Size range
|
|
protected Rangef alpha; // Transparency range (0-1)
|
|
protected Color color; // Color tint
|
|
protected Rangef rotation; // Rotation range (degrees)
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Accessing Particle Assets
|
|
|
|
```java
|
|
// Get particle system by ID
|
|
ParticleSystem system = ParticleSystem.getAssetMap().getAsset("explosion_large");
|
|
|
|
// Get spawner configuration
|
|
ParticleSpawner spawner = ParticleSpawner.getAssetMap().getAsset("fire_spawner");
|
|
|
|
// Use in command arguments
|
|
// ArgTypes.PARTICLE_SYSTEM for command parameters
|
|
```
|
|
|
|
---
|
|
|
|
## Common Patterns
|
|
|
|
### Event-Based Particles
|
|
|
|
{{< callout type="warning" >}}
|
|
**Note:** The examples below are simplified. Entity doesn't have a direct `getPosition()` method. In real code, obtain position via `TransformComponent` from the entity's store. Example:
|
|
```java
|
|
TransformComponent transform = store.getComponent(entityRef, TransformComponent.getComponentType());
|
|
Vector3d position = transform.getPosition();
|
|
```
|
|
{{< /callout >}}
|
|
|
|
{{< tabs items="Block Break,Combat,Death" >}}
|
|
{{< tab >}}
|
|
|
|
```java
|
|
@Subscribe
|
|
public void onBlockBreak(BreakBlockEvent event) {
|
|
// Use getTargetBlock() - not getPosition()
|
|
Vector3i blockPos = event.getTargetBlock();
|
|
Vector3d pos = new Vector3d(
|
|
blockPos.x + 0.5,
|
|
blockPos.y + 0.5,
|
|
blockPos.z + 0.5
|
|
);
|
|
|
|
// Spawn break particles at block center
|
|
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);
|
|
|
|
// Blood/damage effect
|
|
ParticleUtil.spawnParticleEffect(
|
|
"damage_hit",
|
|
hitPos,
|
|
componentAccessor
|
|
);
|
|
|
|
// Critical hit special effect
|
|
if (event.isCritical()) {
|
|
ParticleUtil.spawnParticleEffect(
|
|
"critical_hit_sparks",
|
|
hitPos,
|
|
0, 0, 0, // rotation
|
|
1.5f, // larger scale
|
|
new Color(255, 215, 0, 255), // gold color
|
|
getNearbyPlayers(hitPos, 50),
|
|
componentAccessor
|
|
);
|
|
}
|
|
}
|
|
```
|
|
|
|
{{< /tab >}}
|
|
{{< tab >}}
|
|
|
|
```java
|
|
@Subscribe
|
|
public void onEntityDeath(EntityDeathEvent event) {
|
|
Entity entity = event.getEntity();
|
|
Vector3d deathPos = entity.getPosition();
|
|
|
|
// Death particles
|
|
ParticleUtil.spawnParticleEffect(
|
|
"entity_death_poof",
|
|
deathPos,
|
|
componentAccessor
|
|
);
|
|
|
|
// Soul rising effect for players
|
|
if (entity instanceof Player) {
|
|
ParticleUtil.spawnParticleEffect(
|
|
"soul_ascend",
|
|
deathPos.add(0, 0.5, 0),
|
|
componentAccessor
|
|
);
|
|
}
|
|
}
|
|
```
|
|
|
|
{{< /tab >}}
|
|
{{< /tabs >}}
|
|
|
|
### Continuous Effects
|
|
|
|
{{< tabs items="Player Trail,Aura,Area Effect" >}}
|
|
{{< tab >}}
|
|
|
|
```java
|
|
// Spawn particle trail at player position
|
|
public void spawnTrailEffect(Player player, Store<EntityStore> store,
|
|
ComponentAccessor<EntityStore> componentAccessor) {
|
|
if (hasTrailEffect(player)) {
|
|
// Get position from 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 doesn't have a `getPosition()` method. Get position via `TransformComponent` from the entity store.
|
|
{{< /callout >}}
|
|
|
|
{{< /tab >}}
|
|
{{< tab >}}
|
|
|
|
```java
|
|
// Persistent aura around player
|
|
public class AuraManager {
|
|
private final Map<UUID, Boolean> activeAuras = new HashMap<>();
|
|
private Store<EntityStore> store;
|
|
private ComponentAccessor<EntityStore> componentAccessor;
|
|
|
|
public void enableAura(Player player) {
|
|
// Use player.getPlayerRef().getUuid() - not 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) {
|
|
// Get position from 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
|
|
// Area healing effect
|
|
public void createHealingZone(Vector3d center, double radius, int durationTicks) {
|
|
// Spawn ring particles
|
|
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
|
|
);
|
|
}
|
|
|
|
// Central pillar effect
|
|
ParticleUtil.spawnParticleEffect(
|
|
"healing_pillar",
|
|
center,
|
|
componentAccessor
|
|
);
|
|
}
|
|
```
|
|
|
|
{{< /tab >}}
|
|
{{< /tabs >}}
|
|
|
|
---
|
|
|
|
## Performance Guidelines
|
|
|
|
{{< callout type="warning" >}}
|
|
**Performance Notes:**
|
|
- Default broadcast distance: **75 blocks** (`DEFAULT_PARTICLE_DISTANCE`)
|
|
- Particles use `SpawnParticleSystem` packet (ID: 152)
|
|
- Set `isImportant = true` for critical visual feedback
|
|
- Limit particle count for client performance
|
|
- Use `maxConcurrentParticles` to cap active particles
|
|
{{< /callout >}}
|
|
|
|
### Optimization Tips
|
|
|
|
| Tip | Description |
|
|
|-----|-------------|
|
|
| Limit total particles | Keep under 100-200 for burst effects |
|
|
| Use appropriate `cullDistance` | Don't render particles too far away |
|
|
| Batch spawns | Spawn multiple particles in same tick |
|
|
| Use `spawnBurst` wisely | Bursts are cheaper than continuous |
|
|
| Consider player count | More players = more network traffic |
|
|
|
|
```java
|
|
// Good: Efficient particle spawning
|
|
public void spawnEfficiently(Vector3d position) {
|
|
// Only spawn for nearby players
|
|
List<PlayerRef> nearbyPlayers = getNearbyPlayers(position, 50);
|
|
|
|
if (!nearbyPlayers.isEmpty()) {
|
|
ParticleUtil.spawnParticleEffect(
|
|
"my_effect",
|
|
position,
|
|
nearbyPlayers, // Limited audience
|
|
componentAccessor
|
|
);
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Related Topics
|
|
|
|
- [Entity Effects]({{< relref "entity-effects" >}}) - Status effects with visual components
|
|
- [Networking]({{< relref "/advanced/networking" >}}) - How particles are broadcast
|
|
- [Events]({{< relref "/core-concepts/events" >}}) - Triggering particles from events
|