How to replace Mutiple Timers with TweenLite delayedCall or ENTER_FRAME event? - actionscript-3

Hey everyone so I have a lot of timers in my game to be specific around 8 timers. They all control different Movie clip objects that appear on the stage at different times. I also change the timers in my difficulty update function. Now I have read a lot to understand that Timers do cause lag and decrease the performance. I am creating this game using AS3 Adobe AIR for Android devices. My game seems to freeze for half a second every second which I believe is do to the timers as well as the garbage collector. Either way I was wondering if I remove all these timers and instead replace them with TweenLite TweenLite.delayedCallfuncion if it would dramatically increase performance. I Have tried this on one of my old timers that i removed and replaced with the tweenlite function and it seems to be working just fine but not sure if this is the correct way of doing it here is how i have it set up in my constructor:
TweenLite.delayedCall(6.0, addWatch);
and the addWatch function:
private function addWatch():void
{
TweenLite.delayedCall(6.0, addWatchTimer);
var newWatch:mcWatchTimer = new mcWatchTimer();
stage.addChild(newWatch);
aWatchTimerArray.push(newWatch);
//Start screen sound
watchSoundChannel;
watchSound = new watch();
watchSoundChannel = watchSound.play(0, 9999);
}
this seems to loop it without me having to attach an ENTER_FRAME Eveent listener to it. But not sure if this would be wise since I want to be able to change the delayedCall in my difficulty update to a faster time interval.
Any feedback on the situation would be appreciated. Hope I made enough sense.

Related

Actionscript-3 looping issue--Adobe Animate CC

My employer decided they wanted me to start doing animation with Adobe's new "Animate CC" application. My issue is that I don't know how to loop my animation outside of the Adobe Animate environment. I am new to Adobe Animate CC and ActionScript, unfortunately, so I will probably need a relatively basic answer to understand why my solution isn't working. From what I can tell, my ActionScript code is being ignored by the IDE completely.
In the IDE and in the browser test command, the animation plays beyond frame 100, to the end, and then flashes a frame of white before repeating. I need it to loop without this white frame interrupting the screen, whether that be through a loop or some other means that I'm just not aware of.
For context: my project has about 100 layers of content and I'm unfamiliar with how this program works. I've thoroughly searched the web for tutorials on how to do what I need to do, but I've come up empty handed.
I have an actions layer among my motion tweens and other layers
https://gyazo.com/6e0b8502d98b6c9903bb96ac3a939bae
I've been trying to use gotoAndPlay(0) at frame 100 to start the animation over from the beginning.
https://gyazo.com/704ee7158bae6dfd149b6283cfa33451
Basically, how do I use Action-Script in Adobe Animate CC in order to infinitely loop my animation until closed?
Thanks everyone.
Your flicker may be a result of having an extra blank keyframe on one of your layers.
Assuming that you don't have any additional scripts to stop your animation (e.g. stop()), the Timeline should loop automatically whether your animation is inside a MovieClip or on the main Timeline. You shouldn't have to put any script on your timeline or in a separate AS file to make an animation loop. I would suggest this method.
Additionally, although you have the code specifying that you want it to go the first frame, it will ignore your call because the timeline is still playing and therefore the priority. One way you can combat this is by adding a stop(); function and a delay timer that contains your gotoAndPlay(0) function. This will take focus away from playing the Timeline and will allow you to execute your script. I wouldn't suggest this method because it seems a bit redundant.
However, if you're curious one way that you could approach this is shown below, simply add this script to the frame you want the animation to restart at.
//Stop the Timeline
stop();
//Create a delay timer for 5 miliseconds that is executed once
var timer:Timer = new Timer(5,1);
//Add an event listener that calls once the timer is complete
timer.addEventListener(TimerEvent.TIMER_COMPLETE, timerHandler);
//Start the timer
timer.start();
//Timer handler that is called once the delay timer is complete
function timerHandler(event:TimerEvent){
//Go to and play the first frame
gotoAndPlay(0);
}

Moving text across screen smoothly

