News: Go to the wiki and do the Flying Ship tutorial February 06, 2012, 02:15:51 am
Welcome, Guest. Please login or register. *

particle system ideas
Pages: 1
  Send this topic  |  Print  

  particle system ideas
Author Message
0 Members and 1 Guest are viewing this topic.
2playgames
OpenWar Project Founder
Administrator
Sr. Member
***
Offline Offline

Posts: 857


Busy busy busy busy busy


View Profile WWW
« on: May 10, 2008, 10:36:36 pm »

(23:14:10) Phil: Also more about the Particle System, this is how it works. For a basic particle system it has an Emitter Velocity, Volume, and Affector. The Emitter Volume determines where the particle is located in space when its created and its initial direction. The Emitter Velocity determines based on its direction its speed and acceleration or a new directon. The Emitter Affector(s) determine each....
(23:14:32) Phil: Particles appearance over time, such as how its angle changes, its size, its shade, etc
(23:15:19) Phil: So the different emitter volumes can be a point, rectangle, ellipse, line, spline, bezier, etc.
(23:16:01) Phil: The different emitter velocities are directional, ortho, outward, towards, etc. And the different affectors can be size, angle, color, alpha, gravity, etc.
(23:16:26) Phil: So each system has one emitter velocity and volume, and a list of affectors.
(23:17:37) Phil: So theres an interface for an emitter velocity, and emitter volume, then some concrete class to implement them. These interfaces also lets the particle systems customizable because a user can create their own emitter type for their own specific needs.
(23:19:04) Phil: any input? anything overly complicated?
(23:19:13) Bart van Heukelom.nl [2playgames]: i understand the volume and the affector
(23:19:17) Phil: ok
(23:19:34) Bart van Heukelom.nl [2playgames]: which btw i'd cal (Particle)Emitter and ParticleAffector respectively :p
(23:19:42) Bart van Heukelom.nl [2playgames]: but i don't really get what the velocity does
(23:19:46) Phil: Ok
(23:20:11) Bart van Heukelom.nl [2playgames]: i also assume there's a fourth class particle
(23:20:20) Bart van Heukelom.nl [2playgames]: and a 5th particlesystem
(23:22:03) Phil: well an example Velocity is Directional. Directional takes in a "minAngle", "maxAngle", and "minSpeed", "maxSpeed". So the particle would point somewhere between the two angles given, and have a speed between the two speeds given. Another example would be an Outward velocity. Outward velocity points the direction of the particles away from the systems location, so they radiate out from a point, an
(23:22:12) Phil: ellipse, or whatever volume.
(23:22:23) Bart van Heukelom.nl [2playgames]: yes but why not put all that in affector?
(23:23:23) Phil: The affector manipulates the particles over time, this gives the particles an initial angle and initial speed.
(23:23:35) Phil: You could have it in an affector, but its slower
(23:23:51) Bart van Heukelom.nl [2playgames]: so basically volume+velocity = emitter
(23:23:55) Phil: yes
(23:24:06) Bart van Heukelom.nl [2playgames]: but then in a way that you can make different combinations
(23:24:09) Bart van Heukelom.nl [2playgames]: yeah, seems smart
(23:24:47) Phil: yeah, instead of restricting to certain emitter types this makes it better object oriented and customizable.
(23:25:01) Bart van Heukelom.nl [2playgames]: volume = creator, velocity = launcher, something like that Smiley
(23:25:10) Phil: yes
(23:25:24) Bart van Heukelom.nl [2playgames]: and then affector = steer
(23:25:30) Phil: yup.
(23:25:32) Bart van Heukelom.nl [2playgames]: ok
(23:26:41) Bart van Heukelom.nl [2playgames]: but how will you allow extending the amount of particle types
(23:26:54) Phil: explain
(23:27:19) Bart van Heukelom.nl [2playgames]: for example, if i want a particle which draws a guy (just a random example)
(23:27:28) Bart van Heukelom.nl [2playgames]: and i want it to grow more legs over time
(23:27:50) Bart van Heukelom.nl [2playgames]: i can't use affector, because it doesn't know the particle may even have a property for legs?
(23:27:57) Phil: ohh
(23:28:32) Phil: do you have a better example? lol I don't understand what you mean by grow legs
(23:28:55) Bart van Heukelom.nl [2playgames]: well, like it has two legs first, but in time gets more, ending up with 5
(23:29:07) Phil: oh ok
(23:29:15) Bart van Heukelom.nl [2playgames]: in other words, a particle type with a new kind of property
(23:30:06) Phil: well each particle has an update method, so if you make that class inherit particle, and override the update then you can put whatever logic inside that. The particle knows its lifetime, its current time in life, etc
(23:30:16) Bart van Heukelom.nl [2playgames]: ok
(23:30:24) Bart van Heukelom.nl [2playgames]: but what if i want to use the same particle in two effects
(23:30:33) Bart van Heukelom.nl [2playgames]: in one i want it to grow legs, in the other i want arms
(23:30:37) Bart van Heukelom.nl [2playgames]: same particle, different affectors
(23:30:45) Phil: Ohh
(23:30:46) Phil: hmm
(23:31:07) Bart van Heukelom.nl [2playgames]: perhaps make Affector generic (Affector<GuyParticle>)
(23:31:13) Phil: Well Ill make the affector a template
(23:31:14) Phil: yeah
(23:31:39) Phil: so anything that inherits a particle can be affected uniquely
(23:31:48) Phil: according to the affector
(23:32:00) Phil: does that work?
(23:32:03) Bart van Heukelom.nl [2playgames]: yeah
(23:32:17) Bart van Heukelom.nl [2playgames]: although we'd have to split up volume, so we can have multiple particle types in it
(23:32:34) Phil: like..
(23:33:02) Bart van Heukelom.nl [2playgames]: Volume.addType(GuyParticle.class, LegAffector) // LegAffector = Affector<GuyParticle>)
(23:33:32) Phil: Well the particle system has the list of affectors
(23:33:48) Bart van Heukelom.nl [2playgames]: oh yeah, forgot about the system
(23:34:12) Bart van Heukelom.nl [2playgames]: but say i want guys, and smoke, in one system
(23:34:23) Bart van Heukelom.nl [2playgames]: that means there must be different types in one system
(23:34:27) Bart van Heukelom.nl [2playgames]: each with their own affector
(23:34:40) Bart van Heukelom.nl [2playgames]: so then there'd be some kind of subsystem
(23:34:43) Phil: Thats a ParticleList, several systems in one
(23:35:08) Phil: well the basic particle system handles one type, a particle list can handle a collaboration of systems
(23:35:25) Phil: but it also can have universal control over the emitter, or specific emitters
(23:35:55) Bart van Heukelom.nl [2playgames]: we can also have multiple particlelists inside a particlelist Smiley
(23:36:12) Phil: what would that be for?
(23:36:14) Bart van Heukelom.nl [2playgames]: although maybe we'd give it a more appropriate name?
(23:36:18) Phil: yeah..
(23:36:23) Bart van Heukelom.nl [2playgames]: for positioning
(23:36:50) Bart van Heukelom.nl [2playgames]: i see each system (and supersystem) having a position and rotation, from which it's children are related
(23:36:57) Phil: ok so several fire effects (smoke, sparks, fire) all over some object on fire? that kind of idea
(23:37:07) Bart van Heukelom.nl [2playgames]: yeah
(23:37:23) Bart van Heukelom.nl [2playgames]: and then you can rotate one system, but keep the other still
(23:37:28) Phil: yeah
(23:37:33) Bart van Heukelom.nl [2playgames]: and everything in the rotated system rotates as well
(23:37:39) Phil: yeah makes sense
(23:38:17) Phil: so its just a tree of systems where if the root is rotated or moved all its children move. If the children move by themselves, only their children move if they have any
(23:38:23) Bart van Heukelom.nl [2playgames]: we'll have to see if we want to keep a particle system and particle super system, or integrate them
(23:38:28) Bart van Heukelom.nl [2playgames]: yeah, a tree
(23:40:29) Phil: So a particle system could implement something like "ParticleNode" that keeps track of its angle, location, and scaling. And a ParticleList has a list of ParticleNodes and itself is also a ParticleNode
(23:41:00) Phil: or "SystemNode", which ever one suits
(23:41:57) Bart van Heukelom.nl [2playgames]: yeah, something like that
(23:42:05) Phil: gotcha
(23:42:27) Phil: now doing this with a Graphics2D object will be easy due to transformations
(23:42:42) Bart van Heukelom.nl [2playgames]: the engine has it's own graphics layer
(23:42:52) Bart van Heukelom.nl [2playgames]: but it support transform very much like java2d
(23:43:00) Phil: oh ok
(23:43:17) Bart van Heukelom.nl [2playgames]: and there's in fact only a java2d implementation atm
(23:43:25) Phil: Yeah in mine I have a "GraphicsLibrary" which has every function that something needs to draw.
(23:43:25) Bart van Heukelom.nl [2playgames]: anyway, there's this classmate of mine who'd maybe like to help
(23:43:38) Bart van Heukelom.nl [2playgames]: he's been working with emitters in the unreal engine, might have some experience tips
(23:43:47) Phil: Yeah
Logged




