I've been trying to make some fire particle emitter with libGDX.
I downloaded an example (http://pastebin.com/cNWs0tt1#). It looks fine, but it eventually ends (the fire extinguishes) and then starts over. I see in the file that is says the duration is 60000ms. So they relied on putting a high number.
Well, that's lame. I tried putting a duration of 0, which of course doesn't work as it just keeps on dying over and over.
So how can I make a particle emitter with unlimited duration?
You can set the continous-flag to true, the effect will start over and over again.
In the editor:
Or in the source-file:
- Options -
attached: false
continuous: true <----------------------------
aligned: false
additive: true
behind: false
I found a simple workaround for what you are trying to accomplish.
effect.findEmitter("youremitter").durationTimer = 0;
If you call this each time the effect is being rendered, you can reset each emitter to it's starting duration timer. I have tested it and it seems to work very nicely.
Do note however that you need to call this line for each one of your emitters. For example, if you have a rocket ship with a flame/smoke particle effect, you should do this.
public void render(float delta) {
effect.findEmitter("fire").durationTimer = 0;
effect.findEmitter("smoke").durationTimer = 0;
// Render your particle effect here
}
I hope this helps, good luck!
Related
Let me set the stage because it's too much code to post everything:
I have a Main.as that is setting up my SoundController.as so I can trigger sounds from any other class (SoundController.as has all the functions needed to call all my sounds as needed)
I have a ControlPanel.as that can access these sounds by using docRef.soundControl.laserFire or whatever other function name I want, and in this case the laserFire sound would trigger once.
So here is my question. I want to let this laser sound effect finish playing before you can fire another laser. So in SoundController.as I've set up the following pieces of code:
private var _laserPlaying:Boolean = false;
internal function laserFire():void {
_sfxChannel = _laser.play(25);
_laserPlaying=true;
_sfxChannel.addEventListener(Event.SOUND_COMPLETE, laserFinished);
}
internal function laserFinished(event:Event):void {
_sfxChannel.removeEventListener(Event.SOUND_COMPLETE, laserFinished);
_laserPlaying=false;
}
public function get laserPlaying():Boolean {
return _laserPlaying;
}
public function set laserPlaying(value:Boolean):void {
_laserPlaying = value;
}
Now in my ControlPanel class in the enterFrameHandler function I want to do an
if (docRef.soundControl.laserPlaying()==false)
or something to that effect so I can check when the sound is done and allow the player to once again press the trigger to fire the laser. So far any variant I've tried on this either gives me an error (in this case 1195; Attempted access of inaccessible method laserPlaying through a reference with static type SoundController) or it actually compiles but after firing the first laser shot it never allows the trigger to be pressed again. So I'm obviously doing something wrong and am hoping someone can help.
Let me just state that the laser sound is playing just fine that first time, so don't worry about all the code I'm not bothering to show to make that portion of the code work. However, if more info is needed to understand how I'm making anything work just let me know. And Thanks in advance!
If your soundController AND ControlPanel are instantiated in Main:
handle the firing event, in ControlPanel, like this:
if(MovieClip(parent).soundController.soundChannel.position==0)
{
MovieClip(parent).soundController.laserfire();
}else{do nothing;}
Of course use proper instance names.
If this doesn't work you'll have to make your code a little easier to understand.
Sorry for wasting everyone's time. I ended up figuring out what I needed to do to make this work. This probably won't be of much use to anyone else since my setup was probably unique to my layout and not something that anyone else will try, but here is what I did anyway.
In my ControlPanel.as I added the following code:
private var _soundController:SoundController;
And then I have a function that waits for the ControlPanel to be added to the stage and once that occurs I fired:
_soundController = new SoundController(docRef);
Now by adding those I was able to simply call:
if(!_soundController.laserPlaying) { do stuff; }
It now seems to wait for laserPlaying to be false and then moves on as intended.
I'm surprised I don't know how to do this, but as it turns out I really don't; simply put, I'm trying to make a side-scrolling shooter game, a basic one and in it, I have 50 stars spawned on-screen through a "for" loop upon the game starting. There is a function which does this and a listener is at the beginning. Problem is, when you lose the game and go back to main menu, 50 more stars would be spawned, which isn't what I want. So, I'm trying to make an "if" statement check at the beginning, so that the game checks whether there is an instance/movie clip of the star object/symbol before determining whether the function that spawns stars should be called out with a listener. So, how do I do this? I looked through some other checks and they didn't help as the codes presented were vastly different there and so I'm just getting errors.
Let me know if a better explanation is needed or if you would like to see some of the code. Note that the game overall already has a lot of code, so just giving all of it would probably not be helpful.
I suggest you rethink your approach. You're focusing on whether stars have been instantiated. That's ok but not the most basic way to think about it.
I would do this instead
private function setup():void{
loadLevel(1);
addListeners();
loadMusic();
// etc...
// call all functions that are needed to just get the app up and running
}
private function loadLevel(lev:int):void{
addStars();
// call all functions that are needed each time a new level is loaded
}
private function restartLevel():void{
// logic for restarting level,
// but this *won't* include adding star
// because they are already added
}
There are other ways to do this but this makes more sense to me than your approach. I always break my game functions into smaller bits of logic so they can be reused more easily. Your main workhorse functions should (IMHO) primarily (if not exclusively) just call other functions. Then those functions do the work. By doing it this way, you can make a function like resetLevel by assembling all the smaller functions that apply, while excluding the part about adding stars.
Here's what I did to solve my problem... Here's what I had before:
function startGame():void
{
starsSpawn();
//other code here
}
This is what I changed it to:
starsSpawn();
function startGame():void
{
//other code here
}
when you said existance, so there is a container, i named this container, (which contain stars , and stars was added to it) as starsRoot, which absolutely is a DisplayObject (right?)
now, to checking whole childrens of a DisplayObject, we have to do this :
for (var i:int=0; i<starsRoot.numChildren; i++) {
var child = starsRoot.getChildAt[i];
}
then, how to check if that child is really star!?
as you said
whether there is an instance/movie clip of the star
so your stars's type is MovieClip, and they don't have any identifier (name), so how to find them and make them clear from other existing movieclips. my suggestion :
define a Linkage name for stars from library, thats a Class name and should be started with a capital letter, for example Stars
now, back to the code, this time we can check if child is an instance of Stars
for (var i:int=0; i<starsRoot.numChildren; i++) {
var child = starsRoot.getChildAt[i];
if (child is Stars) {
// test passed, star exist
break;
}
}
I'm creating a game that uses the starling-layer (the game itself) and the classic display list which contains several Popups and Stuff like that.
I have one thing that troubles me:
If MouseEvents are generated on displayList-elements they always go through to the starling layer and produce TouchEvents etc. which is quite annoying.
I was wondering there is some general (and easy to use) approach to handle that.
One possibility was to listen on all displayList-Elements for the following Events:
interfaceElement.addEventListener(MouseEvent.MOUSE_MOVE, stopPropagationHandler);
interfaceElement.addEventListener(MouseEvent.MOUSE_DOWN, stopPropagationHandler);
interfaceElement.addEventListener(MouseEvent.MOUSE_UP, stopPropagationHandler);
private function stopPropagationHandler(e:MouseEvent):void {
e.stopPropagation();
}
But this looks quite nasty to me.
And even if I did it like that, I have one more issue:
If a starling-element is below that display-list-element and if it has a TouchEvent.TOUCH for rollover-behavior >> the rollover-appearance will not be removed from the starling if you hover over the display-list-element.
I also thought about putting a dummy-starling element behind every display-list-element,... to stop the events.. but that all sounds a bit "over-complicated" for such a "simple" task.
Or am I missing something?
A hint would be much appreciated.
Thanks.
You could create 1 main container in the displaylist (not the stage) and listen for ROLL_OVER and ROLL_OUT, and set somekind of global flag there, that your mouse is over the display-list container. Then in your starling events, check for this flag. This isn't the nicest solution out there i guess, but it should work
var isOverDisplayList:Boolean = false;
container.addEventListener(MouseEvent.ROLL_OVER, onRollOver);
container.addEventListener(MouseEvent.ROLL_OUT, onRollOut);
function onRollOver(e:MouseEvent) {
isOverDisplayList = true;
}
function onRollOut(e:MouseEvent) {
isOverDisplayList = false;
}
Easy one for you guys but new to me. I have an animated walking character called mcPlayer. Inside of it's timeline I have frame labels at various animated states "walkingLeft","walkingRight" and "Idle". The walking animations are of him walking in one spot. I want to be able to use buttons to move the character with actionscript to various targets on the stage and have the corresponding animation play as it moves.So the most direct way I could think to do it is like this...
import com.greensock.*;
btnRight.addEventListener(MouseEvent.CLICK, moveRight);
btnLeft.addEventListener(MouseEvent.CLICK, moveLeft);
function moveRight(Evt:MouseEvent):void{
TweenLite.to(mcPlayer,2,{x:450});
mcPlayer.gotoAndPlay("walkingRight");
}
function moveLeft(Evt:MouseEvent):void{
TweenLite.to(mcPlayer,2,{x:450});
mcPlayer.gotoAndPlay("walkingLeft");
}
I have tried different commands on the mcPlayer timeline,like, putting a stop(); at the beginning of each anima. I have tried putting a gotoandplay(); at the end of each anima so it will go to the beginning and loop.I would like to use the timeline as little as possible.
How do I...
1. Have the animation play continuously while the tween is in motion
2. Have the animation stop when it has reached its destination
and finally have the anima"idle" play after mcPLayer has reached its target.
To loop an animation you would test for the last frame of the animation and then loop back, you can do that within a tween with the onUpdate parameter and use onUpdateParams to pass any data needed for the update. Such as the animation label and the last frame of the animation.
If you want to do something after a tween is completed, such as change to the idle animation, you'd use the onComplete parameter.
Here's an example of what you might do :
btnRight.addEventListener(MouseEvent.CLICK, moveRight);
btnLeft.addEventListener(MouseEvent.CLICK, moveLeft);
function moveRight(Evt:MouseEvent):void{
// lastframe should be replaced with whatever the frame the walk right animation ends on.
TweenLite.to(mcPlayer, 2, {x:450, onUpdate:updateHandler, onUpdateParams:['walkingRight', lastFrame], onComplete:idleHandler);
mcPlayer.gotoAndPlay("walkingRight");
}
function moveLeft(Evt:MouseEvent):void{
// lastframe should be replaced with whatever the frame the walk left animation ends on.
TweenLite.to(mcPlayer, 2, {x:10, onUpdate:updateHandler, onUpdateParams:['walkingLeft', lastFrame], onComplete:idleHandler);
mcPlayer.gotoAndPlay("walkingLeft");
}
function updateHandler(loopLabel:String, lastFrame:int):void
{
if (mcPlayer.currentFrame == lastFrame)
{
mcPlayer.gotoAndPlay(loopLabel);
}
}
function idleHandler():void
{
mcPlayer.gotoAndPlay("idle");
// this is also where you'd do anything else you need to do when it stops.
}
I am not sure how you have your content set up, I was just guessing that you had all the animations on the timeline of the mcPlayer with labels for each animation based on what you had said.
Depending how your content is set up, you might need to implement differently. But the concepts are still the same - using onComplete and onUpdate to handle things for those particular events.
I have been working on this one a while. I have an object in this case a movieClip called "mcBall". I set up two buttons "btnLeft" and "btnRight"with a tween so that the mcBall will ease between the two points smoothly.
Works fine, but where it gets glitchy is the the two buttons are still active an if the user clicks on either button of course the ball goes back to the starting point like it's supposed to.
My question is this ... What is the best way to have the buttons be de-activated while the "mcBall" object is moving. Would it be best to use a removeEventListener for the buttons and then have it added again. Would it be better to use an if statement like "If (mcBall.x = >=81 || <=469) removeEventListener"? Maybe use the tweenEvent.MOTION_FINISH to set up the eventListener again.
Any help would be greatly appreciated. Thanks
using Flash cs3
In this code I managed to turn off one button so that while the ball is moving it remains inactive but the other is still active. I'm not sure of the placement of the removeEventListener.
import fl.transitions.Tween;
import fl.transitions.easing.*;
function moveBallRight(evt:MouseEvent):void {
var moveBall:Tween=new Tween(mcBall,"x",Regular.easeOut,80,470,4,true);
btnRight.removeEventListener(MouseEvent.CLICK,moveBallRight);
btnLeft.addEventListener(MouseEvent.CLICK,moveBallLeft);
}
btnRight.addEventListener(MouseEvent.CLICK,moveBallRight);
function moveBallLeft(evt:MouseEvent) {
var moveBall:Tween=new Tween(mcBall,"x",Regular.easeOut,470,80,4,true);
btnRight.addEventListener(MouseEvent.CLICK,moveBallRight);
btnLeft.removeEventListener(MouseEvent.CLICK,moveBallLeft);
}
btnLeft.addEventListener(MouseEvent.CLICK,moveBallLeft);
Personally, I would recommend using the Actuate tween library. Unlike TweenLite/Max, it is fully opensource, and has most of the features, and is faster, with no pro/pay version.
I also like Actuate's interface much better than TweenLite. It is very similar so easy for people to start using it, but I like how tween modifiers are added in a more explicit way.
Simple example:
Actuate.tween(mySprite, 1, { alpha:1 });
Then is you want to specify an easing equation, just chain it on the end:
Actuate.tween(mySprite, 1, { alpha:1 }).ease(Quad.easeOut);
Want a delay as well? Add that to the chain:
Actuate.tween(mySprite, 1, { alpha:1 }).delay(1).ease(Quad.easeOut);
Of course you can also call a function onComplete, even with parameters:
Actuate.tween(mySprite, 1, { alpha:1 }).onComplete(trace, 'Tween finished');
Check out the Actuate Google Code page linked above for the full list of methods with examples.
I would recommend not using the native Tween class from fl.transitions.Tween. Its not very good. The industry standard is TweenMax from greensock.
Using TweenMax it is trivially easy to respond to end-of-tween events. You simply add an onComplete:myhandlerfunction to your tween.
An example from your above code would look like this:
Instead of
var moveBall:Tween=new Tween(mcBall,"x",Regular.easeOut,80,470,4,true);
You would have:
TweenMax.to(mcBall, 4, {x:470, ease:Expo.easeOut, onComplete:onBallMovedLeftComplete};
Hope that helps. And I hope you never have to use those native tween classes again. They are the pits.
I agree that you should use TweenLite or TweenMax as the other answers suggests.
From what I gather though, the question is the best approach in activating/deactivating your event listeners for the buttons.
I'd say the best approach is to have a function for adding your button listeners and another function for removing them.
Then, whenever you call a tween, you first call the removal function before executing the tween.
Then upon completion, you call the function to add them again. You can use the onComplete parameter with Tweenlite to specify the function to add the button listeners.
for example :
function moveBallRight(evt:MouseEvent):void
{
removeButtonListeners();
TweenLite.to(mcBall, 4, {x:470, ease:Expo.easeOut, onComplete:addButtonListeners};
}
function moveBallLeft(evt:MouseEvent):void
{
removeButtonListeners();
// do your tween
TweenLite.to(mcBall, 4, {x:80, ease:Expo.easeOut, onComplete:addButtonListeners};
}
function addButtonListeners():void
{
// add both listeners here
}
function removebuttonListeners():void
{
// remove both listeners here
}
Also, you'd obviously want to call addButtonListeners at the beginning of your program as well, so that the listeners are initially active when the program runs.