ActionScript: How to Re- setInterval Each Time Function Works? - actionscript-3

I have a function that draws a rectangle on the screen (see createInfoPanel())
While drawing rectangle, I am adding 2 text fields on it.
But as you may guess, it is adding those immediately.
I want to delay adding these text fields, then I want to remove these panels after a while.
The problem is, when I set an interval or timer, they won't work after I using once (I had to stop them by clearing/removing, it didn't set them again).
Since my panel is being created each time image changes, I need them to work every time image changes.
So, I have 2 questions:
1- How can I re-set interval each time my createInfoPanel() function works? It won't work anymore after setting and claring once.
2- You can see infoPanel.addChild(titleField); line in addInfoPanel() function. How can I work a smooth animation here? I mean, text appears slowly?
Thanks in advance.
public class ImageRotator extends Sprite
{
private var ... ; //Some variables
public function ImageRotator(xmlPath:String = "images.xml", interval:int = 8301):void
{
timer = new Timer(interval);
loadXML(xmlPath);
}
private function loadXML(file:String):void
{
urlLoader = new URLLoader(new URLRequest(file));
urlLoader.addEventListener(Event.COMPLETE, parseXML);
}
private function parseXML(e:Event):void
{
xml = new XML(e.target.data);
loadImages();
}
private function loadImages():void
{
for (var i:int = 0; i < xml.children().length(); i++)
{
var loader:Loader = new Loader();
loader.load(new URLRequest(xml.children()[i].#src));
imagesVector.push(loader);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, sortImages);
}
}
private function sortImages(e:Event):void
{
imagesCounter++;
for (var i:int = 0; i < imagesVector.length; i++)
{
imagesVector.reverse();
addChild(imagesVector[i]);
}
//I have only 3 images, I needed to set indexes because
//they were covering each other
this.setChildIndex(imagesVector[2], 0);
this.setChildIndex(imagesVector[1], 0);
this.setChildIndex(imagesVector[0], 0);
if (imagesCounter == imagesVector.length)
{
createInfoPanel();
timer.addEventListener(TimerEvent.TIMER, autoChange);
timer.start();
}
}
private function createInfoPanel():void
{
infoPanel.graphics.beginFill(0x000000, 0.0);
infoPanel.graphics.drawRect(0, 0, 967, 138);
infoPanel.graphics.endFill();
////Here I want to run addInfoPanel() function with 2 seconds delay,
////After it starts, I want to run removeInfoPanel() function with 2 more seconds delay
addChild(infoPanel);
}
private function addInfoPanel():void {
titleField.text = xml.children()[infoCounter]. # title;
titleField.x = 425;
titleField.y = 0;
description.text = xml.children()[infoCounter]. # description;
description.x = 427;
description.y = 26;
infoPanel.y = 300;
infoPanel.addChild(titleField);
infoPanel.addChild(description);
}
private function removeInfoPanel():void {
infoPanel.removeChild(titleField);
infoPanel.removeChild(description);
}
private function addActions():void
{
//Some function
}
private function changeImage(e:MouseEvent):void
{
//Image changing function
}
private function changeDepth(e:TweenEvent):void
{
//Some function
}
private function autoChange(e:TimerEvent):void
{
//Some function
}
}
Edit: How I used to work the intervals:
private function createInfoPanel():void
{
//lines above code sample
intervalInfoPanel = setInterval(addInfoPanel,2000);
addChild(infoPanel);
}
private function addInfoPanel():void {
//lines above code sample
clearInterval(intervalInfoPanel);
intervalInfoPanelRemove = setInterval(removeInfoPanel,3500);
}
private function removeInfoPanel():void {
//lines above code sample
clearInterval(intervalInfoPanelRemove);
}

1- How can I re-set interval each time my createInfoPanel() function
works? It won't work anymore after setting and claring once.
how exactly are you resetting your interval? you don't show the code here.
but normally you can reset + re-use a timer like this:
timer.reset();
this will stop and reset the timer's currentCount to 0.
you can then later say timer.start(); and everything should work like it never ran before.
2- You can see infoPanel.addChild(titleField); line in addInfoPanel()
function. How can I work a smooth animation here? I mean, text appears
slowly?
use a tween. add the TextFields with txt.alpha = 0; and then tween the alpha value slowly to 1.0. TweenLite (http://www.greensock.com/tweenlite/) is a great tweening-engine.
import com.greensock.*;
txt.alpha = 0.0;
TweenLite.to(txt, 1, {alpha:1.0, delay:0.4});

Related

How to get a percentage from new Date();

I have a digital clock for now, and I need the corn to know when 10 seconds as passed, this way it can go to the next frame. Im having difficulty finding out how to gather the 10 secs and make it out of 100% for example
its 9:30:21 and i pushed the button
at 9:30:31 it should be done
but I want to create a percentage bar based on that 10sec.. heres my code
farmSlot1.addEventListener(MouseEvent.CLICK, farmClick1);
var startTime: Date = new Date();
var startSec: Number = startTime.seconds;
function farmClick1(e: MouseEvent): void {
addChild(menu);
menu.x = 400;
menu.y = 90;
menu.buyCornBtn.addEventListener(MouseEvent.CLICK, buyCorn1);
}
function buyCorn1(e: MouseEvent): void {
var startTime: Date = new Date();
startSec = startTime.seconds;
menu.buyCornBtn.addEventListener(Event.ENTER_FRAME, cornloading1);
farmSlot1.progressB.visible = true;
menu.buyCornBtn.removeEventListener(MouseEvent.CLICK, buyCorn1);
removeChild(menu);
}
function cornloading1(event: Event): void {
var now: Date = new Date();
var hr: Number = now.hours;
var min: Number = now.minutes;
var sec: Number = now.seconds;
var finished: Number = startSec + 5
var percent = Math.round((finished-sec) * 100)
if(sec < finished){
farmSlot1.loader_txt.text = percent
Object(root).farmSlot1.progressB.bar.scaleX = percent;
trace("hit");
}else if (sec == finished && farmSlot1.currentLabel != "corn") {
removeEventListener(Event.ENTER_FRAME, cornloading1);
trace("It did it");
farmSlot1.loader_txt.text = ""
farmSlot1.gotoAndStop("corn");
}
}
At first, as I see you are writing the code inside Flash frames. Incapsulating your code within classes is better approach which allows to avoid tons of problems in the future. Here is a link described some basic approaches for using classes:
http://www.kirupa.com/developer/as3/classes_as3_pg1.htm
In answer to your question:
You can simply use flash.utils.Timer class instead of using Date and ENTER_FRAME event: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/Timer.html
Some piece of code:
//Import timer class
import flash.utils.Timer;
...
//In the class's body
//Create a timer instance. Timer will be executed 10 times every 100 milliseconds
private var timer:Timer = new Timer(100, 10);
...
//Somewhere in class's method (usually in the constructor)
timer.addEventListener(TimerEvent.TIMER, timerHandler);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, timerCompleteHandler);
//Add click handler
button.addEventListener(MouseEvent.CLICK, buttonClickHandler);
...
private function buttonClickHandler(event:MouseEvent):void
{
//Do some stuff and start timer.
timer.start();
}
private function timerHandler(event:TimerEvent):void
{
//Update progress indicator
}
private function timerCompleteHandler(event:TimerEvent):void
{
//1 second is over so do some stuff.
}

How to remove all of one class of children from screen in Flash CS4 AS3?

Ok, so I've been stuck on this for about three hours now and I finally feel like asking for help.
Basically, I am trying to remove all instances of an enemy object from the screen when my player ship makes contact with one of them, as he then loses a life and is put back into a safe position on the screen.
EDIT: This is all the code from my Enemy Dude .as file, a bit overboard maybe but nonetheless.
package
{
import flash.display.MovieClip;
import flash.events.*;
import flash.media.Sound;
import flash.media.SoundChannel;
public class Enemydude extends MovieClip
{
private var _root:Object;
private var speed:int = 6;
private var shipps = this
public function Enemydude()
{
addEventListener(Event.ADDED, beginclass);
addEventListener(Event.ENTER_FRAME, entFrame);
}
private function beginclass(event:Event):void
{
_root = MovieClip(root);
}
private function entFrame(event:Event):void
{
x -= speed;
if(this.x < -64)
{
removeEventListener(Event.ENTER_FRAME, entFrame);
_root.removeChild(this)
}
if(_root.gameover)
{
x = -700
removeEventListener(Event.ENTER_FRAME, entFrame);
removeEventListener(Event.ADDED, beginclass);
}
for (var i:int = 0; i<_root.playerBulletContainer.numChildren; i++)
{
var bulletTarget:MovieClip = _root.playerBulletContainer.getChildAt(i)
if (hitTestObject(bulletTarget))
{
removeEventListener(Event.ENTER_FRAME, entFrame);
_root.removeChild(this);
_root.playerBulletContainer.removeChild(bulletTarget);
bulletTarget.removeListeners();
_root.Score += 10
makeExplosion();
}
}
if(hitTestObject(_root.mcship))
{
makeExplosion();
shipPos();
removethis();
}
}
private function makeExplosion()
{
var sndExplode:snd_explosion1;
var sndExplodeChannel:SoundChannel;
sndExplode=new snd_explosion1();
sndExplodeChannel=sndExplode.play();
var newExplosion01:explosionEffect=new explosionEffect ;
newExplosion01.x=this.x;
newExplosion01.y=this.y;
_root.explosionContainer.addChild(newExplosion01);
}
private function shipPos()
{
_root.lives -= 1;
_root.mcship.x = 80;
_root.mcship.y = 225;
for each(var i:Enemydude in _root.enemies)
{
removethis();
}
_root.enemies.length = 0;
}
public function removethis():void
{
if(parent) parent.removeChild(this)
removeEventListener(Event.ENTER_FRAME, entFrame);
}
}
}
EDIT: And this is the code I now have that relates to the Enemydude in my main timeline, quite sorry about all this.
var enemies:Array = [];
var Shipheight:Number = 300;
var Enemytime:int = 0;
var Enemylimit:int = 16;
if (Enemytime<Enemylimit)
{
Enemytime ++;
}
else
{
var newEnemy01 = new Enemydude();
newEnemy01.y = Shipheight;
newEnemy01.x = stage.stageWidth + 64;
addChild(newEnemy01);
enemies.push(newEnemy01);
Enemytime = 0
function shipY(event:Event):void
{
Shipheight = Math.ceil(Math.random()* 250) + 80;
}
Thank you for your help in advance, any advice is appreciated.
I suggest storing your enemies in an Array.
For example, create the array enemies:
var enemies:Array = [];
And then amend your code to:
else
{
var newEnemy01 = new Enemydude();
newEnemy01.y = Shipheight;
newEnemy01.x = stage.stageWidth + 64;
addChild(newEnemy01);
enemies.push(newEnemy01);
Enemytime = 0;
}
That way you can remove all of the enemies using this new array:
for each(var i:Enemydude in enemies)
{
i.remove(); // Or whatever function Enemydude has to remove itself.
}
// Empty the enemies Array.
enemies.length = 0;
Here's the .remove() method you could make for Enemydude:
public function remove():void
{
if(parent) parent.removeChild(this);
// Remove any event listeners etc from this object.
}
A common and easy way of doing this is to create a subcontainer to hold the objects and destroy this object instead. It makes easy for some collision checks too, since you can use the holder object to make one check against the player.
If you don't want to create this, you can use an array or a vector to store references to this objects, what makes easy to traverse the list.
I persoally recommend the vector aprouch:
var enemyList:Vector.<Enemy> = new Vector.<Enemy>();
Then you can loop almost like an array (as Marty Wallace showed on his answer):
for each(var e:Enemy in enemyList) {
container.removeChild(e);
}
enemyList.length = 0; // empty vector
Vectors are a bit slower than normal arrays, but are type safe. The difference in performance is almost negligible in most cases.

AS3:Calling a switch case from another class does't work

i am making a game in flash and the problem that i am having is with two classes a class called Menu for the welcome screen which has a startgame button and the engine class which runs everything when i run the game for the first time i set the menu to appear automatically by this code:
public var state:int;
public const MENU:int = 0;
public const GAME:int = 1;
// create the variable for the menu
private var _menu:Menu;
public var sBg1:ScrollBg;
public var sBg2:ScrollBg;
public function Engine(menu:Menu)
{
_menu = menu;
//we add event listener when the engine is added to the stage
addEventListener(Event.ADDED_TO_STAGE, onAdded);
}
private function onAdded(e:Event):void {
//then we remove the event listener and initiate the init function
removeEventListener(Event.ADDED_TO_STAGE, onAdded);
init();
}
private function init():void {
//the init function set the game state at first to menu and run the drawUI function
state = MENU;
drawUI();
}
public function drawUI():void
{
//the drawUI function draw the needed elements on stage according to the state of the game
switch(state){
case MENU:
_menu = new Menu();
addChild(_menu);
break;
case GAME:
sBg1= new ScrollBg();
addChild(sBg1);
sBg1.x = 0;
sBg1.y = 0;
//if(contains(_menu)){
//removeChild(_menu);}
trace('this the game');
break;
}
}
and i change the state from menu to the actual game using this code in the menu class:
public var start_btn:MovieClip;
private var _engine:Engine;
public function Menu()
{
addEventListener(Event.ADDED_TO_STAGE, displayMenu);
}
private function displayMenu(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, displayMenu);
start_btn = new startBtn();
start_btn.x = 100;
start_btn.y = 200;
addChild(start_btn);
start_btn.addEventListener(MouseEvent.CLICK, startGame);
}
private function startGame(e:MouseEvent):void
{
start_btn.removeEventListener(MouseEvent.CLICK, startGame);
_engine = new Engine(this);
_engine.state = 1;
_engine.drawUI();
}
i use the drawUI function each time for the menu for example it places the start button and for the game it places the background but for some reason i only get the trace statement saying (this the game) but the background is not displayed any clues .
i spend more then 4 hours trying to find out what is the problem and i still can't if anyone can help me that would be great.
Thanks
If you see the trace but nothing on screen that is most likely because the ScrollBg class doesn't have anything to display. Make sure that class has some sprites or images in it.

Making Timers available for GC?

In a function that creates a new timer every time it is called, is this the correct way to dispose of it?
private var _timers:Vector.<Timer> = new Vector.<Timer>;
private var _timer:Timer
private function timer():void
{
_timer = new Timer(10000, 1);
_timers.push(_timer);
_timer.addEventListener(TimerEvent.TIMER_COMPLETE, onTimer, false,0,true);
_timer.start();
}
private function onTimer(e:TimerEvent):void
{
e.target.removeEventListener(TimerEvent.TIMER_COMPLETE, onTimer);
_timers[0] = null;
_timers.shift();
}
Maybe you can add a
_timers[0].stop();
Just in case your times change for whatever reason, it's best to deal with the object directly instead of assuming the Timer object is at the 0 index.
Just a small adjustment required for onTimer():
private function onTimer(e:TimerEvent):void
{
var timer:Timer = e.currentTarget as Timer;
timer.removeEventListener(TimerEvent.TIMER_COMPLETE, onTimer);
_timers.splice(_timers.indexOf(timer), 1);
}
You don't need to set the index to null and it's never good practice to assume your item will be at a specified index, always make sure. In this case you make sure by using the indexOf() method available in the Array type object (_timers).
Hope it helps.
I've made function "delay" that handles delay calls. I made it for my game in which I have used delay calls alot and I had to find a way to handle delays efficiently. Still AS3 guru's out there may still find more efficient ways, please let know if any.
public static var timer_stack:Vector.<Timer> = new Vector.<Timer>();
public static function delay(delaytime:Number, func_name:Function, repeat:Number = 1)
{
var timer:Timer = new Timer(delaytime, repeat);
timer_stack.push(timer);
timer_stack[timer_stack.length-1].addEventListener(TimerEvent.TIMER, func_name ,false,0,true);
timer_stack[timer_stack.length-1].addEventListener(TimerEvent.TIMER_COMPLETE,
function(e:TimerEvent){ delay_complete(e, func_name); });
timer_stack[timer_stack.length-1].start();
}
public static function delay_complete(e, func_name:Functio):void
{
e.target.stop();
e.target.removeEventListener(TimerEvent.TIMER, func_name);
timer_stack[timer_stack.length-1].removeEventListener(TimerEvent.TIMER_COMPLETE,
function(){ func_name_complete(e, func_name);} );
for(var i=0; i < timer_stack.length; i++)
{
if(timer_stack[i].running == true)
trace("timer # "+i+" is running");
if(timer_stack[i].running == false)
{
timer_stack[i] = null;
timer_stack.splice(i,1);
trace("remove timer # "+i);
}
}
}

AS3 question - Best way to lockout buttons

Hello and thanks for reading this.
I made buttons using as3 within flash but what I'd like to do is make them inactive for a few seconds when one is pressed. Normally I'd use google to solve this kind of a problem but I dont even know how to word it properly.
Thanks
You could :
Set the .enabled property to false in order to have your click event handlers disabled.
Add a new locking variable and surround all the code in your click handler with 'if(lockingVariable)'. Then all you would need to do is set this to false. Ideally, though, you'd just disable the button.
As for doing it for a few seconds, look into the timer class. This link should be helpful. The typical pattern goes something like this :
var myTimer:Timer = new Timer(1000, 1); // 1 second
myTimer.addEventListener(TimerEvent.TIMER, runOnce);
myTimer.start();
function runOnce(event:TimerEvent):void {
trace("runOnce() called # " + getTimer() + " ms");
}
All you would have to do is have a re-enabling callback as the method for line 2 and your button would be disabled for 1 second.
Try using this as a base class for your buttons:
package
{
import flash.display.SimpleButton;
import flash.events.MouseEvent;
import flash.events.Event;
public class MyButton extends SimpleButton
{
// vars
public const DELAY:uint = 30;
private var _timer:int = 0;
/**
* Constructor
*/
public function MyButton()
{
addEventListener(MouseEvent.CLICK, _click);
}
/**
* Called on Event.ENTER_FRAME
*/
private function _handle(e:Event):void
{
_timer --;
if(_timer < 1) removeEventListener(Event.ENTER_FRAME, _handle);
}
/**
* Called on MouseEvent.CLICK
*/
private function _click(e:MouseEvent):void
{
if(_timer > 0) return;
_timer = DELAY;
addEventListener(Event.ENTER_FRAME, _handle);
// do your stuff below
clickAction();
}
/**
* Override this and fill with your actions
*/
protected function clickAction():void
{
trace("override me");
}
}
}
Here's an example of overriding the clickAction() method in MyButton:
package
{
public class MyPlayButton extends MyButton
{
override protected function clickAction():void
{
trace("play button clicked");
}
}
}
The way I would do it is simply set the enabled property of the button to false for a set amount of time, using a Timer, once the button is pressed.
myBut.addEventListener(MouseEvent.CLICK, doStuff);
function doStuff(e:MouseEvent){
//write whatever the button does here
disableBut();
}
function disableBut(){
myBut.enabled = false;
var timer:Timer = new Timer(3000, 1);
timer.addEventListener(TimerEvent.TIMER, enableBut);
timer.start()
}
function enableBut(e:TimerEvent){
myBut.enabled = true;
}
Remember that the length of time that the button is disabled for is set in the first parameter of the Timer() constructor, and is in milliseconds. In my example you can see that myBut is disabled for 3 seconds.