Easy way to make a lot of buttons share a function? AS3 - actionscript-3

I am trying to do a simple light-up pegboard in flash. I have finished the general logic for 1 peg but there will be a total of 2,300 pegs and I don't want to have to add an event listener to each movieclip.
Here is my code:
import flash.events.Event;
var my_color:ColorTransform = new ColorTransform();
movieClip_1.addEventListener(MouseEvent.MOUSE_UP, fl_MouseClickHandler);
function fl_MouseClickHandler(event:MouseEvent):void
{
if (my_color.color == 0)
{
my_color.color = 0x0000FF;
event.target.transform.colorTransform = my_color;
}
else if (my_color.color == 255)
{
my_color.color = 0x00FF00;
event.target.transform.colorTransform = my_color;
}
else if (my_color.color == 65280)
{
my_color.color = 0xFF0000;
event.target.transform.colorTransform = my_color;
}
else if (my_color.color == 16711680)
{
my_color.color = 0xFFFFFF;
event.target.transform.colorTransform = my_color;
}
else if (my_color.color == 16777215)
{
my_color.color = 0x000000;
event.target.transform.colorTransform = my_color;
}
else
{
trace(my_color.color);
}
}
[

Here are 3 ways to accomplish this:
Put the code on the peg's own timeline. (or make a class file, and attach it to your peg object). This will re-use the same code for each peg instance automatically. Just take the same code you have, but use the this keyword instead of a hard reference to the movie clip:
var my_color:ColorTransform = new ColorTransform();
this.addEventListener(MouseEvent.MOUSE_UP, fl_MouseClickHandler);
function fl_MouseClickHandler(event:MouseEvent):void
{
//.....
Make a container Sprite/MovieClip and have all the pegs be the sole children of it. Then iterate over all the children of that container and attach the listener:
//loop through all children of the container and add an event listener
var i:int = container.numChildren;
while(i--){
container.getChildAt(i).addEventListener(....);
}
This is good because you don't have to give them instance names, which would be quite tedious.
Attach a click listener to a common parent of all pegs, and use the target property of the event to see if the click was on a peg.
Assuming you have right-clicked your peg library object, gone to properties and checked "export for actionscript" and given it the Class name "MyPeg", you could do this:
commonParent.addEventListener(MouseEvent.CLICK, parentClick);
function parentClick(e:Event):void {
if(e.target is MyPeg){
//it's a PEG, do something
}
}
Now, depending on how your peg object is structured, target could also refer to a child of your peg (instead of the peg itself). To avoid this if it's applicable, you can disable mouse input on the children of the peg. So on the first frame of your peg object, you could this: this.mouseChildren = false;
Now, even better (less tedious) would be to instantiate your pegs through code too. So as mentioned earlier, export your peg for actionscript in it's properties, and give it a class name ("MyPeg" for my example). Then something along these lines:
var curRow:int = 0;
var curCol:int = 0;
var totalRows:int = 25;
var totalCols:int = 92;
var startingY:int = 10;
var startingX:int = 10;
var padding:int = 2; //gap between pegs
var curPeg:MyPeg;
while(true){
//create the peg, and add it to the display.
curPeg = new MyPeg();
addChild(curPeg);
//add the click listener to this peg
curPeg.addEventListener(MouseEvent.CLICK, fl_mouseClickHandler);
//assign the position of this peg
curPeg.x = startingX + (curCol * (curPeg.width + padding));
curPeg.y = startingY + (curRow * (curPeg.height + padding));
//increment the column
curCol++;
//check if we've reached the last column in the row
if(curCol >= totalCols - 1){
//yes, so reset the column to 0 and increment the row
curCol = 0;
curRow++;
//break out of the loop if the curRow exceeds or is equal to the total rows var
if(curRow >= totalRows) break;
}
}
This way you could change your grid size simply by modifying the number assigned to totalCols and totalRows - no need to tediously move around 2300 objects in FlashPro.

One way to do it is loop through all the children of the parent of your 2300 pegs.
for (var i:int=0; i<numChildren; i++) {
var clip = getChildAt(i);
if (clip.name.indexOf('movieClip_')==0) {
clip.addEventListener((MouseEvent.MOUSE_UP, fl_MouseClickHandler);
}
}
Another way to do it is to add a handler to the entire parent clip and then in the handler check and see if what was clicked is one of your pegs. But you have to disable mouseChildren on the child clips for that to work.
Note that you may want to look at replacing that big if/then statement with switch/case, which is clearer and more compact in this type of situation.

Related

AS3 Error drag and drop multiple draggable object to multiple target

I want to make the game drag and drop to create multiple draggable objects and it can dragged to multiple targets. But I encountered an error when I drag to the first object that I choose to certain target object is not dragged to the target and then I drag it to another target then succeed. I wanted to fix it. And if you can fix it when the object is dragged to the target and then want to be replaced by another object then the dragged object will be replaced and returned to its original position.
This is a overview the program
And this is the source codes that I use
var xPos:int;
var yPos:int;
var poin:int = 0;
var namaobj1:String;
var namaobj2:String;
addListeners(membaca, menulis, berenang, sepakbola, melukis, memasak, menari, bercocoktanam, beladiri, bermainmusik);
proses.addEventListener(MouseEvent.CLICK,proses1);
function getPosition(target:Object):void
{
xPos = target.x;
yPos = target.y;
}
function dragObject(e:MouseEvent):void
{
getPosition(e.target);
e.target.startDrag(true);
}
function stopDragObject(e:MouseEvent):void
{
if (e.target.hitTestObject(getChildByName("target2")))
{
e.target.x = getChildByName("target2").x;
e.target.y = getChildByName("target2").y;
namaobj2 = e.target.name;
}
else if (e.target.hitTestObject(getChildByName("target1")))
{
e.target.x = getChildByName("target1").x;
e.target.y = getChildByName("target1").y;
namaobj1 = e.target.name;
}
else
{
e.target.x = xPos;
e.target.y = yPos;
}
pil1.text = namaobj1;
pil2.text = namaobj2;
e.target.stopDrag();
}
function addListeners(... objects):void
{
for (var i:int = 0; i < objects.length; i++)
{
objects[i].addEventListener(MouseEvent.MOUSE_DOWN, dragObject);
objects[i].addEventListener(MouseEvent.MOUSE_UP, stopDragObject);
}
}
I'm using draggable objects by putting addListener function.
I also include his .fla can be downloaded here ( TEST.FLA ) rather you can more easily apply fixed codes
You can add Mouse_UP event in your targets instead of you dragged objects. Then when the MOUSE_UP event is trigged, you will know which objects is your target(e.target) without hitTestObject. The code is as follows:
You could have to set dragged object's mouseEnabled when mouse down, and true after dragged.

How to get index of a Bitmap Image from bitmapdata(from an Array)?

I am wondering if i have an Array that push content that is Bitmap, how do i get index of a specific image when clicked. I tried to use indexOf but no luck, my codes are below.
Thanks for your time!
Code:
//First Part is where i add the URLRequest and add the image into contentHolder then onto Stage
function loadImage():void {
for(var i:int = 5; i < somedata.length; i++){
if(somedata[i]){
var loader:Loader = new Loader();
loader.load(new URLRequest("http://www.rentaid.info/rent/"+somedata[i]));
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded);
}
}
}
function onImageLoaded(e:Event):void {
loadedArray.push(e.target.content as Bitmap);
for(var i:int = 0; i < loadedArray.length; i++){
var currentY1:int = 200;
e.currentTarget.loader.content.height =200;
e.currentTarget.loader.content.y += currentY1;
currentY1 += e.currentTarget.loader.content.height +300;
_contentHolder.mouseChildren = false; // ignore children mouseEvents
_contentHolder.mouseEnabled = true; // enable mouse on the object - normally set to true by default
_contentHolder.useHandCursor = true; // add hand cursor on mouse over
_contentHolder.buttonMode = true;
_contentHolder.addChild(loadedArray[i]);
addChild(_contentHolder);
_contentHolder.addEventListener(MouseEvent.CLICK, gotoscene);
}
}
// then the part where i try to get the index
function gotoscene(e:MouseEvent):void {
var index:Number;
index = loadedArray.indexOf(e.target);
trace(index);
}
Edit:
var viewport:Viewport = new Viewport();
viewport.y = 0;
viewport.addChild(_contentHolder);
Your first question has very simple answer:
var image:Bitmap = new Bitmap();
var images:Array = new Array(image);
for (var i:uint = 0; i < images.length; i++) {
// images[i].bitmapData is the original image in your array
// image.bitmapData is searched one
if (images[i].bitmapData == image.bitmapData) {
// found
}
}
But your problem is bigger than this. I see you keep wandering around..
You should add listener to each child, not the content holder as one. I usually don't use Loaders, but get their Bitmaps and wrap them in Sprites or something, that I add into the scene. You should store either this Sprite or your Loader into that array, not the Bitmap. Then add listener to each of them (Sprite or Loader, not Bitmap) and get the target. Depending on what you've stored in the array, you can easily get it as:
function gotoscene(e:MouseEvent):void {
var index:uint = loadedArray(indexOf(e.target));
}
But it's important to store one specific type that will actually be clickable. Don't think about the Bitmap - it's only a graphic representation, and doesn't do much in the code.
**EDIT:
Okay I'm adding the code you need but it's important to understand what you are doing and not just rely on someone else's answer :)
function onImageLoaded(e:Event):void {
var bitmap:Bitmap = e.target.content as Bitmap; // get the Bitmap
var image:Sprite = new Sprite();
image.addChild(bitmap); // wrap it inside new Sprite
// add listener to Sprite!
image.addEventListener(MouseEvent.CLICK, gotoscene);
// gets url of current image (http://website.com/images/image1.jpg)
var url:String = e.target.loaderURL;
// get only the number from that url by replacing or by some other way
// this removes the first part and results in "1.jpg"
var name:String = url.replace("http://website.com/images/image", "");
// this removes the extension and results in number only - 1, 2, 3
// it's important to change this depending on your naming convention
name = name.replace(".jpg", "");
image.name = "button" + name; // results in "button1", "button2", "button3"
// store object, name, or whatever (not really needed in your case, but commonly used)
loadedArray.push(image.name);
image.x = counter * 100; // position so you can see them, at 100, 200, 300, etc.
_contentHolder.addChild(image); // add newly created Sprite to content
}
function gotoscene(e:MouseEvent):void {
var name:String = e.target.name;
// strips down "button" from "button1", and only the number remains,
// which is 1, 2, 3, etc. the number of the scene :)
var scene:uint = name.replace("button", "");
// you're the man now :)
}

AS3 Object Bin and Reset Button

I am trying to create a game for kids where they can drag letters on to a stage to make words.
I want to add a 'trash can' where users can drag letters they no longer need to dispose of them. I have created the movie clip but am totally unsure how to make it function using AS3.
I would also like to add a reset button so that the stage reverts to it's original state. Again, I have drawn it up and added the little as3 that I am aware of (to make it a button) but if anyone could assist with how to actually make this happen, I would be grateful.
The files are here: SWF | FLA and the code for the game is as follows:
import flash.display.MovieClip;
for (var i=1; i<27; i++)
{
this["object" + i].addEventListener(MouseEvent.MOUSE_DOWN, onStart);
this["object" + i].addEventListener(MouseEvent.MOUSE_UP, onStop);
}
var sx = 0,sy = 0;
function onStart(e)
{
sx = e.currentTarget.x;
sy = e.currentTarget.y;
e.currentTarget.startDrag();
}
function onStop(e)
{
if ( e.target.dropTarget != null &&
e.target.dropTarget.parent == dest &&
e.currentTarget.name != "copy" )
{
var objectClass:Class =
getDefinitionByName(getQualifiedClassName(e.currentTarget)) as Class;
var copy:MovieClip = new objectClass();
copy.name = "copy";
this.addChild(copy);
copy.x = e.currentTarget.x;
copy.y = e.currentTarget.y;
e.currentTarget.x = sx;
e.currentTarget.y = sy;
copy.addEventListener(MouseEvent.MOUSE_DOWN, onStart);
copy.addEventListener(MouseEvent.MOUSE_UP, onStop);
}
e.currentTarget.stopDrag();
}
resetButton.addEventListener(MouseEvent.CLICK, reset);
resetButton.buttonMode = true;
function reset(event:MouseEvent):void
{
//Not sure what AS3 to add here to reset to original state
}
I have already gave you the solution here Flash AS3 Clone, Drag and Drop
Here, I am providing a detail solution on how to drag objects inside a bin and remove them.
For dropping copied objects inside a bin, after dragging is stopped, check collision with bin object. for more info see,
copiedObject.hitTestObject(binObject)
For e.g.
First create trash-can MovieClip on the stage and give it an instance name 'trashCan' and add following lines to your onStop()(below e.currentTarget.stopDrag();)function like so:
UPDATE:
var copiedObjsArr:Array = [];
function onStop(e)
{
if ( e.target.dropTarget != null &&
e.target.dropTarget.parent == dest &&
e.currentTarget.name != "copy" )
{
//Code here remains same
//.......
//Keep collecting copied letters for further access in `reset()` function
copiedObjsArr.push(copy);
}
else if(e.currentTarget.name == "copy") //this is 'else if' (newly added)
{
var tarObject:MovieClip = e.currentTarget;
// These detects collision of dragged object with the trashCan
if(tarObject.hitTestObject(trashCan)) {
//These removes dragged object from the display list (not from the memory)
removeChild(tarObject);
tarObject = null; //to garbage
}
}
e.currentTarget.stopDrag();
}
And your reset() becomes like so:
function reset(event:MouseEvent):void
{
if(copiedObjsArr.length > 0)
{
//Traverse through all copied letters
for(var i:int = 0; i<copiedObjsArr.length; i++)
{
var objToRemove:MovieClip = copiedObjsArr[i];
removeChild(objToRemove);
objToRemove = null;
}
//Finally empty the array
copiedObjsArr = [];
}
}

use 1 object multiple times in as3?

I'm trying to make something like bookmarks, I have 1 note on the stage and when the user clicks it, it starts to drag and the users drops it where they want. the problem is I want these notes to be dragged multiple times.. here is my code:
import flash.events.MouseEvent;
//notess is the instance name of the movie clip on the stage
notess.inputText.visible = false;
//delet is a delete button inside the movie clip,
notess.delet.visible = false;
//the class of the object i want to drag
var note:notes = new notes ;
notess.addEventListener(MouseEvent.CLICK , newNote);
function newNote(e:MouseEvent):void
{
for (var i:Number = 1; i<10; i++)
{
addChild(note);
//inpuText is a text field in notess movie clip
note.inputText.visible = false;
note.x = mouseX;
note.y = mouseY;
note.addEventListener( MouseEvent.MOUSE_DOWN , drag);
note.addEventListener( MouseEvent.MOUSE_UP , drop);
note.delet.addEventListener( MouseEvent.CLICK , delet);
}
}
function drag(e:MouseEvent):void
{
note.startDrag();
}
function drop(e:MouseEvent):void
{
e.currentTarget.stopDrag();
note.inputText.visible = true;
note.delet.visible = true;
}
function delet(e:MouseEvent):void
{
removeChild(note);
}
any help will be appreciated.
You need to create a new instance of your note class when you drop, copy the location and other variables from the note you were dragging, add your new note to the stage, and return the dragging note to its original position.
Something like:
function drop($e:MouseEvent):void
{
$e.currentTarget.stopDrag();
dropNote($e.currentTarget as Note);
}
var newNote:Note;
function dropNote($note:Note):void
{
newNote = new Note();
// Copy vars:
newNote.x = $note.x;
newNote.y = $note.y;
// etc.
// restore original note.
// You will need to store its original position before you begin dragging:
$note.x = $note.originalX;
$note.y = $note.orgiinalY;
// etc.
// Finally, add your new note to the stage:
addChild(newNote);
}
... this is pseudo-code really, since I don't know if you need to add the new note to a list, or link it to its original note. If you Google ActionScript Drag Drop Duplicate, you will find quite a few more examples.
I think you are not target the drag object in drag function and problem in object instantiation
for (var i:Number = 1; i<numberOfNodes; i++) {
note = new note();
addChild(note);
...
....
}
function drag(e:MouseEvent):void{
(e.target).startDrag();
}
If you are dragging around multiple types of objects (eg. Notes and Images), you could do something like this, rather than hard coding the type of object to be instantiated.
function drop(e:MouseEvent):void{
// Get a reference to the class of the dragged object
var className:String = flash.utils.getQualifiedClassName(e.currentTarget);
var TheClass:Class = flash.utils.getDefinitionByName(className) as Class;
var scope:DisplayObjectContainer = this; // The Drop Target
// Convert the position of the dragged clip to local coordinates
var position:Point = scope.globalToLocal( DisplayObject(e.currentTarget).localToGlobal() );
// Create a new instance of the dragged object
var instance:DisplayObject = new TheClass();
instance.x = position.x;
instance.y = position.y;
scope.addChild(instance);
}

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.