Control loaded swish animation in AS 3.0 - actionscript-3

I'm developing an AS 3.0 wrapper to add some extra stuff that has to load some old and plain frame to frame SwishMax 3 animations and then be able to stop them, play them, and so...
Here is my code:
package {
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.display.Loader;
import flash.display.MovieClip;
import flash.net.URLRequest;
import flash.events.*;
[SWF(backgroundColor="#ffffff", frameRate="17", width="300", height="250")]
public class SwishMaxWrapper extends Sprite {
function SwishMaxWrapper() {
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
addChild(loader);
var request:URLRequest = new URLRequest("swishy.swf");
loader.load(request);
}
private function completeHandler(event:Event):void {
var movie:MovieClip = event.target.content;
movie.stop();
}
}
}
The animation load works as expected but the movie.stop() doesn't. What is wrong?

I tested your code and it works on my machine. The SWF that I loaded had its animation in the main timeline. Is it possible that the swishy.swf has animation that is not on the main timeline? Perhaps the animation is in another symbol instead, and an instance of that symbol is on the stage. Anyway, when you call stop() in your code above, it's just telling the main timeline to stop, but other movie clips on the stage will keep on going.
I think that's what Simsoft was pointing out.
I tested your code using a SWF that had a symbol on the stage that had animation in it, and I got the problem that you are describing. I fixed it by modifying completeHandler() as follows:
public function completeHandler(event:Event):void {
var movie:MovieClip = event.target.content;
movie.stop(); //doesn't work - main timeline is only one frame long
for(var i:int = 0; i<movie.numChildren; i++) {
var child:MovieClip = movie.getChildAt(i) as MovieClip;
if(child) { //need this test - if the cast to MovieClip fails, child will be null
child.stop(); //works
}
}
}
Hopefully you don't have more animations nested at deeper layers. If that's the case, you'll have to modify this to keep peering into the children of each child and trying to stop their timelines as well.
Anyway, hope that helps. Good luck!

stop() isn't recurive, I think the problem is here.
function ruleThemAll(target : DisplayObjectContainer, doStop : Boolean = true) : void
{
for(var i : uint = 0; i < target.childNum; ++i)
{
var child : DisplayObject = target.getChildAt(i);
// If it's a container, go into to stop children
if(child is DisplayObjectContainer)
ruleThemAll(child as DisplayObjectContainer, doStop);
if(child is MovieClip)
{
if(doStop)
MovieClip(child).stop();
else
MovieClip(child).play();
}
}
}

Related

Unable to addChild on MouseCoordinations

What i am trying to do is, to place a new tower each time on MouseX and MouseY. but it seems it isn't working Any Idea guys?
or if you can create a tileMap array and add new child of PrototypeTower each time when we click on the Tower (on x=50, y=400) to select and place wherever we want. When i click the the box at x=50, y=400, the startDrag() doesn't work.
Main.as
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.ui.Mouse;
public class Main extends Sprite
{
private var pTower:PrototypeTower = new PrototypeTower;
private var zTower:PrototypeTower = new PrototypeTower;
private var fTower:PrototypeTower = new PrototypeTower;
public function Main()
{
pTower.x = 50;
pTower.y = 400;
addChild(pTower);
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
private function onAddedToStage(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
pTower.addEventListener(MouseEvent.CLICK, onClicked);
}
private function onClicked(e:Event):void
{
removeEventListener(MouseEvent.CLICK, onClicked);
zTower.x = mouseX;
zTower.y = mouseY;
addChild(zTower);
zTower.startDrag();
addEventListener(MouseEvent.CLICK, onPlaced);
}
private function onPlaced(e:Event):void
{
removeEventListener(MouseEvent.CLICK, onPlaced);
zTower.stopDrag();
fTower.x = mouseX
fTower.y = mouseY;
addChild(fTower);
}
}
}
PrototypeTower.as
package
{
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.events.Event;
public class PrototypeTower extends MovieClip
{
public function PrototypeTower()
{
this.graphics.beginFill(0x00FF00);
this.graphics.drawRect(this.x, this.y, 20, 20);
this.graphics.endFill();
}
}
}
Thank you, i am totally noob, wondering around from days!
Sorry this is just a schematic for now. I'll try to refine it later if you need. Hopefully this clears some things up for you though
When you click the tower, add a new tower at the x,y of the mouse and do some sort of startDrag(tower) on the new tower you just added. Then when you click on the stage, stop the drag and set the new X,y
edit
You might try getting rid of all your removeEventListener calls
I think your problem is you are removing the event listener that gets added in your main function. Keep in mind that the main function (class constructor) for the document class only gets called once, so you add an event listener for ADDED_TO_STAGE only once, and then you remove it the first time you try to add anything to the stage, and you never put it back. Just don't remove it in the first place.
You are calling zTower.startDrag() before you add it to the stage. Do addChild(zTower) and then zTower.startDrag()

