- jMonkeyEngine 3.0 Cookbook
- Rickard Edén
- 1323字
- 2021-09-03 10:00:48
An advanced ParticleEmitter class
Soaring birds are nice but it's easy to feel that the result of the previous recipe could have been much better if the birds were better animated. If you've worked with the ParticleEmitter
class before or have been observant of the birds, you will know that particles can actually be animated although they only cycle through every frame once per lifetime. This is much too slow for the birds.
In this recipe, we're going to look at what's needed to make the birds flap their wings. It's not as simple as it sounds and requires modifying the ParticleEmitter
code and writing our own ParticleInfluencer
class.
If we have a look at the ParticleEmitter
class to see what we need to do, we can see that there is an updateParticle
method that seems like a good place to start. This is called for every particle in each update cycle. One thing that is less obvious at first is that since we have the same ParticleInfluencer
instance affecting all particles, it also needs to be updated separately for each frame. To achieve the latter, we can use a control.
Getting ready
To be able to modify the ParticleEmitter
class, we need the source. This means we have to check it out from the repository. If you're not comfortable with this, you can still do the first part and learn more about the ParticleInfluencer
instance.
After having checked out the source code for jMonkeyEngine from the repository, it should be opened as a project in the SDK.
Build it and then change the reference in the properties for this project to use the .jar
files from the source code project instead of the supplied jMonkeyEngine.jar
files.
How to do it…
In the first section, we'll create a new ParticleInfluencer
instance. This consists of the following steps:
- The first thing we'll do is create a new class called
BirdParticleInfluencer
and have it extend theDefaultParticleInfluencer
class. Since the flat particles point in the direction they're flying, it sometimes looks weird when they have a Y-velocity. We're going to fix that by not allowing the particles to have any velocity in the y axis. We override theinfluenceParticle
method and set the Y-velocity to0
. After this we need to normalize the velocity, as shown in the following code:public void influenceParticle(Particle particle, EmitterShape emitterShape) { super.influenceParticle(particle, emitterShape); particle.velocity.setY(0); particle.velocity.normalizeLocal(); }
- We can now replace the
ParticleInfluencer
interface in theParticleEmitter
element's Property window with our own. - That was the easy part, and that's how far we get without modifying the engine. In the next section, we will extend the current
ParticleEmitter
instance to animate particles continuously. This will consist of the following steps:- Let's start by making our
ParticleInfluencer
interface ready to update the particles in every frame. Let's start by making ourParticleInfluencer
interface ready to update the particles in every frame. We're going to add two methods to it. The first one is for updating the particle, and the second one is for updating the influencer itself, as shown in the following code:public void influenceRealtime(Particle particle, float tpf); public void update(float tpf);
- In our
BirdParticleInfluencer
class, we're going to need some new fields. ThemaxImages
property keeps track of how many images there are in a cycle. TheanimationFps
property defines how fast the animation should run. These two properties should be added to the class's read/write/clone methods as well to ensure that they're saved properly. Thetime
andincreaseFrames
are runtime properties only:private int maxImages = 1; private float animationFps = 10f; private float time = 0f; private int increaseFrames;
- Now, let's go to our
update
method. This is the method that runs once every frame. We add functionality to check whether it's time to change the frame in the particle or not. The logic goes like this: when the current passed time is larger than the time between frames, increase the frame index by one. Using awhile
loop rather than anif
statement allows us to compensate for low frame rate, by skipping several frames, if necessary, to keep up with the frames per second:public void update(float tpf){ super.update(tpf); float timeBetweenFrames = 1f / animationFps; time += tpf; increaseFrames = 0; while (time > timeBetweenFrames){ increaseFrames++; time -= interval; } }
- In
influenceRealtime
, which is the method that is run once per particle and frame, all we do is tell it to increase theimageIndex
value if needed, making sure not to exceed the maximum images in the cycle:public void influenceRealtime(Particle particle, float tpf) { super.influenceRealtime(particle, tpf); if(increaseFrames > 0){ particle.imageIndex = (particle.imageIndex + increaseFrames) % maxImages; } }
- That's the influencer part. Let's make sure
influenceRealtime
is called from theParticleEmitter
class. At the end of theupdateParticle
method, add the following code:particleInfluencer.influenceRealtime(p, tpf);
- Let's start by making our
Unfortunately, we also need to comment out the following line:
//p.imageIndex = (int) (b * imagesX * imagesY);
In the last section of the recipe, we will create a control that will update the ParticleInfluencer
class. This consists of the following steps:
- We create a new class called
BirdParticleEmitterControl
and make it extendAbstractControl
. The important bit here is thecontrolUpdate
method where we in turn call theupdate
method of theParticleEmitter
instance:public void controlUpdate(float tpf){ super.update(tpf); if(spatial != null && spatial instanceof ParticleEmitter){ ((ParticleEmitter)spatial).getParticleInfluencer().update(tpf); } }
- Apart from that, we also need to add the following code for it to work properly:
public Control cloneForSpatial(Spatial spatial) { return new BirdParticleEmitterControl(); }
- To affect the birds by our changes, we need to do a few more things. First, we need to open the birds scene in the SceneComposer window.
- Selecting the Emitter element, we need to choose Add Control.. and then select Custom Control. Our newly created control should be available in the list.
- Now, we need to load the scene inside an application. We just load the scene and move it up into the sky by using the following code:
public void simpleInitApp() { Node scene = (Node) assetManager.loadModel("Scenes/ParticleTest.j3o"); scene.setLocalTranslation(0, 60, 0); rootNode.attachChild(scene); }
How it works...
Particle emitters are normally limited in what control you have over the particles. The ParticleInfluencer
class gives us some basic control during particle creation.
Since the birds are flat planes, they look best when viewed straight on. This creates a problem when we have said that they should always point in the direction they're flying if they're moving along the y axis.
The influenceParticle
method is a method implemented from the ParticleInfluencer
interface and it is called upon the creation of every new particle. Since the DefaultParticleInfluencer
instance is already applying a velocity with variation, we just needed to remove any Y-velocity.
In the ParticleEmitter
class, we commented out a line in the update
method. That's the current animation logic that will override our changes every time. A workaround would be to let the ParticleInfluencer
class keep track of the current frame, but that would make all the birds have the same frame. Another alternative would be to move it to one of the other ParticleInfluencer
classes.
By using the control pattern to update the ParticleInfluencer
class, we can offset some code and keep minimum changes in the ParticleEmitter
class.
Unfortunately, the changes we made to the ParticleEmitter
class won't be picked up by Scene Composer, as it uses its own compiled classes. So to see it, we had to start an application and load the scene there.
There's more…
The birds now continuously flap their wings like many small birds do when flying. Larger birds tend to glide more, with only an occasional flap. They also fly in straight lines.
The influenceRealtime
method we created opens up new possibilities to create better looking particles.
An additional touch would be to implement logic to have the birds both soar and flap interchangeably, and circle around a point or change their direction. Are you up for it?
- 無代碼編程:用云表搭建企業數字化管理平臺
- BeagleBone Media Center
- Blender 3D Incredible Machines
- Building Minecraft Server Modifications
- 深入理解Elasticsearch(原書第3版)
- Windows Phone 7.5:Building Location-aware Applications
- 大數據分析與應用實戰:統計機器學習之數據導向編程
- HTML+CSS+JavaScript網頁設計從入門到精通 (清華社"視頻大講堂"大系·網絡開發視頻大講堂)
- 機器學習微積分一本通(Python版)
- Xamarin Blueprints
- 高效使用Greenplum:入門、進階與數據中臺
- Instant GLEW
- C語言編程魔法書:基于C11標準
- 基于JavaScript的WebGIS開發
- VC++ 2008專題應用程序開發實例精講