2playgames
OpenWar Project Founder
Administrator
Sr. Member
***
Offline Offline

Posts: 857


Busy busy busy busy busy


View Profile WWW
« Reply #1 on: May 14, 2008, 08:41:37 pm »

I've started implementing this, although I'm running into some things.

Currently I have a class ParticleSystem. This contains Particles, Emitters and other particle systems. However, I'm not sure how to exactly implement the emitter:

- Make it quite generic, allowing implementation that use multiple types, do or do not use a volume and launcher, etc. However, where then to put the Affector?
- Make it specific, only allow one type of particle to be spawned. Put the Affector in the system and let it affect all particles in the system.

What to do?
Logged




Phil
Guest
« Reply #2 on: May 15, 2008, 03:03:51 am »

Heres the basic abstract Structure of my implementation of the above ideas.

Code:
public interface IParticle {
    public void draw();
    public void update(float deltatime):

    public float getX();
    public float getY();
    public float getInitialAngle();   
    public float getVelocityX();   
    public float getVelocityY();   
    public float getLifeTime();
    public float getLife();
    public boolean isDead();
    public boolean isCustomDraw();
   
    public void setLifeTime(float lifetime);
    public void setX(float x);
    public void setY(float y);
    public void setInitialAngle(float angle);
    public void setVelocityX(float x);
    public void setVelocityY(float y);
}
public interface IEmitterVolume {
    void initialVolume(IParticle p);
}
public interface IEmitterVelocity {
    void initialVelocity(IParticle p);
}
public interface IEmitterAffector {
    void affectParticle(Iterator<? extends IParticle> particles, float deltatime);
}
public interface ISystemNode {
    public String getName();
    public void draw();
    public void update(float deltatime);
    public ISystemNode getClone();