How would I play a sound when the collision occurs?

I am new to flash and using as3. I am in the process of making a simple catching game where the items fall from the top and you control a basket at the bottom to catch them. My script is fine and is playing without erros throughout which I am happy about, but how would I add a sound clip to this script to play when the item lands in the basket? Thanks in advance!!!
import flash.events.MouseEvent;
import flash.events.Event;
import flash.text.TextField;
var catcher:Catcher;
var createEnemyID:uint;
var gameSpeed:uint;
var droppedText:TextField;
var caughtText:TextField;
var score:uint=0;
function initGame():void{
catcher=new Catcher();
catcher.x=500;
catcher.y=1400;
addChild(catcher);
stage.addEventListener(MouseEvent.MOUSE_MOVE,moveCatcher);
Mouse.hide();
gameSpeed=500;
createEnemyID=setInterval(createEnemy,gameSpeed);
droppedText=new TextField();
droppedText.x=50;
droppedText.y=50;
addChild(droppedText);
caughtText=new TextField();
caughtText.x=250;
caughtText.y=50;
addChild(caughtText);
droppedText.text=caughtText.text='0';
}
function moveCatcher (e:MouseEvent):void{
catcher.x=this.mouseX;
e.updateAfterEvent();
}
function createEnemy():void{
var enemy:Faller=new Faller();
enemy.y=-1;
enemy.x=Math.random()*stage.stageWidth;
enemy.addEventListener (Event.ENTER_FRAME, dropEnemy);
addChild(enemy);
}
function dropEnemy(e:Event):void{
var mc:Faller=Faller(e.target);
mc.y+=15;
if(mc.hitTestObject(catcher)) {
caught(mc);
}
else if (mc.y>stage.stageHeight){
dropped(mc);
}
}
function caught(mc:Faller):void{
mc.removeEventListener (Event.ENTER_FRAME,dropEnemy);
removeChild(mc);
caughtText.text=String(Number(caughtText.text)+1);
}
function dropped(mc:Faller):void{
mc.removeEventListener (Event.ENTER_FRAME,dropEnemy);
removeChild(mc);
droppedText.text=String(Number(droppedText.text)+1);
if(droppedText.text=='5'){
gameOver();
}
}
function gameOver():void{
score=Number(caughtText.text);
stage.removeEventListener(MouseEvent.MOUSE_MOVE,moveCatcher);
removeChild(catcher);
clearInterval(createEnemyID);
removeChild(caughtText);
removeChild(droppedText);
while(numChildren>0){
getChildAt(0).removeEventListener(Event.ENTER_FRAME,dropEnemy);
removeChildAt(0);
}
Mouse.show();
gotoAndStop('gameover');
}
initGame();
import the sound into flash.
edit the properties and set the class of the sound to MySoundClass or whatever you like but you have to reference it later.
In your code write the following in the collision method.
var sound:Sound = new MySoundClass();
sound.play();
See this AS3 Sound tutorial

Actionscript 3.0, error with hitTestObject

I'm getting an error I can't seem to fix. I think I know kind of what is going on but I'm not sure enough to be able to fix it. I keep getting error
"TypeError: Error #2007: Parameter hitTestObject must be non-null.
at flash.display::DisplayObject/_hitTest()
at flash.display::DisplayObject/hitTestObject()"
Basically I fire an attack in my game. It hits an enemy and he is killed just fine. BUT, he has an animation as he dies that takes a couple seconds. It seems if I fire another attack during his animation, my attack IMMEDIATELY gives this error (before striking anything, that is). Once the animation is over, everything is fine again. Also, the game was working 100% fine before I put in this animation.
Here is my document class
package com.classes
{
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.Event;
public class DocumentClass extends MovieClip
{
// we need to keep track of our enemies.
public static var enemyList1:Array = new Array();
// moved stickobject1 to a class variable.
private var stickobject1:Stickman2;
public function DocumentClass() : void
{
//removed the var stickobject1:Stickman2 because we declared it above.
var bg1:background1 = new background1();
stage.addChild(bg1);
stickobject1 = new Stickman2(stage);
stage.addChild(stickobject1);
stickobject1.x=50;
stickobject1.y=300;
//running a loop now.... so we can keep creating enemies randomly.
addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
}
//our loop function
private function loop(e:Event) : void
{
//run if condition is met.
if (Math.floor(Math.random() * 90) == 5)
{
//create our enemyObj1
var enemyObj1:Enemy1 = new Enemy1(stage, stickobject1);
//listen for enemyObj1 being removed from stage
enemyObj1.addEventListener(Event.REMOVED_FROM_STAGE, removeEnemyObj1, false, 0, true);
//add our enemyObj1 to the enemyList1
enemyList1.push(enemyObj1);
stage.addChild(enemyObj1);
}
}
private function removeEnemyObj1(e:Event)
{
enemyList1.splice(enemyList1.indexOf(e.currentTarget), 1);
}
}
}
And here is my attack1 class
package com.classes {
import flash.display.MovieClip;
import flash.display.Stage;
import com.senocular.utils.KeyObject;
import flash.ui.Keyboard;
import flash.events.Event;
public class attack1 extends MovieClip {
private var stageRef:Stage;
private var bulletSpeed:Number = 16;
public function attack1 (stageRef:Stage, x:Number, y:Number) : void
{
this.stageRef = stageRef;
this.x = x;
this.y = y;
addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
}
private function loop(e:Event) : void
{
//move bullet up
x += bulletSpeed;
if (x > stageRef.stageWidth)
removeSelf();
for (var i:int = 0; i < DocumentClass.enemyList1.length; i++)
{
if (hitTestObject(DocumentClass.enemyList1[i].hit))
{
trace("hitEnemy");
removeSelf();
DocumentClass.enemyList1[i].takeHit();
}
}
}
private function removeSelf() : void
{
removeEventListener(Event.ENTER_FRAME, loop);
if (stageRef.contains(this))
stageRef.removeChild(this);
}
}
}
Don't think you should need any other of my classes to figure out what's going on, but let me know if you do! Thanks very much =)
You don't want to do a hit test against any object that may have been removed from the scene (or from the enemyList array). The extra condition added to attack1.loop's for loop should get rid of your error. A better fix is to splice out the items you remove, so they are never tested against in the loop.
The break line will make it stop trying to hit other enemies after the bullet is removed. If the line "DocumentClass.enemyList1[i].takeHit();" removes the item from the enemyList1, you need to make sure you use "i--;" at the bottom of the loop as well, if you plan on looping through the remainder of the enemies. "i--" or "break", you will probably need one of them in that loop.
Double check the order in which you are executing your removal methods. Sometimes it's better to flag the items for removal and remove them in a separate loop than to remove an item that may be needed later in the same loop.
for (var i:int = 0; i < DocumentClass.enemyList1.length; i++){
if(DocumentClass.enemyList1[i] && DocumentClass.enemyList1[i].hit){
if (hitTestObject(DocumentClass.enemyList1[i].hit)){
trace("hitEnemy");
removeSelf();
DocumentClass.enemyList1[i].takeHit();
break;
}
}
}
Not the correct solution in this question. You can always do != null in a conditional statement.
if(object!=null){
party.drink();
}

How many images I need to have more fluently animation(Actionscript);

