this is a repost of a previous question with more info this time.
The files: 2shared.com/file/hRKhEiqh/Script_Test.html and 2shared.com/video/UZNmqzXt/a_anconeus.html
This issue is reproducible on my machine with a new .fla project in Actionscript 3.0 in Flash Professional CS5. It's an edit of my original question with more information.
I'm working on a project to load external SWF's and search through instance names for matching keywords, namely 'drag' and 'drop' to identify movieclip matches, then attach event listeners to these MC's which contain the D&D event listeners and code.
The specific problem is the switching of depths for Movieclips nested in dynamically loaded external SWF files.
Where I am having trouble is the specific commands:
swapChildrenAt, setChildIndex, swapChildren, removeChild/addChild. I've tried all four with the same problem of duplication. Let me explain.
When a draggable MC is clicked, it is moved to the top index of the dynamically loaded SWF so it's visible above everything else in that SWF. The problem is that trying any of these commands all duplicate the MC. What happens is this:
MOUSE_DOWN event fires on MC:
Index of target MC is recorded as '2', the index we will switch to is '20' (maximum index of the SWF)
setChildIndex is called on the target MC parent: mc.parent.setChildIndex(mc, (mc.parent.numChildren-1))
MC moves to index 20 then another instance of the MC is created at the layer it was located previously (index 2), this happens after the MOUSE_DOWN event finishes, I'm not sure exactly when.
This duplicate has been confirmed using the EVENT.ADDED_TO_STAGE listener attached to the stage to catch every object of MovieClip types that is added to the stage. I've inspected the SWF to confirm there's no duplicate MovieClips, the traces also confirm this.
Similar posts mention the same duplication problem but no one has a solution that I've found will work in my case.
http://www.kirupa.com/forum/showthread.php?t=359452
http://board.flashkit.com/board/showthread.php?t=775200
http://forums.adobe.com/thread/199983
As a last note, if I comment out the index swap statement, the code works perfectly with the MC simply staying on its lower z-index instead of being on top. Unfortunately that's not going to work as a solution since I'm not building the external SWF's.
To duplicate this behavior, you need an external AS3 SWF with two at least two MC's with instance names "drag01" and "drop01" or something that matches the keywords 'drag' and 'drop'. Point the String variable 'SWF' to that file and you should see the duplication problem.
Thanks and regards
Cameron
Edit: new trimmed code, copied into a blank AS 3.0 file with the same errors.
import flash.net.URLRequest;
import flash.display.Loader;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.display.MovieClip;
import flash.display.DisplayObject;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.net.URLLoader;
var swf:String = "a_anconeus.swf";
loadSWF(swf);
stage.addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStageReport, true);
stage.addEventListener ( Event.ADDED_TO_STAGE , onAddedToStageReport , true ) ;
function onRemovedFromStageReport (evt:Event)
{
{
trace("REMOVED: " + evt.target.name + " at depth: " + evt.target.parent.getChildIndex(evt.target));
}
}
function onAddedToStageReport (evt:Event)
{
{
trace("ADDED: " + evt.target.name + " at depth: " + evt.target.parent.getChildIndex(evt.target));
}
}
function onDragMouseDown(event:MouseEvent):void
{
var drag:MovieClip = MovieClip(event.target);
var topPosition:uint = drag.parent.numChildren - 1;
trace("click: "+drag.name +", ontarget = "+drag.ontarget + ", current z: " + drag.parent.getChildIndex(drag) + " new z: " + topPosition);
//drag.parent.setChildIndex(drag, topPosition);
var indexToDelete:int = drag.parent.getChildIndex(drag);
//this.parent.removeChild(this);
trace("index to delete: " + indexToDelete +", what's there: " + drag.parent.getChildAt(indexToDelete).name);
drag.startDrag();
//drag.parent.setChildIndex(drag, drag.parent.numChildren-1); //set child depth to top
trace("after change, what's there: " + drag.parent.getChildAt(indexToDelete).name);
//drag.parent.swapChildren(drag, drag.parent.getChildAt(drag.parent.numChildren -1));
}
function onDragMouseUp(event:MouseEvent):void
{
trace("mouse up: "+event.target.name + ", index: " +event.target.parent.getChildIndex(event.target));
var drag:MovieClip = MovieClip(event.target);
drag.stopDrag(); //Movieclips have simple drag methods
}
/*function dragEnterFrameHandler(event:Event):void {
var drag:MovieClip = MovieClip(event.target);
if (drag.mousedown == false)
{
if (drag.onTarget == true)
{
//send it to the drop X/Y
drag.x -= (drag.x - drag.dropon.x)/5;
drag.y -= (drag.y - drag.dropon.y)/5;
}
else if (drag.onTarget == false)
{
drag.x -= (drag.x - drag.homeX)/5;
drag.y -= (drag.y - drag.homeY)/5;
}
}
}*/
function loadSWF(filepath:String)
{
trace("calling loader");
var loader:Loader = new Loader();
var url:String = filepath;
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompleteHandler);
loader.load(new URLRequest(url));
}
function onAddedToStage ( evt:Event )
{
trace("calling onAddedToStage");
/*if (evt.target is MovieClip) //filter only movieclips
{
var mc:MovieClip = MovieClip(evt.target);
// trace ( "onAddedToStage, evt: " + mc.name + ", " +(mc.parent.numChildren-1) ) ;
if (String(mc.name).indexOf("drag") != -1)
{
var dropString:String = String(mc.name).split("drag").join("drop");
if (mc.parent.getChildByName(dropString))
{
trace("our droptarget: " + mc.dropon);
mc.addEventListener(MouseEvent.MOUSE_DOWN, onDragMouseDown);
mc.addEventListener(MouseEvent.MOUSE_UP, onDragMouseUp);
mc.buttonMode = true;
}
}
}*/
}
function onCompleteHandler(loadEvent:Event)
{
trace("load complete");
var swf:MovieClip = MovieClip(loadEvent.currentTarget.content);
//swf.addEventListener ( Event.ADDED_TO_STAGE , onAddedToStage, true ) ;
//trace("event attached, adding child");
trace("child add started");
addChild(swf);
trace("child add finished");
var children:Number = (swf.numChildren-1);
trace("children: " + children);
for (var i:Number = 0; i <= children; i++)
{
trace("LOOP STARTS HERE");
if (swf.getChildAt(i) is MovieClip)
{
//trace("MC: yes");
var mc:MovieClip = MovieClip(swf.getChildAt(i));
trace("name: " + mc.name);
if (String(mc.name).indexOf("drag") != -1)
{
var dropString:String = String(mc.name).split("drag").join("drop");
if (swf.getChildByName(dropString))
{
trace("removing: " + mc.name);
children--;
swf.removeChild(mc);
trace("removed");
//swf.addChild(mc);
/*mc.addEventListener(MouseEvent.MOUSE_DOWN, onDragMouseDown);
mc.addEventListener(MouseEvent.MOUSE_UP, onDragMouseUp);
mc.buttonMode = true;*/
}
}
}
}
trace("finish function");
}
mystery solved :)
looking at your swf I can see that it has two frames, so as soon as you start dragging, the next frame renders and the object comes back.
to test this I added swf.stop(); to yout onCompleteHandler
I can't open your sample files because I only have CS3, but I can tell you what I think is the most likely cause. When you reparent those clips and then later find they've duplicated, is there any kind of timeline playing that happens in the meantime? Like in this sample fla?
Unintentional cloning
The problem is that when you remove a movieclip from a display list into which it was published, but that display list is in a movieclip that is playing, when the clip re-plays the old frame, or in any other way "expects" the clip to be where it was when you published the fla, it just "clones" it and puts it back... or rather, it "clones" what it knows it would have been if you hadn't moved it already. That's what I've illustrated in the fla above. I re-parent the foo clip, randomly place it somewhere onstage, then when the movieclip cycles back to frame 1 it finds that "there should be a foo here, but there's not. better make one."
Related
In Adobe Flash and ActionScript 3.0, I have a movieclip within a button. I want to play the entire movie clip upon mouse over.
However, the movieclip plays only untill the mouse is over. I want to play the movie clip till the end if the mouse was there.
Any help is appreciated.
I found a blog but, it is valid for AS2 only. This is what I want to do, but with AS3 : EchoEcho
I am a noob for flash and I dont know what to share for this kind of problem. I will provide anything that is needed for solving the problem
Thanks
To make it simple...
If you have an instance named "your_mc" that contains your animation (a MC named your_symbol in the library and you have a tween in the instance named "your_mc"
If the MovieClip is placed on the stage, You may try this.
import flash.display.MovieClip;
import flash.events.MouseEvent;
var your_mc:MovieClip = your_mc;
your_mc.stop()
var clipStopped:Boolean = true;
your_mc.addEventListener(MouseEvent.MOUSE_OVER,playStopClip);
your_mc.addEventListener(MouseEvent.MOUSE_OUT,playStopClip);
function playStopClip(e:MouseEvent):void{
switch (clipStopped) {
case false:
clipStopped = !clipStopped;
break;
case true:
clipStopped = !clipStopped;
break;
}
if (!clipStopped){
your_mc.gotoAndPlay(1);
}else{
your_mc.gotoAndStop(1);
}
}
Be careful this is not Class Based, and should be considered as a basic example!
If You want something more specific, please, edit Your question!
Really basic example here:
fla file
swf file
This is not clean, so, just edit Your question if You want something more efficient please.
If you want to play the entire MovieClip, just check MC.currentFrame and MC.total frames and add a Boolean value to check this.
So the MC cannot stop before the end of the animation.
Best regards.
Nicolas
[EDIT]
This will play Your MovieClip to the end when the Mouse is over...
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.events.Event;
var isRunning:Boolean = false;
var your_mc:MovieClip = your_mc;
your_mc.stop()
var clipStopped:Boolean = true;
your_mc.addEventListener(MouseEvent.MOUSE_OVER,playStopClip);
function playStopClip(e:MouseEvent):void{
if(clipStopped && isRunning==false){
trace("is Running = " + !isRunning)
your_mc.gotoAndPlay(1);
clipStopped = !clipStopped;
isRunning = true
your_mc.addEventListener(Event.ENTER_FRAME,changeStatus);
}
}
function changeStatus(e:Event):void{
if (your_mc.currentFrame == your_mc.totalFrames){
isRunning = false;
clipStopped = true;
your_mc.gotoAndStop(1);
your_mc.removeEventListener(Event.ENTER_FRAME,changeStatus);
}
trace(your_mc.currentFrame + " / " + your_mc.totalFrames);
}
fla file
swf file
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.events.Event;
var isRunning:Boolean = false;
var your_mc:MovieClip = your_mc;
your_mc.stop()
var clipStopped:Boolean = true;
your_mc.addEventListener(MouseEvent.MOUSE_OVER,playStopClip);
function playStopClip(e:MouseEvent):void{
if(clipStopped && isRunning==false){
trace("is Running = " + !isRunning)
your_mc.gotoAndPlay(1);
clipStopped = !clipStopped;
isRunning = true
your_mc.addEventListener(Event.ENTER_FRAME,changeStatus);
}
}
function changeStatus(e:Event):void{
if (your_mc.currentFrame == your_mc.totalFrames){
isRunning = false;
clipStopped = true;
your_mc.stop();
your_mc.removeEventListener(Event.ENTER_FRAME,changeStatus);
}
trace(your_mc.currentFrame + " / " + your_mc.totalFrames);
}
fla file
swf file
No more MouseEvent.MOUSE_OUT here if you want to play Your Movie Clip to the last frame.
The MouseEvent.MOUSE_OVER is only available when Your Movie clip animation is completed.
So as You didn't give feedback and the question is unclear : "DownVote"
[/EDIT]
I am building an Adobe Air AS3 IOS and Android App, in which i have a movie clip in the center of the stage. When you start touching this movie clip, you can move it all around the stage.
This is how i'm doing so :
Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
MC_M1.alpha = 1;
MC_M1.addEventListener(Event.ENTER_FRAME, ifHitAct);
MC_M1.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin);
MC_M1.x = 0.516 * gameIntro.stageWidthToUse;
MC_M1.y = 0.75 * gameIntro.stageHeightToUse;
MC_M1.height = 0.2 * gameIntro.stageHeightToUse;
MC_M1.width = MC_M1.height / 1.4;
gameIntro.STAGE.stage.addChildAt(MC_M1,1);
function onTouchBegin(event:TouchEvent)
{
trace("TouchBegin");
if (touchMoveID != 0)
{
trace("It Did Not");
return;
}
touchMoveID = event.touchPointID;
gameIntro.STAGE.stage.addEventListener(TouchEvent.TOUCH_MOVE, onTouchMove);
gameIntro.STAGE.stage.addEventListener(TouchEvent.TOUCH_END, onTouchEnd);
}
function onTouchMove(event:TouchEvent)
{
if (event.touchPointID != touchMoveID)
{
return;
}
//trace("Moving")
MC_M1.x = event.stageX;
MC_M1.y = event.stageY;
}
function onTouchEnd(event:TouchEvent)
{
if (event.touchPointID != touchMoveID)
{
return;
}
//trace("Ending");
touchMoveID = 0;
gameIntro.STAGE.stage.removeEventListener(TouchEvent.TOUCH_MOVE, onTouchMove);
gameIntro.STAGE.stage.removeEventListener(TouchEvent.TOUCH_END, onTouchEnd);
}
When the player actually looses the game, what i am actually doing is the following :
MC_M1.removeEventListener(Event.ENTER_FRAME , ifHitAct);
MC_M1.removeEventListener(TouchEvent.TOUCH_BEGIN , onTouchBegin);
gameIntro.STAGE.stage.removeChild(MC_M1);
MC_M1.alpha = 0;
isDead = 1;
replayButToUse.x = 0.127 * gameIntro.stageWidthToUse;
replayButToUse.y = 0.91 * gameIntro.stageHeightToUse;
replayButToUse.addEventListener(MouseEvent.CLICK, gotoIntro);
This is all happening in a class called : introClassToUse.
So when the users looses, he will get a replay button, and when he clicks it, he will go back to the same class and reload everything, using the following code :
function gotoIntro(event:MouseEvent):void
{
replayButToUse.removeEventListener(MouseEvent.CLICK, gotoIntro);
replayButToUse.alpha = 0;
replayButToUse.removeEventListener(MouseEvent.CLICK, gotoIntro);
stop();
var reload:introClassToUse = new introClassToUse();
}
And so everything loads back up and the game restarts. My problem is, i'm facing a very weird behavior when i tend to replay the game more than 2-3 times. The MC_M1 just stops listening to any touch event, but keeps on listening to ENTER_FRAME events, in which i keep touching the MC_M1 but it seems to not respond to it. I even debugged it remotely from my iPhone, for the first couple of replays, i can see the trace("TouchBegin"); with it's outcome, it was showing me TouchBegin, but after a few replays, the touch events just froze. What am i missing?
Any help is really appreciated, i'm new in AS3, i need to learn so i could manage more
Edit 1 :
I have no code on any frame, i just have lots of AS Classes.
The fla file is linked to an AS Class called gameIntro. In this class, i have linked the following :
- STAGE is an object of type Stage.
- gameIntro.STAGE = stage
Later on, when the user clicks a play button, i call the class introClassToUse. This class has all the game functionalities. All the code present above is in introClassToUse. When the user looses and clicks the replay button, he will go to "goToIntro" function, im which i recall the introClassToUse.
It's all working fine, with several other timers implemented and all, the only problem is that after several replays, the MC_M1 just freezes over
I am removing the MC_M1 each time the user looses and re-add them when i call back the introClassToUse, because i tried to use the .visible property, it didn't work at all ( this is why i am using the gameIntro.STAGE.stage.removeChild(MC_M1)
I know the question is old but maybe someone is still wondering what is going on here (like me).
There are lot of problems in you code but I thing the root of your problem starts here:
function gotoIntro(event:MouseEvent):void{
//...
var reload:introClassToUse = new introClassToUse();
}
It is usually unwanted behavior if simply creating an instance does more than nothing to your program and you don't even need to assign it to variable in this case.
You mentioned this code is located in your introClassToUse class. This basically means that you are creating new instance of your game inside old one and this seem to be completely awry.
You should consider using only instance properties in your class definition and create new introClassToUse() in external classes;
You didn't include many important details about your code like
How the whole class structures look like - for example you can't place line like MC_M1.addEventListener(Event.ENTER_FRAME, ifHitAct);in the scope of your class so obviously you have this in some function and we don't know when and from where it is called.
Where and how your variables are declared, and assigned. It's hard to tell if your MC_M1 is property of an instance or a class, is it internal/public/private/...
Do you link library symbols to your classes or acquire it from stage.
There could be many things that could give you such result. Based on what you wrote I've reproduced behavior similar to what you've describe but using mouse event and a dummy loose condition. This ends the game each time you drop the mc partially outside right edge of the sage, show restart button and starts again if you click it (basically it's mostly your code). It works fine for about 10s and than suddely you can't move the mc anymore. The frame event is still tracing out but touch/mouse is not.
How can it be? I suspect that you could remove only listeners somewhere and have invisible mc stuck on the new one. And this could be easy overlooked, especially if you using static properties. Again we don't even know where is your movie clip coming from so we can only guess what is happening whit your code but I've tried to take the example simple this is how I did it. The problem may lay in some completely different place but you can guess for all scenarios.
Document class of the project - GameIntro.as
package
{
import flash.display.Sprite;
public class GameIntro extends Sprite
{
//Document class. this need to be compiled with strict mode off.
public function GameIntro() {
GameIntro.STAGE = stage;
GameIntro.stageWidthToUse = stage.stageWidth;
GameIntro.stageHeightToUse = stage.stageHeight;
var intro:IntroClassToUse = new IntroClassToUse();
stage.addChild(intro);
}
}
}
IntroClassToUse.as
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.utils.Timer;
/**
* You need to have library symbol linked to this class in .fla with two mcs -
* mcFromLibrarySymbol (dragable) and repButton (reapatButton)
*/
public class IntroClassToUse extends MovieClip
{
var t = 0; //timer ticks
var fc:uint = 0; //frames counter
var isDead = 0;
var mc;
static var repButton;
var logicContex:Timer = new Timer(30);
public function IntroClassToUse() {
trace("toUse", GameIntro.stageWidthToUse);
mc = mcFromLibrarySymbol;
if(!repButton) repButton = repButtonX;
logicContex.addEventListener(TimerEvent.TIMER, logicInterval);
logicContex.start();
init();
}
internal function init() {
trace("init");
mc.alpha = 1;
mc.addEventListener(Event.ENTER_FRAME, onFrame);
mc.addEventListener(MouseEvent.MOUSE_DOWN, onMDown);
mc.x = 0.516 * GameIntro.stageWidthToUse;
mc.y = 0.75 * GameIntro.stageHeightToUse;
mc.height = 0.2 * GameIntro.stageHeightToUse;
mc.width = mc.height / 1.4;
GameIntro.STAGE.stage.addChildAt(mc, 1);
}
internal function onLoose() {
trace("onLoose");
mc.removeEventListener(Event.ENTER_FRAME , onFrame);
mc.removeEventListener(MouseEvent.MOUSE_DOWN, onMDown);
GameIntro.STAGE.stage.removeChild(mc);
mc.alpha = 0;
isDead = 1;
repButton.x = 0.127 * GameIntro.stageWidthToUse;
repButton.y = 0.91 * GameIntro.stageHeightToUse;
repButton.addEventListener(MouseEvent.CLICK, onReplay);
repButton.alpha = 1;
}
internal function onReplay(e:MouseEvent):void {
trace("onReplay");
repButton.removeEventListener(MouseEvent.CLICK, onReplay);
repButton.alpha = 0;
stop();
new IntroClassToUse();
}
internal function onMDown(e:MouseEvent):void {
trace("mouseDow");
GameIntro.STAGE.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMMove);
GameIntro.STAGE.stage.addEventListener(MouseEvent.MOUSE_UP, onMUp);
}
internal function onMMove(e:MouseEvent):void {
mc.x = e.stageX;
mc.y = e.stageY;
}
//you loose the game if you release you mc with part of it over rigth stage edge.
internal function onMUp(e:MouseEvent):void {
trace("mouseUp");
GameIntro.STAGE.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMMove);
GameIntro.STAGE.stage.removeEventListener(MouseEvent.MOUSE_UP, onMUp);
trace("Stage:", GameIntro.STAGE.numChildren);
if (mc.x + mc.width > GameIntro.STAGE.stageWidth) onLoose();
}
internal function onFrame(e:Event):void {
trace("frames", fc++);
}
internal function logicInterval(e:TimerEvent):void {
if (t++ < 300 || !isDead) return;
init();
mc.alpha = 0;
mc.removeEventListener(MouseEvent.MOUSE_DOWN, onMDown);
isDead = 0;
}
}
}
I need to test the collision between 2 movie clips, using air for android action script 3.
Its a collision between an object and several obstacles.
My structure is the following :
The base FLA file, is linked to Action Script file called baseCode.as.
In this AS file, i create the obsctacles, using the following code :
baseCode.as :
package {
import flash.display.MovieClip;
import flash.events.Event;
import flash.geom.Point;
import Mc_MC; // Not strictly needed
public class baseCode extends flash.display.MovieClip
{
//private static var SYMBOLS:Array = new Array(MySymbol1, MySymbol2);
public var t:int = 0;
public function baseCode()
{
// Create five symbols:
for (var i:int = 0; i < 5; i++) {
trace(i);
makeSymbol();
}
}
function randomRange(minNum:Number, maxNum:Number):Number
{
return (Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);
}
public function makeSymbol():void
{
trace("IT entered makeSymbol");
// Pick a random symbol from the array:
// var symType:Class = SYMBOLS[0];
//trace(SYMBOLS[Math.random() * SYMBOLS.length]);
// Construct the new symbol:
//var Positi : Number = new Number(Math.random);
var loc:Point = new Point(randomRange(100,stage.stage.height),0);
var loc2:Point = new Point(randomRange(110,stage.stage.height),0);
//var loc:Point = new Point(10*randomRange(15, stage.width),100*randomRange(10 , stage.width));
trace("this is the starting point" , loc);
var sym:Mc_MC = new Mc_MC(1 + Math.random() *10, loc);
if( t % 2 == 0 ){
var sym2:Mc_MC2 = new Mc_MC2(15 + Math.random() *10, loc);
// Listen for the object hitting the left edge:
//sym2.addEventListener(Event.COMPLETE, remakeObject);
this.addChild(sym2);
}
sym.addEventListener(Event.COMPLETE, remakeObject);
this.addChild(sym);
t ++;
}
public function remakeObject(e:Event):void
{
e.target.removeEventListener(Event.COMPLETE, remakeObject);
//e.removeChild(sym);
//e.parent.removeChild(this.child);
// removeChild(this);
// this.removeChild(sym);
// Replace the dead symbol:
makeSymbol();
}
}
}
Mc_MC and Mc_MC2 are two Action Script file in which the obstacles are called :
Mc_MC.as :
package {
import flash.display.MovieClip;
import flash.events.Event;
import flash.geom.*;
import flash.display.Screen;
import flash.system.Capabilities;
public class Mc_MC extends MovieClip
{
public var speed:Number; // Pixels moved per frame
var valuee:baseCode;
public function Mc_MC(speed:Number, startPosition:Point)
{
this.speed = speed;
this.addEventListener(Event.ENTER_FRAME, update);
this.x = startPosition.x;
this.y = startPosition.y;
}
public function update(speed:Number)
{
var screenWidth:Number = Capabilities.screenResolutionX;
var screenHeight:Number = Capabilities.screenResolutionY;
trace("this.y" , this.y);
trace("this is the stage height" , screenHeight);
trace("this.speed" , this.speed);
if (this.y >= screenHeight - 100) { // We're at the left edge
trace("Entered if");
trace("new Starting Pos" , this.y);
this.y = stage.height;
parent.removeChild(this);
this.removeEventListener(Event.ENTER_FRAME, update);
this.dispatchEvent(new Event(Event.COMPLETE));
}
else this.y += this.speed;
}
}
}
In the base FLA file, i create the main object that will collide with all the obstacles created using Mc_MC and Mc_MC2. I create it using the following code :
Home.fla
import flash.events.*
//import flash.events.EventDispatcher.addEventListener()
import flash.display.DisplayObject;
//import flash.events.MouseEvent;
import flashx.textLayout.events.UpdateCompleteEvent;
import flash.display.MovieClip;
var offsetX:Number;
var offsetY:Number;
//var draggedObject:DisplayObject;
var my_obj:OriginalObject = new OriginalObject();
//left.addEventListener(MouseEvent.MOUSE_MOVE, drag);
//The speed of the scroll movement.
var scrollSpeed:uint = 2;
//This adds two instances of the movie clip onto the stage.
var s1:ScrollBg = new ScrollBg();
var s2:ScrollBg = new ScrollBg();
left.addEventListener(MouseEvent.MOUSE_DOWN,mouseDown);
function mouseDown(e:MouseEvent):void {
stage.addEventListener(MouseEvent.MOUSE_UP,mouseUp); //listen for mouse up on the stage, in case the finger/mouse moved off of the button accidentally when they release.
addEventListener(Event.ENTER_FRAME,myButtonClick); //while the mouse is down, run the tick function once every frame as per the project frame rate
}
function mouseUp(e:MouseEvent):void {
removeEventListener(Event.ENTER_FRAME,myButtonClick); //stop running the tick function every frame now that the mouse is up
stage.removeEventListener(MouseEvent.MOUSE_UP,mouseUp); //remove the listener for mouse up
}
right.addEventListener(MouseEvent.MOUSE_DOWN,mouseDown2);
function mouseDown2(e:MouseEvent):void {
stage.addEventListener(MouseEvent.MOUSE_UP,mouseUp2); //listen for mouse up on the stage, in case the finger/mouse moved off of the button accidentally when they release.
addEventListener(Event.ENTER_FRAME,stopDragging); //while the mouse is down, run the tick function once every frame as per the project frame rate
}
function mouseUp2(e:MouseEvent):void {
removeEventListener(Event.ENTER_FRAME,stopDragging); //stop running the tick function every frame now that the mouse is up
stage.removeEventListener(MouseEvent.MOUSE_UP,mouseUp2); //remove the listener for mouse up
}
my_obj.x = stage.width / 2;
my_obj.y = stage.height - (stage.height / 3 );
stage.addChild(my_obj);
function myButtonClick(ev:Event):void
{
trace("UPPP");
if(my_obj.x > (my_obj.width*2)){
my_obj.x = my_obj.x - 10;
trace("In the limit");
}
else {
trace("out of bounds");
}
trace("myButton has been clicked.");
}
//// This function is called when the mouse button is released.
function stopDragging(ev2:Event):void
{
trace("Down");
if(my_obj.x <= right.x){
my_obj.x = my_obj.x + 10;
}
}
How can I test the collision of the moving Mc_MC / Mc_MC2 with my_obj considering that the come from different AS files?
I am new to AS, so any help would be appreciated!
If you want to be able to collision test objects from different classes / parentage, then you need to set up your project in a way that you can gain a reference to said objects.
From the looks of it, your two objects are actually in the same class already (as your main timeline code and document class code share the same scope, so what you declare in one should be available in the other).
The only thing you are missing, is a top-level reference to your obstacle/Mc_MC. As currently you assign it to a var that is scoped to the makeSymbol function (so you only have a reference to it inside that function).
Solution
In your document class (baseCode.as) , create a top-level var to hold a reference to that obstacle: (for reference, you have a top level var called t, put this line above or below that)
private var obstacle:Mc_MC;
later in your function that instantiates the new Mc_MC (makeSymbol), assign the instance to that top level var:
obstacle = new Mc_MC(1 + Math.random() *10, loc);
addChild(obstacle);
Now you can access that obstacle var anywhere else in the main timeline or document class.
if(my_obj.hitTest(obstacle)){
}
As an aside, if you have a document class, there is no point in having code on the first frame of your main timeline as that code would work the same in your document class (though it has to be contained in a function). Here is an example of where to move main timeline code:
public class Main extends MovieClip {
public function Main():void {
//listen for the added to stage event prior to do anything display oriented
this.addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event):void {
//this is the best place to put the equivalent of timeline code (not including vars or functions, put those in the class root NOT nested here)
}
}
Hi im trying to create a very simple drag and drop game in flash and I the scene to just loop round itself so say, if ( user does this) then go back to the beginning of the scene. but when I try this the symbols that the user has moved stay to where they have moved them too rather than returning to the position they were in at the start of the scene.
Can anyone explain a way to get the symbols to return to where they were at the begining of the scene once the if statement has completed?
The following example will traverse the display list, storing symbols along with their initial positions in a Dictionary. When it's time to reset, just call the resetToOriginalPositions method, passing it the Dictionary that was created.
import flash.utils.Dictionary;
import flash.display.DisplayObject;
import flash.geom.Point;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.display.MovieClip;
var originalPositions:Dictionary;
if(!originalPositions)
{
originalPositions = collectPositions(this);
}
function collectPositions(container:DisplayObjectContainer):Dictionary
{
var positions:Dictionary = new Dictionary(true);
for(var i:int = 0; i < container.numChildren; i++)
{
var currentSymbol:DisplayObject = container.getChildAt(i);
positions[currentSymbol] = new Point(currentSymbol.x, currentSymbol.y);
// this will allow the symbols to be dragged/dropped
currentSymbol.addEventListener(MouseEvent.MOUSE_DOWN, clickHandler);
currentSymbol.addEventListener(MouseEvent.MOUSE_UP, clickHandler);
}
return positions;
}
function clickHandler(e:MouseEvent):void
{
var target:MovieClip = e.target as MovieClip;
if(e.type == MouseEvent.MOUSE_DOWN)
{
target.startDrag();
}
else
{
target.stopDrag();
}
}
function resetToOriginalPositions(positions:Dictionary):void
{
for(var currentSymbol:Object in positions)
{
var position:Point = positions[currentSymbol];
DisplayObject(currentSymbol).x = position.x;
DisplayObject(currentSymbol).y = position.y;
}
}
// this line should be called in your if statement that you already have set up
resetToOriginalPositions(originalPositions);
Marcela's answer may work for you, but just in case you would like something a little simpler...you can store the original positions on a dynamic property of each object. When the condition you require is met to go back to the original positions you can call a function that resets the current x and y positions to the original ones.
//place in frame 1
dragObject1.originalY = dragObject1.y;
dragObject1.originalX = dragObject1.x;
dragObject2.originalY = dragObject2.y;
dragObject2.originalX = dragObject2.x;
//...rest of object posisitions
function resetObjectPositions()
{
dragObject1.y = dragObject1.originalY;
dragObject1.x = dragObject1.originalX;
dragObject2.y = dragObject2.originalY;
dragObject2.x = dragObject2.originalX;
//...rest of object positions
}
//later in scene
if(condition)
{
resetObjectPositions();//make sure to run this code before going back to frame one in the scene to use the original values;
}
I'm creating a screen saver which requires a movie clip to be loaded to the stage at a random position based on the size of the screen, then fade out (which I have all of the animation within a movie clip as tweens)
I've hit a road block and can't figure out how to prevent the movie clips from overlapsing on top of each other. If anything, I'd like for them to appear at another random spot that does not cause the overlapse.
here is all of the code for my project:
stop();
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.Event;
import flash.display.Stage;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
var greystoneLogos:Array = new Array ;
var countTimeArray:Array = new Array ;
var previousLogos:Array = new Array ;
var xpoint:int;
var ypoint:int;
function getNewSymbols()
{
previousLogos = new Array ;
greystoneLogos = new Array ;
var i:int;
for (i=0; i < 3; i++)
{
greystoneLogos[i] = new GreystoneLogo1();
greystoneLogos[i].width = 100;
greystoneLogos[i].height = 60;
addSymbolToStage(greystoneLogos[i],i*2000);
}
}
getNewSymbols();
function addSymbolToStage(currentLogo:MovieClip,waitTime:int)
{
var i3:int;
var i4:int;
var logoBoundaries:Array = new Array()
var XandY:Array = new Array()
for (i3=0; i3 < greystoneLogos.length; i3++)
{
if (greystoneLogos[i3] !== currentLogo)
{
xpoint = randomRange(this.stage.stageWidth - (currentLogo.width * 4.8));
ypoint = randomRange(this.stage.stageHeight - (currentLogo.height * 6.9));
logoBoundaries = getOffDimensions(currentLogo)
for (i4=0; i4 < logoBoundaries.length; i4++)
{
XandY = logoBoundaries[i4].split(":")
while ((xpoint <= (Number(XandY[0]) + Number(currentLogo.width * 4.8)) && xpoint >= (Number(XandY[0]) - Number(currentLogo.width * 4.8))) && (ypoint <= (Number(XandY[1]) + Number(currentLogo.height * 6.9)) && ypoint >= (Number(XandY[1]) - Number(currentLogo.height * 6.9)))){
xpoint = randomRange(this.stage.stageWidth - (currentLogo.width * 4.8));
trace(XandY[0] + " And " + (Number(currentLogo.width * 4.8)))
trace(xpoint + " And " + (Number(XandY[0]) + Number(currentLogo.width * 4.8)))
ypoint = randomRange(this.stage.stageHeight - (currentLogo.height * 6.9));
}
}
}
else
{
continue;
}
}
previousLogos.push(currentLogo);
currentLogo.x = xpoint;
currentLogo.y = ypoint;
stage.addChild(currentLogo);
currentLogo.gotoAndStop(1);
var countTime:Timer = new Timer(waitTime,1);
countTime.addEventListener(TimerEvent.TIMER, function(){
currentLogo.gotoAndPlay(1);
currentLogo.addFrameScript ( currentLogo.totalFrames - 1 , function(){
currentLogo.stop()
stage.removeChild(currentLogo)
if(stage.numChildren <= 1){
getNewSymbols();
}
}) ;
});
countTime.start();
}
function getOffDimensions(currentLogo:MovieClip){
var i3:int;
var tempArr:Array = new Array()
for (i3=0; i3 < greystoneLogos.length; i3++)
{
if (greystoneLogos[i3] !== currentLogo){
tempArr[i3]=greystoneLogos[i3].x +":"+ greystoneLogos[i3].y
}
}
return tempArr
}
function randomRange(max:Number, min:Number = 0):Number
{
return Math.random() * (max - min) + min;
}
There are also may be a handful of unused variables from multiple things I've been trying out.
The code that I posted, will make the movie clip appear at a random spot based on the last movie clip that came up. So let's say we have 3 movie clips (the user will be able to change how many of the clips get displayed) 1 appears at 0,0 the other at 400,400 and the last one appears at 10,10 because I have no way of saving the previous values to compare in the while loop.
I hope this clarifies it a tad more
EDIT:
Based on a function shown below, I've added this:
for (i3=0; i3 < greystoneLogos.length; i3++)
{
if (greystoneLogos[i3] !== currentLogo && greystoneLogos[i3] != null)
{
while(currentLogo.hitTestObject(greystoneLogos[i3]) == true){
xpoint = randomRange(this.stage.stageWidth - (currentLogo.width));
ypoint = randomRange(this.stage.stageHeight - (currentLogo.height));
i3 = 0
}
}else{
continue;
}
}
Which results in a rather bad loop as well as the logo's still overlap above each other
The quickest way I can think to solve this is to do a hit test (http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObject.html#hitTestObject()) on the new MovieClip and if it returns true, run the placement code again
Ok, here's the implementation of this quickest way.
You can track your present displayObject by the .numChildren property. You don't even need an array of your logos or things. Let's say you have a function that adds new movieClip to your screen. It knows how many clips you can have (MovieClipDummy is just my testing class - it draws a circle with a specified radius. It should be replaced by your objects).
private function addAnotherMovieClip(): void {
if (_currentDummmiesCount < _dummmiesCount) {
var newDummy: MovieClipDummy = new MovieClipDummy(90);
addChild(newDummy);
//If we get a stackoverflow error (see below)
//we just remove our object from the screen as it will most likely just won't fit
if (checkForEmptySpace(newDummy) != "") {
removeChild(newDummy);
return;
}
} else {
//Do nothing or do something
}
}
It calls another function, checkForEmptySpace, which tries to place your movieclip so it won't overlap with other objects. Here it is:
private function checkForEmptySpace(newClip: Sprite): String {
//you should store your screen width somewhere.
//you can also call stage.stageWidth instead, but first make sure that you
//always have a link to the stage or it will throw an error
newClip.x = Math.random() * _screenWidth;
newClip.y = Math.random() * _screenHeight;
//===========================
//Important part - we try to check all the present children of our container
//numChildren is a property of the DisplayObjectContainer
for (var i: int; i < numChildren; i++) {
//We need a try here because we will get a StackOverflow error if there's no empty space left
try {
//We need to check if our current display object, received with getChildAt()
//is not the same as the one we've just added to the screen
//And if our new object intersects with ANY other object on the stage - we
//call THIS function once again.
//We do recursion because we can easily catch an error and remove this object from
//the screen
if (newClip != getChildAt(i) && newClip.hitTestObject(getChildAt(i))) {
//If our recursive function returns an error - we should pass it further
if (checkForEmptySpace(newClip) != "") {
return "error";
}
}
//The only error that can go here is stackoverflow error. So when we get one
//we return this error string
} catch (error: Error) {
trace(error);
return "error";
}
}
//We only return this empty string if we don't have stackoverflow error
//so there's possibly no space left for another movieclip
return "";
}
You can do it without recursion, but you will have to check for empty space with another logic.
And, you can do it more "professionally" by using Minkowski addition. You should consider storing an array of "boundary" points of your movieclips (let's say every movieclip is a rectangle) and when you add a new object to the screen, you calculate this Minkowsky addition. It will have some "free" spots on your screen which represent any possible coordinates of your new movieclip. It's pretty interesting to implement something like that because the accuracy will be phenomenal. But if you don't have time - just use that recursive placement function