For a long time I've been searching for a solution to this problem, so I decided to post a tread instead when the search didn't clarify anything.
I have a textfield that is supposed to move across the screen. I've solved this by adding a speed to its x-value dynamically through an "enter-frame function". However, the movement is very "laggy" and consists of sudden "jumps" in the movement. I've tried a couple of possible solutions to this, all of them without luck.
embedding fonts
changing the textfield's antiAliasType
using BitmapData like this:
bmd = new BitmapData (myTextField.width, myTextField.height, true, 0);
bmd.draw (myTextField);
bm = new Bitmap (bmd);
bm.x = myTextField.x;
bm.y = myTextField.y;
bm.cacheAsBitmap = true;
bm.smoothing = true;
this.addChild(bm);`
And then moving the "bm" instance
None of these methods worked.
EDIT: By request, I am adding the relevant code for the actual movement of the text.
stage.addEventListener(Event.ENTER_FRAME, time);
private function time(evt:Event):void
{
bm.x-= textSpeed;
}
The variable textSpeed is defined as a public static var. Its value is 2.
*EDIT2: I've prepared a clean fla-file with nothing but moving text. The same lag occurs for me also here. The code is in the actions panel. Download link
the way Flash IDE works, is that setting the framerate is actually the 'maximum' framerate. That is, it doesn't force the animation to run at that rate - it can vary depending on the machine and available resources.
As far as I know, there's no way to force Flash to run at a certain framerate - the best way to make animations 'smooth' is to use Tween classes like TweenLite.
If you NEED to animate by incrementing position values, then I suggest making it time based instead, for example:
var fps = 24;
var moveTimer:Timer = new Timer(1000/fps);
moveTimer.addEventListener(TimerEvent.TIMER, onMoveTimer);
moveTimer.start();
function onMoveTimer(e:TimerEvent){
bm.x -= 1;
}
Again, this doesn't solve the smoothness of the animation, but it will be much more reliable across different machines than using enter frame.
Try increasing the framerate. Because you naturally try to read text as it animates, you can generally notice the gaps between frames at 24fps. Try setting stage.frameRate to 30, 48, or 60 (60 being the max) and see if that solves your issues. I've had similar issues with animating text in the past and increasing frame rate has fixed them.
I would also recommend only increasing it as needed. You are much more likely to drop frames with a higher frame rate (makes logical sense; each frame has less time to calculate as frame rate increases), so you might want to do something like:
stage.frameRate = 48;
// run animations here
stage.frameRate = 24; // in an Event.COMPLETE handler
That will make sure your animations are smooth while giving the rest of your application the best shot of running well on lesser devices. If you are running a lot of animations, you might consider keeping it elevated permanently.
You should also look into using the Greensock animation library (TweenLite/TweenMax) instead of Flash's built-in tweening. Greensock has a vastly superior API, both in terms of features and performances, especially on mobile.

Time Based Animation in Flash

I am new to working in ActionScript and I'm experimenting with using the Timeline to trigger certain events in my game. In particular, I'm using the timeline to trigger the fire event for a gun so that when the fire animation gets to a certain frame, a bullet is spawned. In the gun class (Enter_Frame) I check that the mouse is being held down and the time between the last shot and the current time is longer than the cool down, if everything checks out I play the animation.
if (time - lastShot > cooldown)
{
canShoot = true;
lastShot = time;
}
if (mouseHold && canShoot)
{
play();
}
This creates a problem when the frame rate is brought below the point where the full animation cannot be played before the cool down is up again. In this instance the bullets fire slower with lower frame rates.
In addition, higher frame rates make the gun more responsive to mouse input because the fire frame comes sooner than in lower frame rates.
The goal is obviously to make the game completely frame rate independent. I would like to have the ability to slow down or speed up the frame rate of the animation depending on the cool down of the gun.
What is the best way to make this animation play in a specific time period without skipping over the actions that I have put into the timeline?
It sounds like you're on the right track, but approaching this the wrong way. Check out the Timer class, it's framerate independent, and will greatly aid you.
var my_timer = new Timer(1000,0); //in milliseconds
my_timer.addEventListener(TimerEvent.TIMER, catchTimer);
my_timer.start();
function catchTimer(e:TimerEvent)
{
trace("event fired");
}
You should look into time based animation instead of frame based if you want your animations to be precise and not depend on the framerate, this way your animations will always be the same and will compensate the slower frame rates of slower computers. Here is an article that explains it very well: http://www.flashgamesclassroom.com/classroom/actionscript/frame-based-vs-time-based-animation/

How to get rid of lag caused by lots of enemy instances?

im making a flash shooter game and ive encountered one problem. When there are a lot of monsters on the stage which are visible by player, the game starts to lag. In my opinion, its due to Event.ENTER_FRAME (each enemy instance has it) where z-sorting, enemy movement, updating other stuff like health is done. Since things like theese, cant be done each second or at similar time interval,im using ENTER_FRAME. My question is, how can i have many instances of the enemy in my game and still dont have it lagging. Ive done optimising in all over the code and if im not mistaken,big ammount of enemies is the performance bottleneck here.
Question me if i wasnt clear; to see the game go to http://ernyz.lhosting.info/bandymas.html or if you want to see the code,i will be able to put it here,just ask :)
Having an enter frame events for each instance is most likely the problem. A single event where you loop over all instances and do actions is usually faster.
There shouldn't be much for you to change: Instead of adding the listener to each enemy, add only one listener to the stage and call the enemies' update functions.
class Enemy {
function update(e:Event) { /* ... */ }
}
class Main {
function onEnterFrame(e:Event) {
for each (var enemy:Enemy in enemies) {
enemy.update(e);
}
}
}
From my experience, unless you're doing something very wrong, flash rendering pipeline is what takes the most time of your application. And since you get more enemies, you get more MovieClips and more complex rendering.
But having one ENTER_FRAME event for each object is indeed a big overhead that can be easily avoided.
A good practice before optimizing your code is to actually run it through a profiler. I don't believe the actual Flash program has it, but Flash Builder surely does. If you post us a screenshot or a log of the game being profiled, we can be of more assistance.
By quickly playing your game, I've seen that all your enemies are a bunch of graphics with a bunch of gradients, therefore costly to render. Have you tried setting the quality to low? Does the lag go away?

Best practices: ENTER_FRAME vs. Timer

I'm creating a Flash game which is based on the old Pacman and I'm not sure which is the best way to control the animation.
As I understand it these type of games were originally dependent on a game loop which ran faster or slower depending on the CPU, which is why I imagine that the most similar to use would be the ENTER_FRAME event.
This however presents the problem of having to have a specific frame rate and changing it later is out of the question, not to mention being limited to very few different "speeds" (see below). An example could be that the sprite has to move 12 pixels before the next move is determined. If the speed is then 4 pixels per frame, the math is quite simple:
[...]
public var stepCount:uint = 0;
[...]
function enterFrameHandler(e:Event):void
{
if(stepCount==0) {
//Some code to evaluate next move. Let's say it evaluates to MOVE RIGHT
}
if(MOVE_RIGHT)
{
x += 4;
}
stepCount++;
if(stepCount > 2)
{
stepCount = 0; //Now ready to evaluate direction again.
}
}
This all works fine, but let's say that I want the sprite to move 5 pixels per frame. Then the number of frames before making the next evaluation would not compute. The stepSize would have to be a multiple of 12, which limits the different possible speeds (1,2,3,4 and 6 pixels per frame).
This is why I attempted to base the movement on a Timer instead, which I also managed to get to work, but the movement was somewhat erratic and it seemed like the Timer was using far more memory than the ENTER_FRAME event. Instead of an even movement the Timer made the sprite slow down and speed up and slow down again.
Another possible solution could be the Tween class, but it seems extravagant.
Does anyone have experience with what works best in other games?
Morten Twellmann
You have several separate issues here. Your first question is, should you execute your game loop in a frame event or a timer event? The answer is easy - you should do it in a frame event. The reason is that regardless of how you move your characters, the screen is updated precisely once per frame. So any time you're calling your game loop more than once per frame you're wasting CPU, and any time you call it less than once per frame, you're sacrificing visual quality. So this one is easy, don't bother with timer events at all.
The next question is whether your game's movement should be tied to frames or miliseconds, and the answer is that it depends on the game. Ask yourself this: suppose that some user is playing your game, and their spaceship (or whatever) is flying along at a given speed. Suddenly, the user's anti-virus package does something heavy, and the CPU spike causes Flash to stop updating for one second. Once the spike is over, do you want the spaceship to continue moving from where it was when the spike started? Or do you want it to jump forwards to where it would be if it had continued moving during the spike? If you want the former, you should tie your movement to frames; if you want the latter, you should tie it to miliseconds. But which one is best depends on how you want your game to work.
The final question is, how exactly should you move the characters in your game? Based on what you wrote, I'd do it as follows. For frame-based movement (i.e. the first approach described earlier):
// the ship moves 25 pixels per second
var shipSpeed:Number = 25;
// the number of seconds per frame, based on the published framerate
var frameTime:Number = 1 / stage.frameRate;
// game loop called each frame:
function gameLoop() {
// ...
playerShip.x += shipSpeed * frameTime;
// ....
}
This way, the ship's movement on screen is constant, regardless of what framerate you publish your SWF at. Using a higher framerate simply makes the movement smoother. Likewise, to tie your movement to time instead of frames, simply change "frameTime" in the code above to refer to the time elapsed since the previous frame, as described in Allan's answer.
Yes frame rates will vary depending on CPU amongst other things. Therefore you need to take this into account with your game loop. What I like to do is get the time difference between the current frame and the old frame and use that value in my calculations. So if it happens that there is a delay the larger difference value will then make up for the fact less frames ran.
var _previousTime:Number;
//gameLoop is the function called on ENTER_FRAME
public function gameLoop(e:Event):void
{
var currentTime:Number = getTimer();
var difference:Number = currentTime - _previousTime;
_previousTime = currentTime;
//use difference variable with calculations involving movement
}