    public void initialize();   
    public void setLocation(float x, float y);   
    public void setLocation(Vector location);
    public void setEmitterOffset(float x, float y);   
    public void setEmitterOffset(Vector offset);   
    public void setEmitterScale(float x, float y);   
    public void setEmitterScale(Vector scale);   
    public void setEmitterAngle(float angle);
       
    public void addEmitterOffset(float x, float y);   
    public void addEmitterAngle(float angle);   
    public void addEmitterScale(float x, float y);
   
    public Vector getLocation();   
    public Vector getEmitterOffset();   
    public Vector getEmitterScale();   
    public float getEmitterAngle();   
}

public abstract class ParticleSystem<T extends IParticle> implements ISystemNode {

    protected IEmitterVolume volume = null;
    protected IEmitterVelocity velocity = null;
    protected LinkedList<IEmitterAffector> affectors = null;

    protected float emitterAngle = 0f;
    protected Vector emitterScale = Vector.one();
    protected Vector emitterOffset = Vector.zero();

    private boolean alive = false;
    private boolean visible = true;

    protected Class<T> particleType;
    protected boolean enabled = false;
    protected String name = null;
    protected Vector location = Vector.zero();
   
    protected ParticleSystem(Class<T> particleType)
    {
this.particleType = particleType;
this.volume = new VolumeDefault();   //A self created class that sets the particles velocity to 0
this.velocity = new VelocityDefault();  //A self-created class that sets the particles location to 0,0 (Particle system location)
this.affectors = new LinkedList<IEmitterAffector>();
    }

    public final void initialize()
    {
//Set a couple things here that initializes data that all systems share... (left out).
this.onInitialize(); //Abstract method used to initialize the sub-class's particles.
    }

   public final void draw()
    {
//Some methods should go here regarding initializing particle drawing.

        float cX = 0; //Camera X coordinate
        float cY = 0; //Camera Y coordinate

translate(location.x - cX, location.y - cY);
rotate(emitterAngle);
scale(emitterScale.x, emitterScale.y);

Iterator<T> particles = getIterator();
IParticle p = null;
while (iter.hasNext())
{
    p = iter.getNext();

    // Calculate the particles size, angle, alpha, red, green, and blue acording to its life

    if (p.isCustomDraw())
p.draw();
    else
g.drawParticle(p.getX(), p.getY(), size, angle, alpha, red, green, blue);
}

        this.onDraw(g); //Abstract method for custom drawing on top of the system.
    }

    public final void update(float deltatime)
    {
//There was alot of code in here in regards to particle system creation delay, and particle system life span.
this.onUpdate(deltatime); //Abstract method for custom updating.
        affectParticles(deltatime);
    }

    protected abstract void onInitialize();
    protected abstract void onDraw(GraphicsLibrary g);
    protected abstract void onUpdate(float deltatime);
   
    protected abstract Iterator<T> getIterator();
   
    public abstract int getParticlesAlive();
    public abstract void dispose();

    protected final void affectParticles(float deltatime)
    {
Iterator<T> particles = getIterator();
Iterator<IEmitterAffector> affectors = affectors.getIterator();
while (affectors.hasNext())
{
    affectors.getNext().affectParticle(particles, deltatime);
    particles.reset(); // Resets the particle Iterator back to the beginning
}
    }

