📄 particlecontroller.java
字号:
/*
* Copyright (c) 2003-2009 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jmex.effects.particles;
import java.io.IOException;
import java.util.ArrayList;
import com.jme.math.FastMath;
import com.jme.renderer.Camera;
import com.jme.renderer.Camera.FrustumIntersect;
import com.jme.scene.Controller;
import com.jme.scene.Spatial;
import com.jme.system.DisplaySystem;
import com.jme.util.export.InputCapsule;
import com.jme.util.export.JMEExporter;
import com.jme.util.export.JMEImporter;
import com.jme.util.export.OutputCapsule;
/**
* <code>ParticleController</code> controls and maintains the parameters of a
* ParticleGeometry particle system over time.
*
* @author Joshua Slack
* @version $Id: ParticleController.java,v 1.14 2007/04/03 14:30:20 nca Exp $
*/
public class ParticleController extends Controller {
private static final long serialVersionUID = 1L;
private ParticleSystem particles;
private int particlesToCreate = 0;
private float releaseVariance;
private float currentTime;
private float prevTime;
private float releaseParticles;
private float timePassed;
private float precision;
private boolean controlFlow;
private boolean updateOnlyInView;
private Camera viewCamera;
private int iterations;
private ArrayList<ParticleInfluence> influences;
protected ArrayList<ParticleControllerListener> listeners;
public ParticleController() {}
/**
* ParticleManager constructor
*
* @param system
* Target ParticleGeometry to act upon.
*/
public ParticleController(ParticleSystem system) {
this.particles = system;
setMinTime(0);
setMaxTime(Float.MAX_VALUE);
setRepeatType(Controller.RT_WRAP);
setSpeed(1.0f);
releaseVariance = 0;
controlFlow = false;
updateOnlyInView = false;
precision = .01f; // 10ms
system.updateRotationMatrix();
warmUp(60);
}
/**
* Update the particles managed by this manager. If any particles are "dead"
* recreate them at the origin position (which may be a point, line or
* rectangle.) See com.jme.scene.Controller.update(float)
*
* @param secondsPassed
* float
*/
public void update(float secondsPassed) {
// If instructed, check to see if our last frustum check passed
if (isUpdateOnlyInView()) {
Camera cam = viewCamera != null ? viewCamera : DisplaySystem
.getDisplaySystem().getRenderer().getCamera();
int state = cam.getPlaneState();
boolean out = cam.contains(particles.getWorldBound()).equals(FrustumIntersect.Outside);
cam.setPlaneState(state);
if (out) {
return;
}
}
// Add time and unless we have more than precision time passed
// since last real update, do nothing
currentTime += secondsPassed * getSpeed();
// Check precision passes
timePassed = currentTime - prevTime;
if (timePassed < precision * getSpeed()) {
return;
}
// We are actually going to do a real update,
// so this is our new previous time
prevTime = currentTime;
// Update the current rotation matrix if needed.
particles.updateRotationMatrix();
// If we are in the time window where this controller is active
// (defaults to 0 to Float.MAX_VALUE for ParticleController)
if (currentTime >= getMinTime() && currentTime <= getMaxTime()) {
// If we are controlling the flow (ie the rate of particle spawning.)
if (controlFlow) {
// Release a number of particles based on release rate,
// timePassed (already scaled for speed) and variance. This
// is added to any current value Note this is a float value,
// so we will keep adding up partial particles
releaseParticles += (particles.getReleaseRate() *
timePassed * (1.0f + releaseVariance *
(FastMath.nextRandomFloat() - 0.5f)));
// Try to create all "whole" particles we have added up
particlesToCreate = (int) releaseParticles;
// If we have any whole particles, then subtract them from
// releaseParticles
if (particlesToCreate > 0)
releaseParticles -= particlesToCreate;
// Make sure particlesToCreate is not negative
else
particlesToCreate = 0;
}
particles.updateInvScale();
// If we have any influences, prepare them all
if (influences != null) {
for (ParticleInfluence influence : influences) {
influence.prepare(particles);
}
}
// Track particle index
int i = 0;
// Track whether the whole set of particles is "dead" - if any
// particles are still alive, this will be set to false
boolean dead = true;
// opposite of above boolean, but tracked seperately
boolean anyAlive = false;
// i is index through all particles
while (i < particles.getNumParticles()) {
// Current particle
Particle p = particles.getParticle(i);
// If we have influences and particle is alive
if (influences != null && p.getStatus() == Particle.Status.Alive) {
// Apply each enabled influence to the current particle
for (int x = 0; x < influences.size(); x++) {
ParticleInfluence inf = influences.get(x);
if (inf.isEnabled())
inf.apply(timePassed, p, i);
}
}
// Update and check the particle.
// If this returns true, indicating particle is ready to be
// reused, we may reuse it. Do so if we are not using
// control flow, OR we intend to create particles based on
// control flow count calculated above
boolean reuse = p.updateAndCheck(timePassed);
if (reuse && (!controlFlow || particlesToCreate > 0)) {
// Don't recreate the particle if it is dead, and we are clamped
if (p.getStatus() == Particle.Status.Dead
&& getRepeatType() == RT_CLAMP) {
;
// We plan to reuse the particle
} else {
// Not all particles are dead (this one will be reused)
dead = false;
// If we are doing flow control, decrement
// particlesToCreate, since we are about to create
// one
if (controlFlow) {
particlesToCreate--;
}
// Recreate the particle
p.recreateParticle(particles.getRandomLifeSpan());
p.setStatus(Particle.Status.Alive);
particles.initParticleLocation(i);
particles.resetParticleVelocity(i);
p.updateVerts(null);
}
} else if (!reuse || (controlFlow && particles.getReleaseRate() > 0)) {
// The particle wasn't dead, or we expect more particles
// later, so we're not dead!
dead = false;
}
// Check for living particles so we know when to update our boundings.
if (p.getStatus() == Particle.Status.Alive) {
anyAlive = true;
}
// Next particle
i++;
}
// If we are dead, deactivate and tell our listeners
if (dead) {
setActive(false);
if (listeners != null && listeners.size() > 0) {
for (ParticleControllerListener listener : listeners) {
listener.onDead(particles);
}
}
}
// If we have a bound and any live particles, update it
if (particles.getParticleGeometry().getModelBound() != null && anyAlive) {
particles.updateModelBound();
particles.updateWorldBoundManually();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -