Init
This commit is contained in:
788
content/advanced/effects/particles.en.md
Normal file
788
content/advanced/effects/particles.en.md
Normal file
@@ -0,0 +1,788 @@
|
||||
---
|
||||
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
|
||||
Reference in New Issue
Block a user