    // Returns a new particle with its velocity and location
    protected final T newParticle()
    {
T p = null;
try
{
    p = particleType.getConstructor(new Class[] {}).newInstance(new Object[] {});
}
catch (Exception e)
{
    e.printStackTrace();
}

if (p == null)
    return null;

p.setLifeTime(/** Some random number between a min and a max */);

volume.initialVolume(p);
velocity.initialVelocity(p);

p.setX(p.getX() + emitterOffset.x);
p.setY(p.getY() + emitterOffset.y);

return p;
    }
 

    // The getter, setter methods.. as well as addAffector.. etc etc
}

This is very abstract and many things in the ParticleSystem class I left out for you to fill in according to your ideas.

Couple notes..

The Iterator is a custom interface that includes an extra function "reset" to save time creating one for each affector because each affector goes through each one.
Logged
Phil
Guest
« Reply #3 on: May 15, 2008, 03:26:22 am »

O yeah heres the 'SystemNodeList'

Code:
package engine.effects;

import engine.Camera;
import engine.GraphicsLibrary;
import engine.util.Iterator;
import engine.util.NameLinkedList;
import engine.util.Vector;

public class SystemNodeList implements ISystemNode
{

    private boolean enabled = true;
    private boolean visible = true;
    private float angle = 0f;
    private Vector scale = Vector.one();
    private Vector offset = Vector.zero();
    private Vector location = Vector.zero();
    private String name = null;
    private LinkedList<ISystemNode> nodes = null;
   
    public SystemNodeList(String name) {
this.name = name;
this.nodes = new LinkedList<ISystemNode>();
    }
    public void initialize() {
Iterator<ISystemNode> i = nodes.getIterator();
while (i.hasNext())
    i.getNext().initialize();
    }
    public void update(float deltatime) {
if (!enabled)
    return;
Iterator<ISystemNode> i = nodes.getIterator();
while (i.hasNext())
    i.getNext().update(deltatime);
    }
   
    public void draw() {
if (!visible)
    return;

        float cX = 0; //Camera X coordinate
        float cY = 0; //Camera Y coordinate

translate(location.x - cX, location.y - cY);
rotate(emitterAngle);
scale(emitterScale.x, emitterScale.y);

Iterator<ISystemNode> i = nodes.getIterator();
while (i.hasNext())
    i.getNext().draw();
    }
    public void addNode(ISystemNode node) {
nodes.add(node);
    }
    public ISystemNode removeNode(String name) {
return nodes.remove(name);
    }
    public ISystemNode getNode(String name) {
return nodes.remove(name);
    }
    public void setEmitterAngle(float angle) {
this.angle = angle;
    }
    public void setEmitterOffset(float x, float y) {
this.offset.set(x, y);
    }
    public void setEmitterOffset(Vector offset) {
this.offset = offset;
    }
    public void setEmitterScale(float x, float y) {
this.scale.set(x, y);
    }
    public void setEmitterScale(Vector scale) {
this.scale = scale;
    }
    public void setLocation(float x, float y) {
this.location.set(x, y);
    }
    public void setLocation(Vector location) {
this.location = location;
    }
    public void setVisible(boolean visible) {
this.visible = visible;
    }
    public void addEmitterAngle(float angle) {
this.angle += angle;
    }
    public void addEmitterOffset(float x, float y) {
this.offset.add(x, y);
    }
    public void addEmitterScale(float x, float y) {
this.scale.add(x, y);
    }
    public float getEmitterAngle() {
return angle;
    }
    public Vector getEmitterOffset() {
return offset;
    }
    public Vector getEmitterScale() {
return scale;
    }
    public Vector getLocation() {
return location;
    }
    public String getName() {
return name;
    }
    public LinkedList<ISystemNode> getNodeList() {
return nodes;
    }
    public boolean isVisible() {
return visible;
    }
    public boolean isEnabled() {
return enabled;
    }
    public SystemNodeList getClone()
    {
SystemNodeList clone = new SystemNodeList(_name + ".clone");
clone.angle = angle;
clone.enabled = enabled;
clone.location = location.getClone();
clone.nodes = nodes.getClone(); //Gets a complete non-referenced clone of every system.
clone.offset = offset.getClone();
clone.scale = scale.getClone();
clone.visible = visible;
return clone;
    }
   
}


I thought I would be nice and post 95% of this classes code :-P

Theres alot of things you need to do yourself like all the clone implementations as well as a couple LinkedList things... you can have and change this however you want!
Logged
2playgames
OpenWar Project Founder
Administrator
Sr. Member
***
Offline Offline

Posts: 857


Busy busy busy busy busy


View Profile WWW
« Reply #4 on: May 15, 2008, 09:04:33 am »

Thinking it through some more, I've got a bunch of different ideas now (implementation-wise, the concept remains the same). I'll type them out later today (working school now).
Logged





Pages: 1
  Send this topic  |  Print  
 

Jump to: