How do I get a complete animation loop in one keystroke? - libgdx

What do I need to fix so that a single keystroke plays one full animation loop?
Creating animation object:
jojoStandSummonTextureAtlasRight = new TextureAtlas(Gdx.files.internal("jojo/stand_summon/right/jojo_stand_summon.atlas"));
jojoStandSummonAnimationRight = new Animation<TextureRegion>(1 / 3f, jojoStandSummonTextureAtlasRight.getRegions());
Rendering animations:
if(Gdx.input.isKeyJustPressed(E) && lastKeyInput == RIGHT){
sb.draw(jojo.jojoStandSummonAnimationRight.getKeyFrame(elapsedTime, false), jojo.getPosition().x, jojo.getPosition().y);
lastKeyInput = RIGHT;
}

The Animation class provided by LibGDX includes an .isAnimationFinished() function. This will return a boolean indicating when the animation has finished playing.
In your case, I assume you're updating your elapsedTime variable in your update() function. So you can do something like:
if(!jojoStandSummonAnimationRight.isAnimationFinished()) {
elapsed_time += Gdx.graphics.getDeltaTime();
} else {
// animation is finished
}

Related

AS3: Fast hovering doesn't execute rollOut

I'm having a serious problem that is getting me nervous:
I've made a button _btn that includes ROLLOVER and ROLLOUT animations with coding (an nested movieclip instance called barra that increases to half alpha when you hover over and decreases when you hover out).
[Here it should go a descriptive image but I'm new and I need 10 reputation. I'll appreciate your help]
This works perfectly but the problem occurs when I move my cursor very quickly from one point to another, with the button in between. It seems that the ROLLOUT function is not detected, so the ROLLOVER animation keeps working (and if you look carefully, the animation stops for a few seconds and then continues).
[Here it should go another descriptive image too]
This is the code in the Actions layer:
//Funciones ROLL OVER
function _btnOver(event:MouseEvent):void {
_btn.buttonMode = true;
_btn.addEventListener(Event.ENTER_FRAME,_btnFadeIn);
}
function _btnFadeIn(event:Event):void {
_btn.barra.alpha += 0.1;
if (_btn.barra.alpha >= 0.5)
{
_btn.removeEventListener(Event.ENTER_FRAME,_btnFadeIn);
}
}
_btn.addEventListener(MouseEvent.ROLL_OVER,_btnOver);
//Funciones ROLL OUT
function _btnOut(event:MouseEvent):void {
_btn.addEventListener(Event.ENTER_FRAME,_btnFadeOut);
}
function _btnFadeOut(event:Event):void {
_btn.barra.alpha -= 0.1;
if (_btn.barra.alpha <= 0.2)
{
_btn.removeEventListener(Event.ENTER_FRAME,_btnFadeOut);
}
}
_btn.addEventListener(MouseEvent.ROLL_OUT,_btnOut);
Click here if you want to download the FLA and SWF files, so you can see the problem clearly.
I barely know how to use ActionScript 3 (my only programming knowledge is Processing) and I don't have time now to learn it from head to toe, but I've researched about the problem and it's still not clear.
With tutorials and guides, I managed to learn how to create and understand this code, and I think the problem might be in the functions of the events ROLL_OVER and ROLL_OUT, which contain the addEventListener of the ENTER_FRAME events (where the animations actually are), respectively. But I don't know exactly what I have to do to fix it, what should I add or change.
I would be really glad if someone could help with this, I'm frustrated! What do you recommend me to do?
Thanks in advance
(PD: I don't understand most of the programming language. If you can be as clear and direct as possible, I'll really appreciate it)
Apparently your troubles lay in incoherent animation sequence by using enter frame listeners. You are running two independent listeners, both altering alpha of a single object, this creates a conflict, only one will work (you can determine which if you add both at once and trigger events, the resultant alpha value will indicate which listener changes it last) and you apparently expect one to do a fade in while the other to do a fade out. Instead, you should use one listener (probably even persistent) and give your object "target alpha" property as well as delta to change alpha per frame. An example:
var bbta:Number=0.2; // btn.barra's target alpha
_btn.addEventListener(Event.ENTER_FRAME,_btnFade);
function _btnFade(e:Event):void {
var a:Number=_btn.barra.alpha;
if (Math.abs(a-bbta)<1e-8) return;
// no sense of setting alpha with minuscule difference
const delta:Number=0.1; // how fast to change per frame
if (a>bbta) {
a-=delta;
if (a<=bbta) a=bbta;
} else {
a+=delta;
if (a>=bbta) a=bbta;
}
_btn.barra.alpha=a;
}
function _btnOver(event:MouseEvent):void {
_btn.buttonMode = true; // move this elsewhere, if you don't cancel buttonMode
bbta=0.5; // set target alpha, the listener will do a fade-in
}
function _btnOut(event:MouseEvent):void {
bbta=0.2; // set target alpha, the listener will do a fade-out
}
I edited some code in here, basically i am checking hover state onLoop function, so you can change your settings on here
import flash.events.Event;
var isRolledOver:Boolean = false;
//Funciones ROLL OVER
function _btnOver(event:MouseEvent):void {
isRolledOver = true;
}
function _btnOut(event:MouseEvent):void {
isRolledOver = false;
}
_btn.addEventListener(MouseEvent.ROLL_OVER,_btnOver);
_btn.addEventListener(MouseEvent.ROLL_OUT,_btnOut);
this.addEventListener(Event.ENTER_FRAME,onLoop);
function onLoop(e){
if(this.isRolledOver){
if(_btn.barra.alpha < 0.5) _btn.barra.alpha += 0.1;
}
else{
if(_btn.barra.alpha > 0.5 || _btn.barra.alpha > 0) _btn.barra.alpha -= 0.1;
}
}
I added the sample fla in case

