My Actionsript is Skipping Frame 3 and Going Straight to Frame 4 - actionscript-3

I'm trying to make a primitive game in Flash. I'm using AS3 to build it. So far everything I have coded is working fine. Until now, I've only had 3 frames. However, I am ready to move on so I added a fourth frame. But, when I test the animation, it skips from frame 2 to frame 4. I put a trace in Frame 3 to see if Flash was even running it, and the trace executes the trace so I know Flash isn't completely ignoring Frame 3. But, I have a stop(); at the end of frame 3 and I have a stop(); on Frame 4. So, I'm not sure why Frame 3 is being skipped. The game doesn't have any tweens or actual animations so it shouldn't be anything of that sort. The only interaction is clicking on dots. I've put the code for all 4 of my frames below (I'm not sure if this is frowned upon. If it is, please tell me and I'll remove it but I'm putting it because it seems like it may be helpful). I'm also uploading a link to my .FLA file in case someone wants to see the whole thing.
Frame 1:
import flash.events.MouseEvent;
var dotList = new Array(); var level:int = 10; var invisoDotList = new Array();
var loop:int;
for(loop = 0; loop < level; loop++)
{
var dot:Dot = new Dot();
var invisoDot:InvisoDot = new InvisoDot();
var tester:Boolean = true;
var xval:int = Math.floor(Math.random()*(1+520))+14;
var looper:int = 0;
while(looper < dotList.length)
{
if(Math.abs(xval - dotList[looper].x) > 30)//minimum spacing
{
looper++;
}
else
{
looper = 0;
xval = Math.floor(Math.random()*(1+520))+14;
}
}
dot.x = xval;
dot.y = 187;
invisoDot.x = xval;
invisoDot.y = 187;
invisoDot.alpha = 0;
dotList[loop] = dot;
invisoDotList[loop] = invisoDot;
addChild(invisoDot);
addChild(dot);
}
//trace(dotList); test to ensure that dots are added to the array
button.addEventListener(MouseEvent.CLICK, hideDots);
function hideDots(e:MouseEvent)
{
for(var loop:int = 0; loop < dotList.length; loop++)
{
dotList[loop].alpha = 0;//make dots disappear
}
nextFrame();
}
stop();
Frame 2:
import flash.events.MouseEvent;
button.addEventListener(MouseEvent.CLICK, next);
function next(e:MouseEvent)
{
nextFrame();
}
stop();
Frame 3:
import flash.events.MouseEvent;
removeChild(button);
var clicks:int = -1;
//trace(dotList.length);
stage.addEventListener(MouseEvent.CLICK, clickCount);
for(var loopvar:int = 0; loopvar < dotList.length; loopvar++)
{
//trace("loop");
dot = dotList[loopvar];
invisoDot = invisoDotList[loopvar];
dot.addEventListener(MouseEvent.CLICK, onClick);
invisoDot.addEventListener(MouseEvent.CLICK, onClick);
//trace("event");
}
//trace(dotList.length);
function onClick(e:MouseEvent)
{
//e.currentTarget.alpha = .5;
for(var hitcheck:int = 0; hitcheck < dotList.length; hitcheck++)
{
if(dotList[hitcheck].x == e.currentTarget.x)
{
dotList[hitcheck].alpha = 1;
}
}
//trace("check");
}
function clickCount(e:MouseEvent)
{
clicks++;
//trace(clicks);
var numChanged:int = 0;
for(var index:int = 0; index < dotList.length; index++)//check whether the user has gotten all the dots
{
if(dotList[index].alpha == 1)
{
numChanged++;
}
}
if(numChanged == level)//if the user has gotten all the dots
{
trace("next screen for sucess");
trace(clicks);
}
else if((clicks - numChanged) >= 2)//this ends the session as soon as 2 mistakes are made
{
trace("next screen for failed number of clicks");
trace(clicks);
}
/*else if((clicks - level) >= 2)//if the user has made too many mistakes. This ends the session after the maximum number of tries have been used
{
trace("next screen too many clicks");
trace(clicks);
}*/
}
trace("end");
stop();
Frame 4:
stop();
Link to the .FLA file: https://www.dropbox.com/s/x1vim49tnz227id/Game.fla
If any of the conventions I've used in this question are wrong or frowned upon, please let me know and I'll correct them. It's been over a year since I've last posted on StackOverflow.

Does the same button instance exist on both frame 1 and 2?
If so you will end up with two click event handlers on the button on frame 2 (hideDots() and next()). If you click on the button then they both call nextFrame() which would skip frame 3.
Possible solutions:
Remove the first event listener before moving to the next frame:
button.addEventListener(MouseEvent.CLICK, hideDots);
function hideDots(e:MouseEvent)
{
for(var loop:int = 0; loop < dotList.length; loop++)
{
dotList[loop].alpha = 0;//make dots disappear
}
// Remove the event listener here:
button.removeEventListener(MouseEvent.CLICK, hideDots);
nextFrame();
}
OR
Have different instances of the button on frame 1 and 2.
You can do this by having a keyframe for the button on frame 1 and 2 - Flash will create a new instance of the button when it hits that frame.

Related

Flash AS3 AddEventListener with Parameter using loop

I have 34 buttons in my scene, if I click any of them a MovieClip will be visible and jump (gotoAndStop) to a frame based on which button I pressed.
import flash.events.Event;
import flash.events.MouseEvent;
stop();
MC.visible = false;
var btns:Array = new Array(
prov1, prov2, prov3, prov4, prov5, prov6, prov7, prov8, prov9, prov10,
prov11, prov12, prov13, prov14, prov15, prov16, prov17, prov18, prov19, prov20,
prov21, prov22, prov23, prov24, prov25, prov26, prov27, prov28, prov29, prov30,
prov31, prov32, prov33, prov34
);
for(var i:int = 0; i < 34; i++)
{
btns[i].addEventListener(MouseEvent.CLICK, function(e:Event):void{OpenDetail(i+1)});
trace(i);
}
function OpenDetail(frame:int)
{
MC.visible = true;
MC.gotoAndPlay(1);
MC.MSC.gotoAndStop(frame);
}
In the code above it should be that if I click prov1 it will open MC.MSC and goto frame 1, if I click prov2 it will open MC.MSC goto frame 2, etc.
But what really happened is when I click any of my buttons above, MC.MSC is opened but goes to frame 34.
Where did I do wrong? Any help would be very appreciated. Thanks.
Your mistake is not understanding what closure (an unnamed unbound function) is and how it works. The thing is, your i iterator goes to 34 and all the closures you create read i value from variable reference rather than use i value of the moment they were created.
Instead, you should do the following:
for (var i:int = 0; i < 34; i++)
{
btns[i].addEventListener(MouseEvent.CLICK, onClick);
}
function onClick(e:MouseEvent):void
{
// Get reference to the clicked button.
var aBut:DisplayObject = e.currentTarget as DisplayObject;
// Option 1: figure its index within the list.
var anIndex:int = btns.indexOf(aBut) + 1;
// Option 2: figure its index from the button's name.
var anIndex:int = int(aBut.name.substr(4));
// Go to the relevant frame.
OpenDetail(anIndex);
}

Animation code not fired when mouse is out Clip1 but mouse is inside clip 2

Problem:
When I move the mouse cursor out of Clip 1 but is above Clip 2, the MOUSE_OUT of Clip 1 does not work.
Expectation:
Granted that the mouse is inside Clip 2, the location of the mouse is outside of Clip 1 already, so the function mouse_out() of Clip 1 should fire the code inside it.
Full code:
I am attaching the full code so far.
import flash.display.MovieClip;
cat1.addEventListener(MouseEvent.MOUSE_OVER,mouse_over);
cat1.addEventListener(MouseEvent.MOUSE_OUT,mouse_out);
cat2.addEventListener(MouseEvent.MOUSE_OVER,mouse_over);
cat2.addEventListener(MouseEvent.MOUSE_OUT,mouse_out);
cat3.addEventListener(MouseEvent.MOUSE_OVER,mouse_over);
cat3.addEventListener(MouseEvent.MOUSE_OUT,mouse_out);
cat4.addEventListener(MouseEvent.MOUSE_OVER,mouse_over);
cat4.addEventListener(MouseEvent.MOUSE_OUT,mouse_out);
cat5.addEventListener(MouseEvent.MOUSE_OVER,mouse_over);
cat5.addEventListener(MouseEvent.MOUSE_OUT,mouse_out);
function mouse_over(e:MouseEvent)
{
squareEaseOut(e.currentTarget,["scaleX",1.5,"scaleY",1.5]);
}
function mouse_out(e:MouseEvent)
{
squareEaseOut(e.currentTarget,["scaleX",1,"scaleY",1]);
}
var iSquareEasingInterval:int;
//simple square easing, this can capture several properties to be animated
function squareEaseOut(mc:Object,vars:Array)
{
var checker:int = 0;
clearInterval(iSquareEasingInterval);
var ini:Array = new Array();
var accelNum:Number = 0;
var jerkNum:Number = 0;
var varsLength:uint = vars.length / 2;
for (var i:uint = 0; i<varsLength; i++)
{
ini[i] = mc[vars[2 * i]];
}
function animateEasing()
{
checker++;
if (compare(mc[vars[0]]+(0.25 * (vars[1] - ini[0])) / ((1 + accelNum) * (1 + accelNum)),vars[1]))
{
var end = new Date();
trace("Time lapse: "+(end - startD));
clearInterval(iSquareEasingInterval);
accelNum = 0;
jerkNum = 0;
for (var j:uint = 0; j<varsLength; j++)
{
mc[vars[2 * j]] = vars[(2 * j) + 1];
}
return;
}
for (var k:uint = 0; k<varsLength; k++)
{
mc[vars[2*k]] += (0.26 * (vars[(2*k)+1] - ini[k])) / ((1 + accelNum) * (1 + accelNum));
}
accelNum += 0.150+(jerkNum*jerkNum*jerkNum);
jerkNum += 0.09;
}
function compare(a:Number,b:Number)
{
if (vars[1]>ini[0])
{
return a>b;
}
else if (vars[1]<ini[0])
{
return a<b;
}
}
var startD = new Date();
iSquareEasingInterval = setInterval(animateEasing,20);
};
The problem is that you are calling the same method squareEaseOut when any mouse over or mouse out event occurs. Since you are moving your mouse immediately out of one Movie Clip and on to the other, the same method gets called twice, first for the mouse out (for the old movie clip) and then for the mouse over of the new Movie Clip. This will not result in correct behavior as the second call will override the first one as you are using setInterval and clearing the interval as well on every call.
While there may be multiple ways to solve this, easiest way would be to have separate methods for mouse out and mouse over, although that might lead to some code repetition. Or, you could wait for the first animation to finish and then call the other one.
You can also look at various tweening libraries available to achieve what you want, but thats not something that I would advertise here.
Hope this helps.

Flash remove child from timer

I have 25 objects of movie clip class named drone, and when i click it, after 2 seconds I want the object to disappear. I also have 25 timers named countdown. Here is what i do:
function clickHandler (event:MouseEvent):void{
event.currentTarget.hp--;
if(event.currentTarget.hp <= 0)
{
for(var i:int = 0;i<25;i++)
{
if(event.currentTarget == _drone[i])
{
countdown[i].start(); //start timer
}
}
}
}
Here is my timer:
for(var i:int = 0;i<25;i++)
{
countdown[i] = new Timer(2000);
countdown[i].addEventListener(TimerEvent.TIMER,timerHandler);
}
function timerHandler(e:TimerEvent):void {
//remove the drone I clicked
//I also dont know which drone i'm clicking
}
What should I do in the timerHandler to remove the object I clicked?
You can use Dictionary. Use the timer as key and movielcip as value.
import flash.utils.Dictionary;
var dict:Dictionary = new Dictionary();
function clickHandler (event:MouseEvent):void{
event.currentTarget.hp--;
if(event.currentTarget.hp <= 0)
{
for(var i:int = 0;i<25;i++)
{
if(event.currentTarget == _drone[i])
{
dict[countdown[i]] = _drone[i];//set the target mc here
countdown[i].start(); //start timer
break;
}
}
}
}
function timerHandler(e:TimerEvent):void {
var mc:MovieClip = dict[e.target] as MovieClip;//get the object been clicked
if (mc && mc.parent) {
mc.parent.removeChild(mc);//remove it
}
}
With minimal changes, set up an array to track the drones:
var arrayToRemove:Array = new Array();
and then in the click handler store drones to be removed in there:
arrayToRemove.push(event.currentTarget);
and in the timerHandler just remove the first element of the array:
removeChild(arrayToRemove.shift());
Since every delay is the same the order of the events and removals will be preserved. Although, it would probably be better to generalize the code using the above example and store all drones and timers in an arrays, so you can have any number of them.

addEventListener adding again and again

My pictures gallery has 8 frames. There are a few lines of AS3 on the AS3 layer in the first frame:
stop();
var picsArrayYouthVillage:Array = new Array(pic1,pic2,pic3,pic4,pic5,pic6,pic7,pic8);
for each (var pic in picsArrayYouthVillage)
{
pic.buttonMode = true;
}
for(var i = 0; i<8; i++)
{
trace("hi");
picsArrayYouthVillage[i].addEventListener(MouseEvent.CLICK, jumpToFrame);
}
function jumpToFrame(m:MouseEvent):void{
gotoAndStop(m.target.name + "_frame");
}
On the Pictures layer there are 8 frames containing pictures and thumbnail buttons (pic1,...pic8)
The problem is when I navigate using the thumbs, every time I click the first button and jumping to frame 1, the event listeners are added again.
Any ideas? Thank you all in advance.
You may check the object has the event listener or not before add event listener to it
for(var i = 0; i<8; i++) {
if (!picsArrayYouthVillage[i].hasEventListener(MouseEvent.CLICK)) {
trace("hi");
picsArrayYouthVillage[i].addEventListener(MouseEvent.CLICK, jumpToFrame);
}
}
EDIT
After I tried the code, I have found the problem,change this code too
var picsArrayYouthVillage:Array = new Array(pic1,pic2,pic3,pic4,pic5,pic6,pic7,pic8);
to
var picsArrayYouthVillage:Array;
if (picsArrayYouthVillage == null) {
picsArrayYouthVillage = new Array(pic1,pic2,pic3,pic4,pic5,pic6,pic7,pic8);
}
Remember to trace hi in the if condition. If it works, it should eight hi and only one time.

Multiple movieclips all go to the same spot; What am i doing wrong?

So I'm trying to shoot multiple bullets out of my body and it all works except I have an odd problem of just one bullet showing up and updating to set position for the new ones.
I have a move able player thats supposed to shoot and I test this code by moving the player and shooting. Im taking it step by step in creating this.
The result of tracing the bulletContainer counts correctly in that its telling me that movieclips ARE being added to the stage; I Just know it comes down to some kind of logic that im forgetting.
Here's My Code (The Bullet it self is a class)
UPDATE*
Everything in this code works fine except for I stated earlier some code seems reduntned because I've resorted to a different approaches.
BulletGod Class:
public class bulletGod extends MovieClip{
//Register Variables
//~Global
var globalPath = "http://127.0.0.1/fleshvirusv3/serverside/"
//~MovieCLips
var newBullet:bulletClass = new bulletClass();
//~Boolean
var loadingBulletInProgress:Number = 0;
var shootingWeapon:Number = 0;
//~Timers
var fireBulletsInterval = setInterval(fireBullets, 1);
var bulletFireEvent;
//~Arrays
var bulletArray:Array = new Array();
var bulletType:Array = new Array();
var bulletContainer:Array = new Array();
//~Networking
var netBulletRequest:URLRequest = new URLRequest(globalPath+"bullets.php");
var netBulletVariables:URLVariables = new URLVariables();
var netBulletLoader:URLLoader = new URLLoader();
//~Bullet Image Loader
var mLoader:Loader = new Loader();
var mRequest:URLRequest = new URLRequest();
public function bulletGod() {
//Load every bullet for every gun
//Compile data to be requested
netBulletVariables.act = "loadBullets"
netBulletRequest.method = URLRequestMethod.POST
netBulletRequest.data = netBulletVariables;
netBulletLoader.dataFormat = URLLoaderDataFormat.VARIABLES;
netBulletLoader.addEventListener(Event.COMPLETE, getBulletImages);
netBulletLoader.load(netBulletRequest);
}
private function getBulletImages(bulletImageData:Event){
//Request every bullet URL image
//Set vars
var bulletData = bulletImageData.target.data;
//Load images
for(var i:Number = 0; i < bulletData.numBullets; i++){
bulletArray.push(bulletData["id"+i.toString()]);
bulletType.push(bulletData["bullet"+i.toString()]);
//trace(bulletData["id"+i]+"-"+bulletData["bullet"+i]);
}
//All the arrays have been set start firing the image loader/replacer
var imageLoaderInterval = setInterval(imageReplacer, 10);
}
private function imageReplacer(){
//Check to see which image needs replacing
if(!loadingBulletInProgress){
//Begin loading the next image
//Search for the next "String" in the bulletType:Array, and replace it with an image
for(var i:Number = 0; i < bulletType.length; i++){
if(getQualifiedClassName(bulletType[i]) == "String"){
//Load this image
mRequest = new URLRequest(globalPath+"ammo/"+bulletType[i]);
mLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadImage);
mLoader.load(mRequest);
//Stop imageReplacer() while we load image
loadingBulletInProgress = 1;
//Stop this for() loop while we load image
i = 999;
}
}
}
}
private function loadImage(BlackHole:Event){
//Image has loaded; find which array slot it needs to go into
for(var i:Number = 0; i <= bulletType.length; i++){
if(getQualifiedClassName(bulletType[i]) == "String"){
//We found which array type it belongs to; now replace the text/url location with the actual image data
var tmpNewBullet:MovieClip = new MovieClip;
tmpNewBullet.addChild(mLoader);
//Add image to array
bulletType[i] = tmpNewBullet;
//Restart loadingBullets if there are more left
loadingBulletInProgress = 0;
//Stop for() loop
i = 999;
}
}
}
//###############################################################################################################################################
private function fireBullets(){
//If player is holding down mouse; Fire weapon at rate of fire.
if(shootingWeapon >= 1){
if(bulletFireEvent == null){
//Start shooting bullets
bulletFireEvent = setInterval(allowShooting, 500);
}
}
if(shootingWeapon == 0){
//The user is not shooting so stop all bullets from firing
if(bulletFireEvent != null){
//Strop firing bullets
clearInterval(bulletFireEvent);
bulletFireEvent = null
}
}
}
private function allowShooting(){
//This function actually adds the bullets on screen
//Search for correct bullet/ammo image to attach
var bulletId:Number = 0;
for(var i:Number = 0; i < bulletArray.length; i++){
if(bulletArray[i] == shootingWeapon){
//Bullet found
bulletId = i;
//End For() loop
i = 999;
}
}
//Create new bullet
//Create Tmp Bullet
var tmpBulletId:MovieClip = new MovieClip
tmpBulletId.addChild(newBullet);
tmpBulletId.addChild(bulletType[bulletId]);
//Add To Stage
addChild(tmpBulletId)
bulletContainer.push(tmpBulletId); //Add to array of bullets
//Orientate this bullet from players body
var bulletTmpId:Number = bulletContainer.length
bulletTmpId--;
bulletContainer[bulletTmpId].x = Object(root).localSurvivor.x
bulletContainer[bulletTmpId].y = Object(root).localSurvivor.y
//addChild(bulletContainer[bulletTmpId]);
}
//_______________EXTERNAL EVENTS_______________________
public function fireBullet(weaponId:Number){
shootingWeapon = weaponId;
}
public function stopFireBullets(){
shootingWeapon = 0;
}
}
}
BulletClass:
package com{
import flash.display.*
import flash.utils.*
import flash.net.*
import flash.events.*
public class bulletClass extends MovieClip {
public var damage:Number = 0;
public function bulletClass() {
//SOME MOVEMENT CODE HERE
}
public function addAvatar(Obj:MovieClip){
this.addChild(Obj);
}
}
}
Well ... if I may say so, this code looks quite wrong. Either something is missing from the code or this code will never make the bullets fly.
First off, you can set x and y of the new bullet directly (replace everything after "orientate this bullet from players body" with this):
tmpBulletId.x = Object(root).localSurvivor.x;
tmpBulletId.y = Object(root).localSurvivor.y;
Perhaps this already helps, but your code there should already do the same.
But to let these bullets fly into any direction, you also need to add an event listener, like so:
tmpBulletId.addEventListener(Event.ENTER_FRAME, moveBullet);
function moveBullet(e:Event) {
var movedBullet:MovieClip = MovieClip(e.currentTarget);
if (movedBullet.x < 0 || movedBullet.x > movedBullet.stage.width ||
movedBullet.y < 0 || movedBullet.y > movedBullet.stage.height) {
// remove move listener, because the bullet moved out of stage
movedBullet.removeEventListener(Event.ENTER_FRAME);
}
// remove the comment (the //) from the line that you need
MovieClip(e.currentTarget).x += 1; // move right
// MovieClip(e.currentTarget).y -= 1; // move up
// MovieClip(e.currentTarget).x -= 1; // move left
// MovieClip(e.currentTarget).y += 1; // move down
}
This example lets your bullet fly to the right. If you need it flying into another direction, just comment out the line with the "move right" comment and uncomment one of the other lines.
This is of course a very simple example, but it should get you started.
I hope this helps, and that my answer is not the wrong answer to the question.
As far as I have expirienced it you can have only one copy of MovieClip object added to specific child. Best approach is to use ByteArray for the clip source and instantiate new MovieClip and pass the ByteArray as a source. It have something to do with child/parent relation since a DisplayObject can have only one parent (and a way to detach the object from scene too).
Well i ended up writeing the whole code from scratch for a 3rd time and ran into a similar problem and just for reference to anybody else that comes to a problem thats random as this one i found that problem was likly does to a conversion error somewhere that doesn't necessarily break any compiling rules. Just that i was calling a movieclip and not the class it self.