I have an onEnterFrame event:
package {
import flash.display.MovieClip;
import flash.display.Loader;
import flash.events.Event;
import flash.net.URLRequest;
import flash.display.BitmapData;
import flash.geom.Matrix;
import flash.errors.IOError;
public class Ball extends MovieClip {
private var images:Array;
private var frames:Array;
var i:int = 0;
public function Ball(images:Array) {
this.images = images
frames = new Array();
images.forEach(function(current){
trace(current);
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadCompleted);
loader.load(new URLRequest(current));
});
}
private function onLoadCompleted(e:Event):void{
frames.push(e.currentTarget.content);
i++;
if(i == images.length)
{
ready();
}
}
private function ready():void{
i = 0;
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(e:Event):void{
graphics.clear();
var bitmapData:BitmapData = frames[i].bitmapData;
graphics.beginBitmapFill(bitmapData, new Matrix(), false, true);
graphics.drawRect(0, 0, 100, 100);
graphics.endFill();
i++;
if(i == frames.length)
{
i = 0;
}
}
}
}
this class is getting an array of images and then animates it, and this is my main class:
public class Test extends MovieClip {
private var ball:Ball;
public function Test()
{
var images:Array = new Array();
for(var i:int = 1; i < 21; i++)
{
images.push('ball' + i.toString(10) + '.png');
}
ball = new Ball(images);
addChild(ball);
}
}
so as you see I am passing an array of 20 images, so the question is how many images I need to make a good animation, not roughly, but smoothly, creating every time a new image like ball1.png, ball2.png, ball3.png, ball4.png - I need to move the ball pixel by pixed to make a good animation? or is there a better way to do this?
It depends upon your perception and device and what you want to visualize from your content.
Please refer to this site:
http://www.mathworks.com/help/toolbox/mupad/plot/INTRO_FramesAndTimeRange.html
First thing I would consider is the framerate. There is no point in having more images as your framerate.
Basically for a smooth animation 30 fps should be ok. Also if you consider this for mobile devices I think you should not go higher than 30fps in order to have a good performance.
Regarding the number of images and how to animate them, I suggest you have a look into this game tutorial (Hungry Hero)
http://www.hsharma.com/tutorials/starting-with-starling-ep-3-sprite-sheets/
http://www.hsharma.com/tutorials/starting-with-starling-ep-5-parallax-background/

AS3 MovieClip not playing consistently

So at the beginning when my SWF loads up it also loads up a sequence of animated clips like so:
var loader:Loader = new Loader();
loader.load(new URLRequest("clips/clip4.swf"));
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, clip4Loaded);
And my clipLoaded function is:
private function clip4Loaded(e:Event):void {
clip4 = e.target.content as MovieClip;
}
The clip4 file being loaded in has a stop() at the first frame. Later in the game (clip4 is the "outro") I use:
clip4.gotoAndPlay(0);
clip4.addFrameScript(clip4.totalFrames - 1, clip4End);
However, the clip only seems to play about 25% of the time and all the other clips which I load the exact same way play fine. The only difference is that those clips get played fairly soon after they load which leads me to believe clip4 is being autoreleased at some point but I really have no clue.
strange - i've got a timeline-animated swf with stop(); in the first frame and the following code:
package {
import flash.display.Loader;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.net.URLRequest;
/**
*
* #author www0z0k
*/
[SWF(width='400', height='300', frameRate='30')]
public class NewClass extends Sprite {
private const URL:String = 'res/1.swf';
private var spr:MovieClip;
public function NewClass():void {
var ldr:Loader = new Loader();
ldr.contentLoaderInfo.addEventListener(Event.INIT, onloaded);
ldr.load(new URLRequest(URL));
}
private function onloaded(e:Event):void {
spr = e.target.content as MovieClip;
addChild(spr);
spr.addFrameScript(spr.totalFrames - 1, function():void { x = x == 0 ? 100 : 0; } );
spr.addEventListener(MouseEvent.CLICK, onclick);
}
private function onclick(e:MouseEvent):void {
spr.gotoAndPlay(0);
}
}
}
and it works exactly as it's written.
could you please upload your clip4.swf anywhere (or test this code with it yourself)?