AS3: repeating function in sigle frame timeline

I'm very new in action script. I have single frame timeline and there is function that moves movie clip verticaly. i want to repeat this only three times.
The code works, I'm just not sure if this is the correct way or if it's too complicated.
var pocet:Number = 0;
pruh.addEventListener(Event.ENTER_FRAME, fl_AnimateVertically);
function fl_AnimateVertically(event:Event)
{
if (pruh.y >= stage.stageHeight) {
pocet++;
}
if (pruh.y < stage.stageHeight) {
pruh.y += 3;
}
else {
pruh.y = 0 - pruh.y;
}
if (pocet == 3) {
pruh.removeEventListener(Event.ENTER_FRAME, fl_AnimateVertically);
}
}
thanx
Congratulations on achieving your goal.
Your code could be improved in terms of readability. You have fl_AnimateVertically as a descriptive name, but other than that it's kind of hard to figure out what's going on exactly. I mean sure it adds 3 to y which probably results in movement, but it's not trivial to understand the exact behaviour.
That's why you want to use abstraction or more of a top down approach as it often called..
What you are doing at the moment is adding a value to the coordinate, which as a result creates an animation. What you actually want is to create an animation, without going into details what that actually means.
And sure enough, people created animations with code before. That's why you can create an animation in the abstract sense: An animation is the change of a property of an object over time. In the realm of flash an animation is called a tween and there's a class doing exactly that..
Let's take the example code there:
var myTween:Tween = new Tween(myObject, "x", Elastic.easeOut, 0, 300, 3, true);
And apply it to your situation.
var verticalAnimation:Tween = new Tween(pruh, "y", Elastic.easeOut, pruh.y, stage.stageHeight, 3, true);
You have to adjust the duration to your liking. I hope you see how this is easier to read and maintain, because you specify properties of the animation like duration. You can also specify easing, which makes the motion more interesting.
Ok, this is only one animation, but you want 3, right?
More precisely, you want to do that same animation again, when it finished.
And you can do exactly that:
var animationCount:uint = 0;
var verticalAnimation:Tween = new Tween(pruh, "y", Elastic.easeOut, pruh.y, stage.stageHeight, 3, true);
verticalAnimation.addEventListener(TweenEvent.MOTION_FINISH, onMotionFinish); // wait for the animation to be finished
function onMotionFinish(e:TweenEvent):void
{
animationCount++; // add 1 to the counter
if(animationCount >= 3) // check how many times the animation finished so far
{
// if it was the last one, remove the listener
verticalAnimation.removeEventListener(TweenEvent.MOTION_FINISH, onMotionFinish);
}
else
{
// otherwise rewind and start again
verticalAnimation.rewind();
verticalAnimation.start();
}
}
There are other libraries than this built in Tween class that are far more powerful.
The one from greensock is very popular and easy to use you can find the documentation for the flash version here
Try this
var pocet:Number = 0;
pruh.addEventListener(Event.ENTER_FRAME, fl_AnimateVertically);
var startY:int=pruh.y;
function fl_AnimateVertically(event:Event)
{
if (pruh.y >= stage.stageHeight) {
pocet++;
pruh.y=startY;
}
if (pruh.y < stage.stageHeight) {
pruh.y += 3;
}
else {
pruh.y = 0 - pruh.y;
}
if (pocet ==3) {
pruh.removeEventListener(Event.ENTER_FRAME, fl_AnimateVertically);
trace("done");
}
}

