Hello and thank you very much for looking at this. I've spent too many hours struggling.
The code below loads a slideshow of four images, along with thumbnails for those images. It works fine.
I've added a button called "invis_button", that when pressed is supposed to remove the 3 loaders that make up the slideshow, using the removeChild command for each loader.
But this is the problem, there are 3 loaders involved in the slide-show. The removeChild command successfully removes one of the loaders (named "loader3"), but not the other two ("container3", and "thumbLoader3"). It returns an error stating "access of undefined property thumbLoader3" or "Container3".
Can someone tell me why this is ? Or better still, how to make that button (invis_button) unload the entire slide-show.
var images3:Array = ["ad_bona1.jpg", "ad_bona2.jpg", "ad_darkhawk1.jpg", "ad_darkhawk2.jpg"];
var thumbX3:Number = -375;
var thumbY3:Number = 220;
var loader3:Loader = new Loader();
loader3.load(new URLRequest("assets/ad_bona1.jpg"));
addChild(loader3);
loader3.alpha = 0;
loadThumbs3();
function loadThumbs3():void
{
var thumbLoader3:Loader;
var container3:Sprite = new Sprite();
addChild(container3);
container3.buttonMode = true;
for(var i3:uint = 0; i3 < images3.length; i3++)
{
thumbLoader3 = new Loader();
thumbLoader3.load(new URLRequest("assets/thumbs/" + images3[i3]));
thumbLoader3.x = thumbX3;
thumbLoader3.y = thumbY3;
thumbX3 += 85;
container3.addChild(thumbLoader3);
thumbLoader3.addEventListener(MouseEvent.CLICK, thumbClicked3);
}
}
function thumbClicked3(event:MouseEvent):void
{
var path3:String = event.currentTarget.contentLoaderInfo.url;
path3 = path3.substr(path3.lastIndexOf("/") + 1);
loader3.load(new URLRequest("assets/" + path3));
}
///PROBLEM BELOW, button removes only "loader3" and not the other two for some reason
invis_button.addEventListener(MouseEvent.CLICK, unload_loaders);
function unload_loaders(event:MouseEvent):void{
removeChild(loader3);
removeChild(thumbLoader3);
removeChild(container3);
}
Not sure if this is the entire reason behind what you're observing... but for starters, "thumbloader3" and "container3" are scoped locally to the loadThumbs3() method, which means once you finish executing the function, Flash's handles to those objects are lost (not to mention being in an entirely different scope)... try creating class-level properties for those two. Once that's done you should be able to successfully remove them from the stage later on.
I hope that you're also properly destroying your objects, and for the sake of brevity you just chose to omit that code above.
I've edited the code you had above & put the properties into the proper scope. (the multiple copies of thumbLoader3 are now collected inside of a vector (specialized array) so that they can be properly addressed when it comes time to destroy them)
I also wrote you a proper destroy method. ;)
I haven't tried it on my own machine, but give it a spin & see how it goes.
var images3:Array = ["ad_bona1.jpg", "ad_bona2.jpg", "ad_darkhawk1.jpg", "ad_darkhawk2.jpg"];
var thumbX3:Number = -375;
var thumbY3:Number = 220;
// begin new instance properties..
// created a new property, allowing you to group (and hold on to) the multiple thumbLoaders
var thumbLoader3Vector:Vector.<Loader> = new Vector.<Loader>();
var container3:Sprite;
// end new instance properties
var loader3:Loader = new Loader();
loader3.load(new URLRequest("assets/ad_bona1.jpg"));
addChild(loader3);
loader3.alpha = 0;
loadThumbs3();
function loadThumbs3():void
{
// this is where container3 used to be declared
container3 = new Sprite();
addChild(container3);
container3.buttonMode = true;
for(var i3:uint = 0; i3 < images3.length; i3++)
{
var tPtr:int = thumbLoader3Vector.length;
thumbLoader3Vector.push(new Loader());
// this is where thumbLoader3 used to be declared & instantiated
thumbLoader3Vector[tPtr].load(new URLRequest("assets/thumbs/" + images3[i3]));
thumbLoader3Vector[tPtr].x = thumbX3;
thumbLoader3Vector[tPtr].y = thumbY3;
thumbX3 += 85;
container3.addChild(thumbLoader3Vector[tPtr]);
thumbLoader3Vector[tPtr].addEventListener(MouseEvent.CLICK, thumbClicked3);
}
}
function thumbClicked3(event:MouseEvent):void
{
var path3:String = event.currentTarget.contentLoaderInfo.url;
path3 = path3.substr(path3.lastIndexOf("/") + 1);
loader3.load(new URLRequest("assets/" + path3));
}
///PROBLEM BELOW, button removes only "loader3" and not the other two for some reason
invis_button.addEventListener(MouseEvent.CLICK, unload_loaders);
function unload_loaders(event:MouseEvent):void{
// since the thumbLoader3 Loaders are children of container3 in the display list, we need to remove them first
for(var $i:uint = 0;$i<thumbLoader3Vector.length;$i++)
{
removeChild(thumbLoader3Vector[$i]);
// also make sure you remove the listener, so that the object will be picked up by garbage collection
thumbLoader3Vector[$i].removeEventListener(MouseEvent.CLICK, thumbClicked3);
}
// and then just set the entire vector to null
thumbLoader3Vector = null;
// remove the loader3 object & set it to null
removeChild(loader3);
loader3 = null;
// remove the container3 object & set it to null
removeChild(container3);
container3 = null;
}
Related
I am having this error, not sure why it appears, i believe its something with scope problem. Because i have added Child already. I can't even remove Child, the child is added within the loop, and i am not sure how to manipulate the childs that were added within the loop from the outside(after the loop has ended).
I am trying to add the child from within the loop to a viewport, but i am demonstrating the problem with removeChild to reduce the complication. Because i am trying to locate the reason of why it is giving me this error, and trying to learn what i should do.
Thanks for your time!
for (var j:int = 5; j < somedata.length; j++)
{
if(somedata[j]){
var myLoader:Loader = new Loader();
var image:Bitmap;
var url:URLRequest = new URLRequest("http://www.rentaid.info/rent/"+somedata[j]);
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded);
myLoader.load(url);
function onImageLoaded(e:Event):void {
image = new Bitmap(e.target.content.bitmapData);
var mw:Number = bf.width*2;
var mh:Number = bf.height*1.2;
image.y = bf4.y+25;
/* if you set width and height image same with the stage use this */
image.width = mw;
image.height = mh;
var _contentHolder: Sprite;
addChild(_contentHolder);
_contentHolder.addChild(image);
}
}
removeChild(_contentHolder);
}
Edit:
function LoadImages() : void {
for (var j:int = 5; j < somedata.length; j++) {
var image:Bitmap;
myLoader = new Loader;
var urlRequest : URLRequest = new URLRequestfor ("http://www.rentaid.info/rent/"+somedata[j])
myLoader.load(urlRequest);
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, LoadComplete);
}
}
function LoadComplete(event : Event) {
_contentHolder.addChild(image);
}
Or something like this?
var loadedArray:Array = new Array();
var counter:int=0;
function loadImage():void{
var loader:Loader = new Loader();
var image:Bitmap;
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded);
loader.load(new URLRequest("http://www.rentaid.info/rent/"+somedata[counter]));
function onImageLoaded(e:Event):void {
image = new Bitmap(e.target.content.bitmapData);
loadedArray.push(e.target.content);
if(counter == somedata.length-1){
for(var i:uint = 5; i < somedata.length; i++){
image[i].x = 0 + i * 100;
addChild(_contentHolder);
_contentHolder.addChild(image[i]);
currentY += _contentHolder.height + 10;
}
}
else{
counter++;
loadImage();
You don't define _contentHolder. You also do not, currently, addChild(_contentHolder). This will be why the removeChild line is throwing an error.
Also, you do not need to addChild(image) and then add image as a child of _contentHolder. One or the other will do. In fact a DisplayObject can only be in ONE place on the display 'tree'. If you want image as a child of _contentHolder only _contentHolder.addChild(image) is necessary.
If you want all of your image instances added to the SAME _contentHolder, it would be best to declare and instantiate _contentHolder OUTSIDE the for loop; Each foor loop iteration will then be adding your images to the same Sprite object. When you remove _contentHolder, the child images will also disappear (although they will still be children of _contentHolder).
Ideally, you should not have more than one Loader operating asynchronously, as you do in your for loop. Instead of using a for loop, create a variable to track which index value you are up to and, when each image loads, increment that value and use it to check if all images are loaded. If not, load the next. This will require the Loader section of your code to be in it's own function, which gets called initially AND from onImageLoaded, if another image needs to be loaded.
The variable that tracks which index you are up to will, likewise, need to be set initially and incremented when each image loads.
In response to your edited question:
Your first new example of code does not attempt to load the NEXT image once the current image is loaded. Also, just as a tip: Function names are not normally written starting with capital letters; This prevents confusion with Class definitions.
Also your first new example of code does not call the 'LoadImages' function to initially load the first image.
Your second example looks like it should work to me. Have you actually tried this version?
The only thing I'd suggest is defining your Loader with the other variables and removing the Event.COMPLETE listener in the 'loaded' function. When adding the event listener you could also add a:
loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgress);
listener and trace out the progress of each image.
I'd also recommend adding trace statements throughout you code to see where it's getting stuck.
I am successful in loading a single image and creating it using addChild(). Now I am trying to load multiple images into a sprite "Container" using a forEach loop increasing the X value for each image so they are displayed in a row. The imageloader is referenced to linkage within an XML document. If I testrun this code, this error pops up at the point when the image is loaded and I try to removeChild() the loadBar Animation.
ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller.
at flash.display::DisplayObjectContainer/removeChild()
Here is the AS3:
private function loadBG():void {
var artGrab:Number = 0;
var artX:Number = 0;
for each (var albumData:XML in mainXML.artist[artistID].album) {
imgURL = new URLRequest(mainXML.artist[artistID].album[artGrab].art);
imgLdr = new Loader();
//if you're loading a bigger image or need a preloader
imgLdr.contentLoaderInfo.addEventListener(Event.COMPLETE,onBGLoaded);
imgLdr.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onLoading);
//add loader animation "All Loader"
ldrAnim = new AllLoader();
albumContainer.addChild(ldrAnim);
ldrAnim.x = artX;
ldrAnim.y = 200;
imgLdr.load(imgURL);
artGrab++;
artX + 481;
ldrAnim.x + 481;
}
}
private function onLoading(evt:ProgressEvent):void {
var bytesToLoad:Number = imgLdr.contentLoaderInfo.bytesTotal;
var numberLoaded:Number = imgLdr.contentLoaderInfo.bytesLoaded;
ldrAnim.progBar.scaleX = numberLoaded / bytesToLoad;
var loadedPercent = Math.round(numberLoaded / bytesToLoad * 100);
ldrAnim.progPercent.text = loadedPercent + " %";
trace("Loading..." + loadedPercent + "%");
}
private function onBGLoaded(evt:Event):void {
trace("image loaded!");
//image setup
addChildAt(imgLdr,0);
//now that its 100% loaded, you can resize it , etc.
removeChild(ldrAnim);
//use cross multiplying of fractions to maintain aspect ratio
var origW = imgLdr.contentLoaderInfo.width;
var origH = imgLdr.contentLoaderInfo.height;
trace("orig width: "+ origW + "orig height: " + origH);
//set new width
imgLdr.width = 481;
var newH:Number = 481 * origH / origW;
imgLdr.height = newH;
//may wish to do positioning AFTER resizing
imgLdr.x = stage.stageWidth / 2 - imgLdr.width / 2;
imgLdr.x = 0;
imgLdr.y = 0;
imgLdr.width = 480;
imgLdr.height = 480;
imgLdr.alpha = 1;
imgLdr.z = 0;
}
Bless you for reading this all, I don't understand what is causing this error so comments are appreciated!
You need to have an array of animations for your loaders to hold with the loaders themselves, then when another ProgressEvent.PROGRESS event will arrive, query the array for event.target index, grab corresponding animation and adjust that, and stop relying on single-valued global vars once you put a single listener onto multiple different objects!
var animations:Vector.<AllLoader>;
var loaders:Vector.<LoaderInfo>;
private function loadBG():void {
var artGrab:int=0;
var artX:int=0;
animations=new Vector.<AllLoader>();
loaders=new Vector.<LoaderInfo>;
for each (var albumData:XML in mainXML.artist[artistID].album) {
imgURL = new URLRequest(mainXML.artist[artistID].album[artGrab].art);
imgLdr = new Loader();
//if you're loading a bigger image or need a preloader
imgLdr.contentLoaderInfo.addEventListener(Event.COMPLETE,onBGLoaded);
imgLdr.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onLoading);
//add loader animation "All Loader"
ldrAnim = new AllLoader();
albumContainer.addChild(ldrAnim);
anomations.push(ldrAnim)
loaders.push(imgLdr.contentLoaderInfo); // fill the arrays
ldrAnim.x = artX;
ldrAnim.y=200;
imgLdr.load(imgURL);
artGrab++;
artX+=481;
}
}
private function onLoading(evt:ProgressEvent):void{
var bytesToLoad:Number=evt.target.bytesTotal;
var numberLoaded:Number=evt.target.bytesLoaded; // note it now refers to target of event
var index:int=loaders.indexOf(evt.target); // should be valid
var ldrAnim:AllLoader=animations[index]; // grab corresponding animation
ldrAnim.progBar.scaleX = numberLoaded/bytesToLoad;
var loadedPercent=Math.round(numberLoaded/bytesToLoad*100);
ldrAnim.progPercent.text = loadedPercent +" %";
trace("Loading..."+loadedPercent +"%");
}
Do the same trick with your onBGLoaded function yourself, as a lesson. Note, you have to retrieve imgLdr value correctly from the event.
What's happening is that you have populated the variable ldrAnim multipe times, creating a new AllLoader each time. When you call removeChild(), this works fine the first time (sort of--it will remove the last one you created, whether it matches the image that loaded or not). When you call removeChild() again, you're calling it for the same one you just removed (which is no longer a child of the object you're calling it on).
One way to fix this is to use a Dictionary and associate each AllLoader with the Loader for that image. When the COMPLETE event fires, you can then look up the Alloader based on the event's properties and remove it.
Another solution is to write a Class that wraps an AllLoader and a Loader and then handles the transition between the two itself when the Loader has finished loading.
That might look something like this:
public class LoadSwitcher extends Sprite{
protected var loader:Loader;
protected var allLoader:AllLoader;
public function loadSwitcher(url) {
super();
loader = new Loader();
var request:URLRequest = new URLRequest(url);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, switchLoaders);
allLoader = new AllLoader(loader);//assume AllLoader now has logic to watch the loader for % complete
loader.load(request);
addChild(allLoader);
}
protected function switchLoaders(e:Event):void {
removeChild(allLoader);
addChild(loader);
}
}
Then just create and position one of these for each one of your albums.
I am trying to make a object, which is a movieclip, move up and down continuously and print its y-axis value whenever it finished a move. The below code works fine.
var tweenUp:Tween = null, tweenDown:Tween = null;
function up():void {
tweenUp = new Tween(person,"y",None.easeNone,person.y,person.y+20,1,true);
tweenUp.addEventListener(TweenEvent.MOTION_FINISH, finishedUp);
}
function down():void {
tweenDown = new Tween(person,"y",None.easeNone,person.y,person.y-20,1,true);
tweenDown.addEventListener(TweenEvent.MOTION_FINISH, finishedDown);
}
function finishedUp(event:TweenEvent):void {
trace(person.y);
tweenUp.removeEventListener(TweenEvent.MOTION_FINISH, finishedUp);
tweenUp = null;
down();
}
function finishedDown(event:TweenEvent):void {
trace(person.y);
tweenDown.removeEventListener(TweenEvent.MOTION_FINISH, finishedDown);
tweenDown = null;
up();
}
up();
However, I am looking for a solution to pass a object to the callback function of listener. I try to use the way shown below but it does not work.
var tweenUp:Tween = null, tweenDown:Tween = null;
var functionFinishedUp:Function = null, functionFinishedDown:Function = null;
function up(object:MovieClip):void {
tweenUp = new Tween(object,"y",None.easeNone,object.y,object.y+20,1,true);
functionFinishedUp = finishedUp(object);
tweenUp.addEventListener(TweenEvent.MOTION_FINISH, functionFinishedUp);
tweenUp.removeEventListener(TweenEvent.MOTION_FINISH, functionFinishedUp);
tweenUp = null;
}
function down(object:MovieClip):void {
tweenDown = new Tween(object,"y",None.easeNone,object.y,object.y-20,1,true);
functionFinishedDown = finishedDown(object);
tweenDown.addEventListener(TweenEvent.MOTION_FINISH, functionFinishedDown);
tweenDown.removeEventListener(TweenEvent.MOTION_FINISH, functionFinishedDown);
tweenDown = null;
}
function finishedUp(object:MovieClip):Function {
return function(event:TweenEvent):void {
trace(object.y);
down(object);
}
}
function finishedDown(object:MovieClip):Function {
return function(event:TweenEvent):void {
trace(object.y);
up(object);
}
}
up(person);
It just goes up and then do nothing because it seems that the listener is removed just after added.
Is there any good solution to remove the listener which has parameters passing, after the listener finished its task?
Thanks in advance for any help you are kind enough to provide!
If you're looking for an easy way to remove an event listener right after the event was received, you can do this:
function listener(event:Event):void
{
// stop listening to the dispatcher for this event type
EventDispatcher(event.target).removeEventListener(event.type, arguments.callee);
// ...and do whatever else you need to do here
}
That line can be used in any event listener.
Another option would be to use Signals (https://github.com/robertpenner/as3-signals). They have an addOnce method that will only listen once and then remove themselves.
First, I advise against using object as the name of a variable! Although technically allowed it is semantically meaningless and unhelpfully similar to the reserved class name Object.
The reason your code isn't working is that you are removing the event handler immediately after adding -- before it ever has a chance to get invoked. You really don't ever have to remove the listeners, because you want them to be invoked every time the respective tweens are complete. If you insist on attaching and detaching the listener functions every iteration you'll have to remove the event listener in the listener function itself. Of course this gets rather tricky with all those closures you're creating and tossing.
In fact you don't need the closures at all, since the tween objects have a reference to the tweened object in the obj property. In addition, you only need to create one up tween and one down tween for each target person, and can then just rewind() and start() each tween back and forth. You can keep track of which tween goes with which person using a couple of Dictionary objects, which use object references as the keys.
Here's a proof of concept that generates twenty persons all with their own set of tweens -- but only two handlers are defined and neither of them are closures. I've also combined up with finishedDown and down with finishedUp:
var upTweens:Dictionary = new Dictionary();
var downTweens:Dictionary = new Dictionary();
for(var i:uint = 0; i < 20; i++) {
// Make a new Person
var person:Person = new Person();
person.y = 100;
person.x = i * 20;
addChild(person);
// Create the tweens but stop them before they can play at all
var top = person.y - 20; // Up is -y in Flash
var bottom = person.y;
var upTween:Tween = new Tween(person, "y", None.easeNone, bottom, top, 1, true);
upTween.stop();
upTween.addEventListener(TweenEvent.MOTION_FINISH, onUpFinished);
var downTween:Tween = new Tween(person, "y", None.easeNone, top, bottom, 1, true);
downTween.stop();
downTween.addEventListener(TweenEvent.MOTION_FINISH, onDownFinished);
// Associate tweens with this person, and start it up!
upTweens[person] = upTween;
downTweens[person] = downTween;
upTween.start();
}
function onUpFinished(e:TweenEvent):void {
var upTween:Tween = Tween(e.currentTarget);
var person:Person = Person(upTween.obj);
var downTween:Tween = Tween(downTweens[person]);
downTween.rewind();
downTween.start();
}
function onDownFinished(e:TweenEvent):void {
var downTween:Tween = Tween(e.currentTarget);
var person:Person = Person(downTween.obj);
var upTween:Tween = Tween(upTweens[person]);
upTween.rewind();
upTween.start();
}
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.
So, in short, my problem is this. I am using a variable which is a movieclip loaded from an external swf. I want to "spawn" multiple instances of the movieclip that all react to the same code, so for example if I say var1.x = 100, they all are at 100x. But my problem is when I run addChild(var1) multiple times(I'm not actually typing in addChild(var1) over and over, I just have it set to add them at random times), the new child just replaces the old one, instead of making multiple movieclips. Should I do something like
var var1:MovieClip
var var2:MovieClip = new var1 ?(which doesnt work for me btw, gives me errors)
Oh, heres the code, and also, I am pretty new to as3 fyi, still don't even know how arrays work, which was my second guess to the problem.
var zombieExt:MovieClip;
var ldr2:Loader = new Loader();
ldr2.contentLoaderInfo.addEventListener(Event.COMPLETE, swfLoaded2);
ldr2.load(new URLRequest("ZombieSource.swf"));
function swfLoaded2(event:Event):void
{
zombieExt = MovieClip(ldr2.contentLoaderInfo.content);
ldr2.contentLoaderInfo.removeEventListener(Event.COMPLETE, swfLoaded2);
//zombieExt.addEventListener(Event.ENTER_FRAME, moveZombie)
zombieExt.addEventListener(Event.ENTER_FRAME,rotate2);
function rotate2 (event:Event)
{
var the2X:int = playerExt.x - zombieExt.x;
var the2Y:int = (playerExt.y - zombieExt.y) * 1;
var angle = Math.atan(the2Y/the2X)/(Math.PI/180);
if (the2X<0) {
angle += 180;
}
if (the2X>=0 && the2Y<0) {
angle += 360;
}
//angletext.text = angle;
zombieExt.rotation = (angle*1) + 90;
}
playerExt.addEventListener(Event.ENTER_FRAME,spawn1);
function spawn1 (event:Event)
{
if(playerExt.y < 417)
{
var someNum:Number = Math.round(Math.random()*20);
if(someNum == 20)
{
addChild(zombieExt)
zombieExt.x = Math.round(Math.random()*100)
zombieExt.y = Math.round(Math.random()*100)
}
}
}
}
addChild() does not create new instances. It is used to add an already created instance to the display list. If you call addChild() multiple times on the same instance then you are just readding itself.
Also each instance is unique, you can not globally change the x position of an instance by changing another one of them. What you would do is as Henry suggests and add each new instance of a MovieClip into an array, then whenever you change something you can loop through the array and apply the changes to each instance.
You can not go var2:MovieClip = new var1 either since var1 is an instance and not a class.
Here's a different method of receiving loaded MovieClips, which i use when i need many copies of the item.
in the swf you are loading, give the target movieclip a linkage name in the library, for this example i will use "foo"
private var loadedSwfClass:Class
private var newZombie:MovieClip;
private var zombieArray:Array = new Array();
function swfLoaded2(event:Event):void
{
loadedSwfClass = event.target.applicationDomain.getDefinition("foo");
for(var n:int = 0; n<100; n++){
newZombie = new loadedSwfClass()
zombieArray.push(newZombie);
addChild(newZombie);
}
}
as per this tutorial
http://darylteo.com/blog/2007/11/16/abstracting-assets-from-actionscript-in-as30-asset-libraries/
although the comments say that
var dClip:MovieClip = this;
var new_mc = new dClip.constructor();
this.addChild(new_mc);
will also work.
It sounds like you might be accessing the same instance some how in your code. It would be helpful to see your code to figure this one out.
If I wanted to load in one swf files and add a MovieClip multiple times I would place it in the library of that SWF file. And then instantiate it and store it into an object pool or a hash or some list.
// after the library were finished loading
var list:Array = [];
for(var i:int=0; i<10; i++) {
var myCreation:MySpecialThing = new MySpecialThing();
addChild(myCreation);
list.push(myCreation);
}
where my library would contain a linkage to the class MySpecialThing.
Calling addChild(var1) multiple times on the same parent doesn't have any effect (unless you have added another child to the same parent in between, in which case it will change the child index and bring var1 to the top). If you call it on different parents, it will just change the parent of var1, doesn't duplicate. Call addChild(new MovieClassName()) at random times instead to add new copies of it. Use an array as suggested here to access them later.
Wow, thanks there henry, just using an array did exactly what I needed, and made things alot simpler.
when you load in using a loader you only get 1 instance, however you can do some funky reflection to determine what class type the given loader.content is, and then instantiate them using that. For Example:
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loader_completeHandler);
loader.load(new URLRequest("ZombieSource.swf"));
var classType:Class;
function loader_completeHandler(evt:Event):void
{
var loadInfo:LoaderInfo = (evt.target as LoaderInfo);
var loadedInstance:DisplayObject = loadInfo.content;
// getQualifiedClassName() is a top-level function, like trace()
var nameStr:String = getQualifiedClassName(loadedInstance);
if( loadInfo.applicationDomain.hasDefinition(nameStr) )
{
classType = loadInfo.applicationDomain.getDefinition(nameStr) as Class;
init();
}
else
{
//could not extract the class
}
}
function init():void
{
// to make a new instance of the ZombieMovie object, you create it
// directly from the classType variable
var i:int = 0;
while(i < 10)
{
var newZombie:DisplayObject = new classType();
// your code here
newZombie.x = stage.stageWidth * Math.random();
newZombie.x = stage.stageHeight * Math.random();
i++;
}
}
Any problems let me know, hope this helps.