I have animation with 5 frames. I want to make pause for x seconds every time one animation cycle ends
1,2,3,4,5 (pause) 1,2,3,4,5 (pause) ...
Array<AtlasRegion> regions = atlas.findRegions("coin");
animGoldCoin = new Animation(1.0f / 20.0f, regions, PlayMode.LOOP);
I can't find way to do this.
Thanks
I don't really like the animation class, you can make your own.
float pauseTime=5f; // lets say that you want to pause your animation for x seconds after each cicle
float stateTime=0f; // this variable will keep the time, is our timer
float frameTime=1/20f; //amount of time from frame to frame
int frame=0; // your frame index
boolean waiting=false; // where this is true, you wait for that x seconds to pass
void Update()
{
stateTime+=Gdx.graphics.getDeltaTime();
if(!waiting && stateTime>frameTime) // that frame time passed
{
stateTime=0f; // reset our 'timer'
frame++; // increment the frame
}
if(waiting && stateTime>=0)
{
frame=0;
waiting=false;
}
if(frame>=NUMBER_OF_FRAMES)
{
frame--;
waiting=true;
stateTime=-pauseTime;
}
}
}
I think this will work, do you understand what I did?
I just had a similar problem but managed to come up with a solution. It works well for me but may not be the best way to go about it.. I'm still learning.
I created a new animation from the old animation's frames but with a speed of 0. It stops on the frame its at until the player speed changes.
if(speedX == 0f && speedY == 0f){
playerIdle = new Animation(0f,playerAnim.getKeyFrames());
playerAnim = playerIdle;
}
I know its an old question, but hopefully this will be useful to someone.
I made a quick solution in my search to pause a Libgdx animation.
I wanted an animation to pause when I pressed the spacebar.
I did try the above method of instantiating a new object and it did work. So I tried to just set the frame duration to 0, but that didn't work for some reason. This a less expensive method w/o instantiation.
If you want to pause an animation simply create three variables two are Boolean variables named toStop and hasLaunched another is a TextureRegion named launchFrame. Haslaunched is used to tell me when the spacebar is pressed.
if (InputHandler.hasLaunched && toStop ) {
launchFrame = launchBarAnimation.getKeyFrame(runTime);
toStop = false;
} else if (InputHandler.hasLaunched && !toStop){
batcher.draw(launchFrame, 90, 20, 50, 37);
} else {
batcher.draw(launchBarAnimation.getKeyFrame(runTime), 90, 20, 50, 37);
}
Related
How would someone change sound levels of a music playing in a loop? For example, I'm making a game and at a certain frame I want the music level (music.wav) to be decreased to half of its volume.
How could someone do this in AS3?
You are using the word "loop" in a confusing way. In programming, a loop usually refers to one of the "for" loops that looks like this:
for (var i:int = 0; i < 10; i++)
{
//do stuff 10 times
}
I surmise that this is not what you mean by loop, but rather that you would like a MovieClip or the main timeline to decrease the volume of a Sound object at the end of n frames. Or do you just mean the music itself is looping? Hopefully you see the value of asking well written questions. That being said..
Mind you, I haven't tried this, but according to my reference book (ActionScript 3.0 Cookbook by Lott, Schall & Peters) you need to use a SoundTransform object which specifies the volume at which you want the sound to be set. Try this:
var _sound:Sound = new Sound(music.wav); // creates a Sound object which has no internal volume control
var channel:SoundChannel = _sound.play(); // creates a SoundChannel which has a soundTransform property
var transform:SoundTransform = new SoundTransform(); // SoundTransform objects have a property called "volume". This is what you need to change volume.
Now in your loop (or on the frame event that you are using) do this:
transform.volume *= 0.9; // or whatever factor you want to have it decrease
//transform.volume /= 1.1; // or this if you prefer.
channel.soundTransform = transform; //
So anytime you want the volume to decrease by this incremental amount, run this bit of code. Of course, you need to make sure that any variables you set are accessible in the code that is referencing them. One way that comes to mind to do this is with a function.
private function soundDiminish(st:SoundTransform, c:SoundChannel, factor:Number = 0.9):void
{
st.volume *= factor;
c.soundTransform = st;
}
Now, whenever you want to diminish the volume just call the soundDiminish function.
Maybe your frame event looks like this:
function onLoadFrame(fe:Event):void
{
soundDiminish(transform, channel); // 3rd parameter optional
}
If you only want this function to be called every 20 frames then:
function onLoadFrame(fe:Event):void
{
// this is a counter that will count up each time this frame event happens
frameCount ++;
if (frameCount >= 20)
{
soundDiminish(transform, channel); // 3rd parameter optional
frameCount = 0; // reset the frame counter
}
}
I have set of 6 movieclips as array_0 and another set of 6 movieclips as array_1. It is like two choices for different screens. Both these arrays are nested in another array as all_array. all 12 movieclips are positioned to a same x and y at initial load and that is outside the visible stage. I would like to use two different global variables for indexing. for example, cCat_Sel which ranges from 0-5 and another cScr_Sel ranges from 0-1. cCat_Sel will be changed on a click event of six buttons separate objects on stage (each button for each category).
so it will show the content for each category as per the value of cScr_Sel. if cScr_Sel is 0 then it will use all_array[0][cCat_Sel] to access the current target and similarly respective array for value of 1 as all_array[1][cCat_Sel]
I have done all the work including all tween animations to move current target and make it visible. But the tween does not bring the second set of mcs to visible area. I have two functions one for movein and one for move out by using tween animation for mc.x property. every relevant click event; I have to move current mc out and make alpha 0 and once that is finished, move in new current target and make alpha 1.
Somehow I have to combine these two tweens in one function. This is the part that I am stuck. or may be putting these mcs in two different arrays not a correct approach. I can easily achieve what I want on Enter Frame event of the root to check for cCat_Sel and cScr_Sel variables and do both animations one after the other but it seems like enter frame uses too much of cpu and makes it slower and probably not preferable.
willing to try anybody's suggestions or guidance. Thanks in advance.
I do not have any formal or informal programming education at all but I make things work by reading and trying out few things as per stackoverflow question and answers and sometime google. because most of my answers I have found from stack overflow.
Update:
function fnSlideInOut(cMc:Object, pMc:Object){
var HideX:Number =650;
var ShowX:Number = 0;
if(cMc != null){
if(cMc.x != ShowX){
//cMc.alpha = 1;
var SlideMcIn:Tween = new Tween(cMc, "x", Strong.easeOut, 650, ShowX, 0.5, true);
SlideMcIn.addEventListener(TweenEvent.MOTION_FINISH, fnSlideInFinish);
SlideMcIn.start();
}
}
if(pMc != null){
if(pMc.x != HideX){
//pMc.alpha = 1;
var SlideMcOut:Tween = new Tween(pMc, "x", Strong.easeOut, 0, HideX, 0.5, true);
SlideMcOut.addEventListener(TweenEvent.MOTION_FINISH, fnSlideOutFinish);
SlideMcOut.start();
}
}
function fnSlideOutFinish(e:TweenEvent){
//SlideMcOut.obj.alpha = 0;
SlideMcOut.removeEventListener(TweenEvent.MOTION_FINISH, fnSlideOutFinish);
}
function fnSlideInFinish(e:TweenEvent){
//SlideMcIn.obj.alpha = 1;
SlideMcIn.removeEventListener(TweenEvent.MOTION_FINISH, fnSlideInFinish);
}
}//End Function
fnSlideInOut(cScr_Sel, pScr_Sel);
I would like expert like you to comment on any kind of errors for the above code. It works 99 times but 1 time the movieclip either does not reach the destination or current and previous both targets showing and that too not where they are suppose to. This only happens when button click event happens in a quick succession. Thanks again
A option could be to use a third party library like TweenLite. It will then make it easy for you to run your second animation right after the first one is complete:
private function startAnimation():void
{
var mcToHide:MovieClip = all_array[cScr_Sel][cCat_Sel];
TweenLite.to(mcToHide, 1, {x: HIDDEN_X_POSITION, y:HIDDEN_Y_POSITION, alpha:0, onComplete:finishAnimation});
}
private function finishAnimation():void
{
var mcToShow:MovieClip = all_array[(cScr_Sel + 1) % 2][cCat_Sel];
TweenLite.to(mcToShow, 1, {x: VISIBLE_X_POSITION, y:VISIBLE_Y_POSITION, alpha:1});
}
You can then call startAnimation() on a relevant mouse click event and after having set cScr_Sel and cCat_Sel accordingly to your needs.
I am currently learning cocos2D-x and am doing some sprite animation.
My Objective is that when a button is clicked the object moves to left with some animation.
Now if you click multiple times rapidly the animation takes place immediately and it looks like the bear is hoping instead of walking.
The solution to it looks simple that I should check if animation is already running and if running the new animation should not take place.
The following is a part of my code.
CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("AnimBear.plist");
CCSpriteBatchNode* spriteBatchNode = CCSpriteBatchNode::create("AnimBear.png", 8);
this->addChild(spriteBatchNode,10);
CCArray *tempArray = new CCArray();
char buffer[15];
for (int i = 1; i <= 8 ; i++)
{
sprintf(buffer,"bear%i.png", i);
tempArray->addObject(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(buffer));
}
CCAnimation *bearWalkingAnimation = CCAnimation::create(tempArray,0.1f);
startAnimation = CCSprite::createWithSpriteFrameName("bear1.png");
startAnimation->setPosition(ccp (350 , CCDirector::sharedDirector()->getWinSize().height/2 -100));
startAnimation->setScale(0.5f);
startAnimation->setTag(5);
//Animation for bear walking
bearAnimate = CCAnimate::create(bearWalkingAnimation);
Here bearAnimate is a global variable and i wish to know if its currently playing the animation.
How do I do it.?Thank you.
Assume the Sprite that runs the action is
CCSprite* bear;
I think you can use something like
bear->numberOfRunningActions()
numberOfRunningActions( ) returns an unsigned integer, so to check if there are no actions, you would have to check if it returns 0
if ( bear -> numberOfRunningActions( ) == 0 ) {
CCLOG( "No actions running." );
} else {
CCLOG( "Actions running." );
}
The bearAnimate (CCAnimate) has a method to check that.
if (bearAnimate.isDone())
doWhatYouWant();
The method is inherited from CCAction. Good luck.
I move a Sprite across the screen using the keyboard, at a rate of 10 pixels/ENTER_FRAME event fire. The issue is that, when it moves, you can see it being "redrawn" every 10 pixels, which makes it hard to look at. I haven't seen this in other Flash games.
If you look closely, you can also see this here (although at a much lower scale): http://kirill-poletaev.blogspot.com/2010/07/smooth-character-movement-using-as3.html
I want to get rid of that effect, any ideas?
If the player is at a distance of ... from the screen edge, it stops moving (by moving in the opposite direction), and the BG starts scrolling (the same visual effect can be seen).
Music in playing in the background, a minimap is updated with the player's position.
private function updater(e:Event):void
{
if(up && GlobalVars.vars.upPossible)
{
cont.y-=unit;
setu(); // Player graphics state
}
else if(down && GlobalVars.vars.downPossible)
{
cont.y+=unit;
setd(); // Player graphics state
}
else if(left && GlobalVars.vars.leftPossible)
{
cont.x-=unit;
setl(); // Player graphics state
}
else if(right && GlobalVars.vars.rightPossible)
{
cont.x+=unit;
setr(); // Player graphics state
}
else
{
ups.visible=false; downs.visible=false; rights.visible=false;
lefts.visible=false; normals.visible=true; // Player graphics state
GlobalVars.vars.scXr=0; GlobalVars.vars.scYu=0; GlobalVars.vars.scXl=0;
GlobalVars.vars.scYd=0; cont.x=int(cont.x); cont.y=int(cont.y); //Someone from the Kongregate.com forums suggested this, no visible effect
}
if((cont.x=GlobalVars.vars.maxX))
{
if(cont.x=GlobalVars.vars.maxX && right && GlobalVars.vars.canScrollR) GlobalVars.vars.scXr=1, cont.x-=unit, setr();
}
else GlobalVars.vars.scXl=0, GlobalVars.vars.scXr=0; //BG Scrolling
if((cont.y=stage.stageHeight*7.3/10))
{
if(cont.y=stage.stageHeight*7.3/10 && down && GlobalVars.vars.canScrollD) GlobalVars.vars.scYd=1, cont.y-=unit, setd();
}
else GlobalVars.vars.scYu=0, GlobalVars.vars.scYd=0; //BG Scrolling
if(cont.y>=stage.stageHeight*7.3/10 && cont.x>=GlobalVars.vars.maxX) GlobalVars.vars.minimapTr=1;
else GlobalVars.vars.minimapTr=0;
if(cont.y-unitGlobalVars.vars.sH-cont.height-3.1) GlobalVars.vars.downPossible=false;
else GlobalVars.vars.downPossible=true;
if(cont.x-unitGlobalVars.vars.sW-cont.width-3.5) GlobalVars.vars.rightPossible=false;
else GlobalVars.vars.rightPossible=true;
GlobalVars.vars.plX=cont.x; //for minimap
GlobalVars.vars.plY=cont.y;
Also, key listener functions:
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyD, false, 0, true);
stage.addEventListener(KeyboardEvent.KEY_UP, keyU, false, 0, true);
private function keyD(e:KeyboardEvent):void
{
if(e.keyCode==37 || e.keyCode==65) left=true;
if(e.keyCode==38 || e.keyCode==87) up=true;
if(e.keyCode==39 || e.keyCode==68) right=true;
if(e.keyCode==40 || e.keyCode==83) down=true;
}
private function keyU(e:KeyboardEvent):void
{
if(e.keyCode==37 || e.keyCode==65) left=false;
if(e.keyCode==38 || e.keyCode==87) up=false;
if(e.keyCode==39 || e.keyCode==68) right=false;
if(e.keyCode==40 || e.keyCode==83) down=false;
}
I've encountered some improvement by increasing the FPS to 120, and decreasing the step to 4, but it's still there. I'm fairly sure it's not a performance issue, but, rather, a movement method fault.
A couple of suggestions:
Increase the frame rate
Use a tween library (e.g. GTween) with some easing effect.
Basically, if you want the object to jump 10px to the right, don't just move it right away, let it animate to its new position with some easing effect. Additionally, if the object is still moving and the key is pressed again, you probably want to accelerate the movement a bit (but only up to a point!).
I think you're asking how to make it more smooth. Well:
If you change the movement 2px per frame, then you'll have a much smoother experience. However, the movement will see very slow. To combat this, you just increase the frame rate of your swf. I believe the maximum is 120 frames, but that should be more than enough.
I love Tweenlite, it's great for pre-defined effects. It isn't for the core of your game though so I'd use Tweenlite for UI effects but barely for ingame movements responding to user controls.
I think around 24-30 fps for games is great, that's how I set all my games. I think abit you're picky, but perhaps what you're missing is a bit of edge: a smooth start and end for the movement. In most platformers I have a similar mechanic:
You want the start of the movement to start slow, reach the normal (max) speed you define and when the player lets go of a button, it slows down back to 0. This means you need to check the speed on enter frame regardless of the button triggers (they increment the speed but aren't the only condition to change speed and move the object)
enterframe loop:
//check for each direction:
if up, y_speed++
else if down, y_speed--
else if right, x_speed++
else if left, x_speed--
else // perform a decrease:
y_speed *= .8
x_speed *= .8
// make sure we aren't past the max speed
if x_speed>max_x_speed
x_speed = max_x_speed
etc. else other direction and y_speed
// now apply the movement
object.x += x_speed
object.y += y_speed
// remove the enterframe for better performance
if math.abs(x_speed)<.1 && math.abs(y_speed)<.1
// remove enterframe for movement here, add it again next time we know we have movement (button downs related to the movement, etc.)
I would implement this in your code but your code is too crowded. Anyway otherwise, most games with these simple controls are working just like your application does.
So, I'm working on the basics of Actionscript 3; making games and such.
I designed a little space where everything is based on location of boundaries, using pixel-by-pixel movement, etc.
So far, my guy can push a box around, and stops when running into the border, or when try to the push the box when it's against the border.
So, next, I wanted to make it so when I bumped into the other box, it shot forward; a small jump sideways.
I attempted to use this (foolishly) at first:
// When right and left borders collide.
if( (box1.x + box1.width/2) == (box2.x - box2.width/2) ) {
// Nine times through
for (var a:int = 1; a < 10; a++) {
// Adds 1, 2, 3, 4, 5, 4, 3, 2, 1.
if (a <= 5) {
box2.x += a; }
else {
box2.x += a - (a - 5)*2 } } }
Though, using this in the function I had for the movement (constantly checking for keys up, etc) does this all at once.
Where should I start going about a frame-by-frame movement like that? Further more, it's not actually frames in the scene, just in the movement.
This is a massive pile of garbage, I apologize, but any help would be appreciated.
try doing something like: (note ev.target is the box that you assigned the listener to)
var boxJumpDistance:Number = 0;
function jumpBox(ev:Event){
if (boxJumpDistance<= 5) {
ev.target.x += boxJumpDistance; }
else if(boxJumpDistance<=10){
ev.target.x += boxJumpDistance - (boxJumpDistance - 5)*2
}
else{
boxJumpDistance = 0;
ev.target.removeEventListener(Event.ENTER_FRAME, jumpBox);
}
}
then instead of running the loop, just add a listener:
box2.addEventListener(Event.ENTER_FRAME, jumpBox);
although this at the moment only works for a single box at a time (as it is only using one tracking variable for the speed), what you would really want to do is have that function internally to the box class, but im unsure how your structure goes. the other option would be to make an array for the boxes movement perhaps? loop through the array every frame. boxesMoveArray[1] >=5 for box 1, etc.