Trouble with SwarmInfluence

I have created an effect in the RenParticleEditor which is designed to look like a shield. Basically it's just an omnidirectional emitter with a swarm influence. It looks great in the editor. Unfortunately, when I bring it into my game, the particles run away and swarm around the origin.

I have tried using SwarmInfluence.setSwarmOffset(particles.getWorldTranslation()) but for some reason it isn't working. It's not actually sticking. Printing the swarm offset right after I set it shows that it's still stuck at 0,0,0… help!

Well I found a bug–the method setSwarmOffset(Vector3f) sets the swarm POINT, not offset. getSwarmOffset(), however, returns swarmOffset. It looks like we need to modify setSwarmOffset  to set the point? Or include a setSwarmPoint(Vector3f v) method?

swarm point is meant for internal use, so the bug is that setSwarmOffset should be setting… swarmOffset. :slight_smile:

Post a patch for us Trussell. :slight_smile:

Well I'm honored! I've never actually posted a patch before. I'll have to google how to do it :stuck_out_tongue:

I've seen people do this + and - thing where stuff should be deleted or added… I've looked it up but searching "how to patch source code" comes up with lots of garbage… so here's the entire java file:

package com.jmex.effects.particles;


import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.util.export.InputCapsule;
import com.jme.util.export.JMEExporter;
import com.jme.util.export.JMEImporter;
import com.jme.util.export.OutputCapsule;

 * Simple swarming influence for use with particles.
 * @author Joshua Slac
public class SwarmInfluence extends ParticleInfluence {

    private float swarmRangeSQ;
    private Vector3f swarmOffset;
    private Vector3f swarmPoint = new Vector3f();
    public static final float DEFAULT_SWARM_RANGE_SQ = 0.01f;
    public static final float DEFAULT_DEVIANCE = FastMath.DEG_TO_RAD * 15;
    public static final float DEFAULT_TURN_SPEED = FastMath.DEG_TO_RAD * 180;
    public static final float DEFAULT_SPEED_BUMP = .1f;
    public static final float DEFAULT_MAX_SPEED = .2f;
    private float deviance = DEFAULT_DEVIANCE;
    private float turnSpeed = DEFAULT_TURN_SPEED;
    private float speedBump = DEFAULT_SPEED_BUMP;
    private float maxSpeed = DEFAULT_MAX_SPEED;
    private transient float maxSpeedSQ = DEFAULT_MAX_SPEED * DEFAULT_MAX_SPEED;

    private static final Vector3f workVect = new Vector3f();
    private static final Vector3f workVect2 = new Vector3f();
    private static final Quaternion workQuat = new Quaternion();
    public SwarmInfluence() {
        this.swarmRangeSQ = DEFAULT_SWARM_RANGE_SQ;
        this.swarmOffset = new Vector3f();
    public SwarmInfluence(Vector3f offset, float swarmRange) {
        this.swarmRangeSQ = swarmRange * swarmRange;
        this.swarmOffset = offset;
    public void prepare(ParticleSystem system) {
    public void apply(float dt, Particle particle, int index) {
        Vector3f pVelocity = particle.getVelocity();
        // determine if the particle is in the inner or outer zone
        float pDist = particle.getPosition().distanceSquared(swarmPoint);
        if (pDist > swarmRangeSQ) {
            // IN THE OUTER ZONE...
            // Determine if the angle between particle velocity and a vector to
            // the swarmPoint is less than the accepted deviance
            float angle = workVect.angleBetween(workVect2);
            if (angle < deviance) {
                // if it is, increase the speed speedBump over time
                if (pVelocity.lengthSquared() < maxSpeedSQ) {
                    float change = speedBump*dt;
                    workVect2.multLocal(change); // where workVector2 = pVelocity.normalizeLocal()
            } else {
                Vector3f axis = workVect2.crossLocal(workVect);
                // if it is not, shift the velocity to bring it back in line
                if ((Float.floatToIntBits(pVelocity.lengthSquared()) & 0x1f) != 0) {
                    workQuat.fromAngleAxis(turnSpeed * dt, axis);
                } else {
                    workQuat.fromAngleAxis(-turnSpeed * dt, axis);
        } else {
            Vector3f axis = workVect2.crossLocal(workVect);
            // IN THE INNER ZONE...
            // Alter the heading based on how fast we are going
            if ((index & 0x1f) != 0) {
                workQuat.fromAngleAxis(turnSpeed * dt, axis);
            } else {
                workQuat.fromAngleAxis(-turnSpeed * dt, axis);

    public float getSwarmRange() {
        return FastMath.sqrt(swarmRangeSQ);

    public void setSwarmRange(float swarmRange) {
        this.swarmRangeSQ = swarmRange * swarmRange;

    public Vector3f getSwarmOffset() {
        return swarmOffset;

    public void setSwarmOffset(Vector3f offset) {
        this.swarmOffset = offset;

    public float getDeviance() {
        return deviance;

    public void setDeviance(float deviance) {
        this.deviance = deviance;

    public float getSpeedBump() {
        return speedBump;

    public void setSpeedBump(float speedVariance) {
        this.speedBump = speedVariance;

    public float getTurnSpeed() {
        return turnSpeed;

    public void setTurnSpeed(float turnSpeed) {
        this.turnSpeed = turnSpeed;

    public float getMaxSpeed() {
        return maxSpeed;

    public void setMaxSpeed(float maxSpeed) {
        this.maxSpeed = maxSpeed;
        maxSpeedSQ = maxSpeed * maxSpeed;
    public void write(JMEExporter e) throws IOException {
        OutputCapsule cap = e.getCapsule(this);
        cap.write(swarmRangeSQ, "swarmRangeSQ", DEFAULT_SWARM_RANGE_SQ);
        cap.write(deviance, "deviance", DEFAULT_DEVIANCE);
        cap.write(turnSpeed, "turnSpeed", DEFAULT_TURN_SPEED);
        cap.write(speedBump, "speedBump", DEFAULT_SPEED_BUMP);
        cap.write(maxSpeed, "maxSpeed", DEFAULT_MAX_SPEED);
        cap.write(swarmOffset, "swarmOffset", new Vector3f());
    public void read(JMEImporter e) throws IOException {;
        InputCapsule cap = e.getCapsule(this);
        swarmRangeSQ = cap.readFloat("swarmRangeSQ", DEFAULT_SWARM_RANGE_SQ);
        deviance = cap.readFloat("deviance", DEFAULT_DEVIANCE);
        turnSpeed = cap.readFloat("turnSpeed", DEFAULT_TURN_SPEED);
        speedBump = cap.readFloat("speedBump", DEFAULT_SPEED_BUMP);
        maxSpeed = cap.readFloat("maxSpeed", DEFAULT_MAX_SPEED);
        swarmOffset = (Vector3f)cap.readSavable("swarmOffset", new Vector3f());


Patches can usually be generated by your subversion client. If you are using Tortoise you can right click on the source file in explorer and create a patch. If you are using SVN integrated with eclipse you will find it by right clicking the file in the project view, and then under the Team sub-menu.

…also please post your patch in the Contrib Depot and then link it from here.

Okay. I'm using SVN integrated with NetBeans, so I'm looking for it right now.


Damn. The bugfix still isn't affecting the behavior I'm seeing at all. All particles swarm to the origin for some reason…