Is it possible to start a particle effect mid way through? I have tried many variations of updating the particle effect/emitters upon initialisation. None of them seem to work. Has anyone managed to do this before? Thanks a lot!
ParticleEffectPool.PooledEffect effect = particleEffectPool.obtain();
effect.setPosition(posnX,posnY);
float value = 1.5f;
for(ParticleEmitter e: effect.getEmitters()){
e.update(value);
value+=1.5f;
}
The above code doesn't draw all of the particles, but it does seem to update the them somewhat. Once the initial effect is over, it resets and then it looks fine
EDIT: I've found a little bit of a hack by doing the following code snippet 5 times upon initialisation of the particle effect. Still interested to see if someone has a better solution
p.getEmitters().get(0).addParticle();
p.update(1);
I assume, that all emitters in your ParticleEffect have the same duration:
ParticleEffectPool.PooledEffect effect = particleEffectPool.obtain();
effect.reset();
effect.setPosition(posnX,posnY);
//divide by 1000 to convert from ms to seconds
float effectDuration = effect.getEmitters().first().duration / 1000f;
float skipProgress = 0.5f;
effect.update(skipProgress * effectDuration);
Note, that if emitters have different duration, you probably would want to pick the max duration. Also, if your emitters have delays, you should take them into account too.
Update
This approach will not work as expected in case, when some of effect's properties change over time. So if you skip half of its duration, you don't take in account all changes that happened before. You just start from some state.
For example, let's say effect has duration = 10, and its velocity is 100 for the first 4 seconds, and after that velocity is 0. If you call effect.update(5), i.e. just skip first 5 seconds, particles will have velocity = 0, they just won't "know", that they had to move for the first 4 seconds.
So, I guess the only workaround here, is to update the effect with small steps in a loop, instead of just updating for half of its duration in one call:
ParticleEffectPool.PooledEffect effect = particleEffectPool.obtain();
effect.reset();
effect.setPosition(posnX,posnY);
//divide by 1000 to convert from ms to seconds
float skipDuration = 0.5f * effect.getEmitters().first().duration / 1000f;
//I guess, to reduce number of iterations in a loop, you can safely use
//a bit bigger stepDeltaTime, like 1 / 10f or bigger, but it depends on you effect;
//here I just use standard frame duration
final float stepDeltaTime = 1 / 60f;
while (skipDuration > 0) {
float dt = skipDuration < stepDeltaTime ? skipDuration : stepDeltaTime;
effect.update(dt);
skipDuration -= stepDeltaTime;
}
Related
I'm having some trouble with an FPS algorithm I have tried to implement into my simulator. The general idea is that I want 60 to be the maximum amount of tick-render cycles per second. Here is my code:
public void run() {
x = 0; //tick is set to 0 originally
lastT = System.currentTimeMillis(); //system time in milliseconds
//tick-render cycle
while(running == true){
currentT = System.currentTimeMillis();
deltaT += currentT - lastT;
lastT = currentT;
if(deltaT/tPerTick >= 1){
tick();
render();
deltaT = 0;
}
}
stop(); //stops thread when running =! true
}
The constant 'tPerTick' is defined as follows
double tPerTick = 1000 / 60
Throughout my development of this program I thought that this algorithm was working perfectly, it was only when I traced this algorithm to confirm that I found an issue. Every time the loop cycles (iterates? I'm not sure what the correct word is here) the if statement is found to be true and therefore the tick-render cycle is executed. I did some more tracing (to find why this was happening) and found that the values for deltaT are always well over tPerTick, like way way over (in some cases 19 seconds even though this is clearly not the case). Is there an error somewhere in my code? I think that I must be either using System.currentTimeMillis() wrong or am tracing the algorithm incorrectly.
In the actual simulation it seems to be working fine (not sure why). When I draw the graphics I pass 'x' (the tick) in and write the time to the screen as x / 60 seconds.
Answering my own question.
System.currentTimeMillis();
Gets the current system time. If you are going through the algorithm manually in debug mode, 'deltaT' is going to be very large since it will be equal to the time that you take to manually trace through the algorithm.
I am writing a timeline for text:
Usage:
Text text = new Text();
......
group.getChildren().addAll(text);
root.getChildren().addAll(group);
tl.play();
This works fine. If I want to pause and continue the animation, tl.pause(); and tl.play(); can do that.
Now, I want to make the animation restart from the beginning and I use tl.stop(); and tl.playFromStart(); But the effect of this combination is as same as the effect of tl.pause(); & tl.play();.
My question is, why does tl.playFromStart(); not work properly and how to resume animation?
How Timelines Work
A Timeline represents a period of time over which an animation is performed. The Timeline comprises of a collection of KeyFrames. Each KeyFrame
must specify a point in time on the Timeline (the Duration object you pass in)
may optionally also specify a collection of KeyValues, which
comprise WritableValues (for example, Propertys) and target
values for those WritableValues at that timepoint
may optionally specify an action to be performed, in the form of an
EventHandler<ActionEvent>
The Timeline has a currentTime property, which (of course) progresses forward as time elapses while the Timeline is playing. pause() will stop the progression of the currentTime, leaving it fixed at its current value. stop() will stop the progression of the currentTime and sets the currentTime back to zero.
If the Timeline has KeyFrames that specify KeyValues, then as the currentTime changes, the WritableValues specified in the KeyValues will be set to values depending on the currentTime. (Specifically, if the WritableValues are interpolatable, the value will be interpolated between two adjacent KeyFrames specifying KeyValues for that WritableValue. Otherwise the value will just be set to the "most recent" KeyFrame specifying a value for that WritableValue.)
If the Timeline has KeyFrames that specify actions (EventHandler<ActionEvent>s), then as the currentTime progresses past the time specified by that KeyFrame, the action is invoked.
Why your code doesn't work with stop() or playFromStart()
In your case, your KeyFrame specifies an action, which adds new transforms to the node's list of transforms. Note that this does not depend on the currentTime at all, except that every time the currentTime reaches 0.04 seconds, a new transform is added (plus, whatever method shiftAndScale whose implementation you didn't show does). Thus if you stop() the timeline, the currentTime gets reset to zero, but nothing happens to the node because of this. (Indeed, the currentTime only varies between 0 and 0.04 seconds anyway.)
Other problems with your code
There is a problem with your code, in that you have a memory leak. A Node maintains an ObservableList of Transforms. You are adding to this list (quite frequently), but never removing anything. The Node is quite intelligent: it keeps a hidden matrix which is the net effect of all the transforms; when you add a new transform it stores it in the list and then updates the "net" matrix with a simple matrix multiplication. Hence you won't see any computational performance problems here: it scales fine from that perspective. However, it does store all the individual transforms (because, for example, it supports removing them later), and so if you let this run long enough you will eventually run out of memory.
The one other (maybe minor) issue with your code is that you are doing a lot of floating point arithmetic when you combine all these transforms. Any rounding errors will eventually accumulate. You should try to find a technique that avoids accumulation of rounding errors.
Ways to fix your code
To fix this, you have a couple of options:
If the animation is "naturally cyclical" (meaning it returns to its starting state after some fixed time, like a rotation), then just define the Timeline in terms of that natural duration. Using just your rotation as a simple example, you could do:
double secondsPerCompleteCycle = (360.0 / 0.75) * 0.04 ;
Rotate rotation = new Rotate(0, new Point3D(1, 0, 0));
group.getTransforms().add(rotation);
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(secondsPerCompleteCycle),
new KeyValue(rotation.angleProperty(), 360, Interpolator.LINEAR)));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
Now timeline.stop() will set the currentTime to zero, which will have the effect of setting the angle of the rotation back to its initial value (also zero).
If the animation is not naturally repetitive, I would use a (integer type) counter to keep track of the "current frame" in whatever time units you choose, and then bind values of the transform to the counter. Using the same example, you could do
double degreesPerFrame = 0.75 ;
LongProperty frameCount = new SimpleLongProperty();
Rotate rotation = new Rotate(0, new Point3D(1, 0, 0));
group.getTransforms().add(rotation);
rotation.angleProperty().bind(frameCount.multiply(degreesPerFrame));
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(0.04), e ->
frameCount.set(frameCount.get() + 1)));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
// to reset to the beginning:
timeline.stop();
frameCount.set(0L);
You could also consider using an AnimationTimer, depending on your exact requirements. I would try one of these techniques first, though.
In your case the algebra gets quite complex (prohibitively complex, for me at any rate). Each action adds three transforms to the node; a translation, a scale, and a rotation about the x-axis. The 4x4 matrix representations of these are:
1 0 0 tx
0 1 0 ty
0 0 1 0
0 0 0 1
for the translation,
sx 0 0 0
0 sy 0 0
0 0 1 0
0 0 0 1
for the scale, and
1 0 0 0
0 cos(t) -sin(t) 0
0 sin(t) cos(t) 0
0 0 0 1
for the rotation.
While it's not too hard to compute the net effect of these three (just multiply them together), computing the net matrix you get from applying these an arbitrary number of times is beyond me (perhaps...). Additionally, the amount you are translating in the x direction is changing, which makes it pretty much impossible.
So the other way to approach this is to define a single transform and apply it to the node, then modify it on each event. This would look like
Affine transform = new Affine() ; // creates identity transform
node.getTransforms().add(transform);
Timeline timeline = new Timeline(Duration.seconds(0.04), event -> {
double shiftX = ... ;
double shiftY = ... ;
double scaleX = ... ;
double scaleY = ... ;
double angle = 0.75 ;
Affine change = new Affine();
change.append(new Translate(shiftX, shiftY));
change.append(new Scale(scaleX, scaleY));
change.append(new Rotate(angle, new Point3D(1, 0, 0)));
transform.append(change);
});
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
As described above, stop() and pause() will have (almost) the same effect. (The only difference is the time to the first new update when you play again, for stop() it will be 0.04 seconds, for pause() it will be less - whatever remained until the next update when it was paused.) But to "reset" the animation, you just do
timeline.stop();
transform.setToIdentity(); // resets to beginning
Note that by using this technique, the node only has one transform applied to it; we just update that transform as we progress. Rounding errors still accumulate, but at least the algebra is viable :).
I have in my android app a code snippet that uses a loop for making/drawing rectangles.
int total_rect = 2000;//This nr should not have to be here.
float rect_positions[][] = new float[total_rect][2];
for(int i =0;i<total_rect;i++){
rect_positions[i][0] = 600 + i*300 ;
rect_positions[i][1] = rand.nextFloat() * 0.8f + 0.1f;
}
They appear every 300 DP when the game scrolls.
The reason is that i wanted it to be endless of rectangles so i dont want to set a specific nr to it.
But i have(?) to make an initial nr to run the loop. (not really sure about this...)
So what i want to know is:
Is there any other(better) way to do this because now i get REALLY low fps and it is lagging like h3ll due to all the calculations for the loop.
Maybe something in the lines of :
int total_rect = 5;
when i>4 run loop again //This is what i dont know how to code...
That should work i think.
Or maybe something like
when rect_positions>last_rectposition + 1500 run loop again //This is the one i think would be the best alternative because that would meen that the further you get the more loops it will be.
Or is it anyone that have a different idea?
I am using this code structure below from here http://www.koonsolo.com/news/dewitters-gameloop/
to set a game loop that processes based on a set fps but renders/draws at the most possible.
How would one implement a cap on the drawing fps so as not to use up all the processing power /battery life. or to limit it for v-syncing.
const int TICKS_PER_SECOND = 60;
const int SKIP_TICKS = 1000000000 / TICKS_PER_SECOND;
const int MAX_FRAMESKIP = 5;
DWORD next_game_tick = GetTickCount();
int loops;
float interpolation;
bool game_is_running = true;
while( game_is_running ) {
loops = 0;
while( GetTickCount() > next_game_tick && loops < MAX_FRAMESKIP) {
update_game();
next_game_tick += SKIP_TICKS;
loops++;
}
interpolation = float( GetTickCount() + SKIP_TICKS - next_game_tick )
/ float( SKIP_TICKS );
display_game( interpolation );
}
I assume that you are actually doing proper motion interpolation? Otherwise it doesn't make sense to render faster than your game update: you'll just be rendering all the objects again in exactly the same position.
I'd suggest the following:
Put a Thread.sleep(millis) call in to stop the busy-looping. Probably a Thread.sleep(5) is fine, since you are just going to do a quick check for whether you are ready for the next update.
Put a conditional test on the display_game call to see if at least a certain number of millisconds has elapsed since the last display_game. For example, if you make this 10ms then your frame rate will be limited to 100 FPs.
There are also a couple of other things that are a bit unclear in your code:
What is DWORD? Is this really Java? Looks like some funny C/C++ conversion? The normal way to get the current time in Java would be long time=System.nanoTime() or similar.....
What graphics framework are you using? If it is Swing, then you need to be careful about what thread you are running on, as you don't want to be blocking the GUI thread....
Finally, you should also consider whether you want to decouple your update loop from the rendering code and have them running on different threads. This is trickier to get right since you may need to lock or take snapshots of certain objects to ensure they don't change while you are rendering them, but it will help your performance and scalability on multi-core machines (which is most of them nowadays!)
I think you can update your display_game to compare the FPS being painted against the desired limit. If it has reach that limit, you can add a wait time for wait time as:
Thread.sleep(500); //wait for 500 milliseconds
In short, I'm trying to make a bar (using GWT's wrapper for HTML5 canvas) that will show something reasonable for a given value, no matter what the value of the bottom and top of the chart actually are. I'm assuming the best approach is logarithmic, but I'm completely open to any other solution.
Assumptions:
Our "bar" vertical, measuring 200 pixels high, 35 pixels wide.
We're showing a "site" versus it's parent "region". The units are ones of power (e.g. kW, MW, GW).
The "region" has a range of 1 kW to 55.19 GW. The average value is 27.6 MW.
Approximately 95% of sites within the region are much closer to 1 W than 55 GW, but the top 5% skew the average significantly.
The first site has a value of 12.67 MW. The second site has a value of 192.21 kW.
Obviously the second site wouldn't even register on a linear graph, while the first would register very low.
How can I make this bar more useful? For example, I'd like the top 5% of sites that skew the region's average to represent only a small portion (5%) of the total bar, while the other 95% should represent 95%.
The line in the lower area of the bar is the region average line, while the entire bar represents Minimum (bottom) to Maximum (top).
Current Java code using log10:
// BAR_GRAPH_WIDTH = 36, BAR_GRAPH_HEIGHT = 200
// regionNsp (MW): [min=0.0, max=55192.8, avg=27596.5]
// siteNsp (MW) = 187.18
DrawingArea canvas = new DrawingArea(BAR_GRAPH_WIDTH, BAR_GRAPH_HEIGHT);
Rectangle bgRect = new Rectangle(1, 0, BAR_GRAPH_WIDTH - 1, BAR_GRAPH_HEIGHT); // backgound bar
bgRect.setFillColor("white");
canvas.add(bgRect);
int graphSize = (int)(BAR_GRAPH_HEIGHT / Math.log10(regionNsp.getMax()));
int siteHeight = (int)Math.log10(siteNsp - regionNsp.getMin()) * graphSize;
Rectangle valueRect = new Rectangle(1, BAR_GRAPH_HEIGHT-siteHeight, 35, siteHeight);
valueRect.setFillColor("lightgreen");
canvas.add(valueRect);
Consider logarithmic scale with a break for extremely high values that are far beyond any others in the population. For an example of a break in the bars and axis, see: http://tomhopper.files.wordpress.com/2010/08/bar-chart-natural-axis-split1.png
I admit that I don't know much about GWT, so I'm answering on the basis of how would I show your values on a paper-and-pencil graph. That answer is that you've answered your own question - use logs. The range from 1000 to 55200000000 with an average around 27600000, after taking (common base 10) logs, becomes about 3 to 11, with the average around 7.4.
The caveat is that what you gain in "reasonableness" you do loose in perspective. Take the decibel scale, which is (common base 10) log based. The difference between an 80 decibel sound and an 85 decibel sound doesn't seem like a big change, except that the second is three times more energetic.