How do I play the animation from the current frame, ActionScript 3.0

I'm trying to make a personalized pause button for my flash animations.
This the code I have for it so far
var paused:Boolean = false;
pause.addEventListener(MouseEvent.CLICK, fl_PauseUnpause);
function fl_PauseUnpause(event:MouseEvent):void
{
if(paused=true)
{
stop();
paused=false;
}
else
{
gotoAndPlay(this.currentFrame);
paused=true;
}
}
Stopping the animation works just fine, but it will not start again afterwards. It gives no error when run.
if(paused=true) // this assigns true to paused and if always evaluates to true
That has to be :
if(paused==true) //or if(paused)
No?

Removing Children in AS3

My flash game exists of a timeline with multiple frames (I know I should avoid the timeline)
The point of the game is a point and click adventure. The object that you are able to pick up get spawned and destroyed accordingly as you enter and leave the room. now my problem is when entering frame 14 (accessibel from frame 12) it creates a piece of paper which you are able to pick up if you have another item. Now my problem is when you can't or don't pick up the paper and go back to frame 12 (only exit is to frame 12), you can't click on any other object and you are basicly stuck on frame 12. When leaving and entering other rooms it works properly but for some reason it doesn't for on the paper on frame 14.
My code to remove objects works as following
In my Main.as Documentclass I have a function that called as soon as the game starts which does the following
if (lastframe == 14)
{
trace (prop.numChildren);
while (prop.numChildren )
{
prop.removeChildAt(0);
}
}
The lastframe variable is established when moving from frames
this function is found on the frame itself (each exit function on it's own respective frame)
function exitKantine(event:MouseEvent):void
{
Main.lastframe = 14;
gotoAndStop(12);
}
The function to remove the prop actually removes it but then causes all other clickable objects to be unusable.
Thanks for looking at my question and thanks in advance for your suggestions
I would say instead of removing children, add it once in the beginning, add all the listeners in the beginning, and toggle the visibility instead of trying to addChild and removeChild every time you want to hide it. Use an array so you can have a few happening at the same time.
something like this:
private function init():void
{
assignVars();
addListeners();
stage.addChild // make sure this is in document class or you are passing stage to the class using it
}
for (var i = 0; i < _thingsAry.length; i++)
{
if (_thingsAry[i] == 14)
{
_thingsAry[i].visible = false;
trace("the visibility of _thingsAry[" + i + "] is " + _thingsAry[i].visible
}
}

TweenLite AS3: ease:Linear.easeNone doesn't work

In the function below I try to throw random items (generated by the function generateItem() ) on the stage and let them move from outside the right side of the stage to just out of the left side. This works fine but the only problem is that ease:Linear.easeNone in the TweenLite.to function doesn't work. The items keep going fast in the beginning and slow at the end of the animation. Here is the code:
private function timerHandler(event:TimerEvent):void{
//item handling
if(gameTimer.currentCount % 4 === 0){
var item:MovieClip = generateItem();
arrItems.push(item);
for each(item in arrItems){
TweenLite.to(item,5,{x:-(item.width - 1), ease:Linear.easeNone});
trace(item + " ----- " + item.x);
if(item.x < -(item.width)){
arrItems.splice(arrItems.indexOf(item),1);
stage.removeChild(item);
}
}
}
What is going on here is that you are overriding your tweens again and again inside the for each loop. Once you have set up a tweening animation for an object with TweenLite.to you don't need to set it again for that same object, unless you want to override it with a new tween.
The reason you see the end of the animation going slower is because the distance the object has to move until the final point of the tweening animation is less (since it has already covered some of it), but the total duration of the animation is still 5 seconds. Speed = distance/time, so same time but shorter distance = slower tweening.
You can fix this by just moving the TweenLite.to call outside of the loop, so only one tween will be set up for each item. Another improvement I recommend for your code is to use the onComplete callback function of TweenLite to avoid that costly for each loop inside your timeHandler function, and remove the item only after the tweening has completed, unless you need to iterate through all items for some other reason than to just check if the tweening has ended.
For example:
private function timerHandler(event:TimerEvent):void
{
//item handling
if(gameTimer.currentCount % 4 === 0)
{
var item:MovieClip = generateItem();
arrItems.push(item);
//only call once for each item
TweenLite.to(item,5,{ x:-(item.width - 1),
ease:Linear.easeNone,
onComplete: removeItem,
onCompleteParams:[item]
});
}
}
private function removeItem(item:MovieClip):void
{
arrItems.splice(arrItems.indexOf(item),1);
stage.removeChild(item);
}
Hope this helps!