Drag and clone MovieClip in AS3 - actionscript-3

I have a toolbar with some cars on the left of the window, and I want to click on one element and drag it to the board creating a clone of it, but I can't do it.
My app looks like this:
Cars on the left are my desired dragged.
My source code is:
public class Car extends MovieClip
{
// imports...
var newcar:Car;
public function Car(){
addListeners();
}
private function addListeners():void{
this.addEventListener(MouseEvent.MOUSE_DOWN,clone);
}
private function clone(e:MouseEvent):void{
// Clone the object
newcar = new dibujo();
newcar.graphics.copyFrom(this.graphics);
newcar.x = this.x;
this.parent.addChild(newcar);
// Asign new events to recently created mc
newcar.addEventListener(MouseEvent.MOUSE_OVER,dragCar);
newcar.addEventListener(MouseEvent.MOUSE_UP,dropCar);
}
private function dragCar(e:MouseEvent):void{
this.startDrag();
}
private function dropCar(e:MouseEvent):void{
this.stopDrag();
}
}
The red car and the truck use my own basic class called 'Car'.
Thanks in advance! I hope someone can help me.

And what is not working?
Main problem I see is, that you create new car, but you don't add it to the display list. In your clone function, you need something like
this.parent.addChild(newcar);
edit:
So as I said in comments, problem is, tah property graphics is read only, so you can't change it.
If your cars are instaces of classes that extend your Car (if they are not, you can easily make them), you can use this:
replace
newcar = new dibujo(); //I think you menat new Car() here
with
newcar = new e.target.constructor;
this should finally make it work.
You will then encounter problem with dragging - it never stops. But solution is simple, add this line to your stopDrag function:
e.target.removeEventListener(MouseEvent.MOUSE_MOVE, dragCar);

Related

method (function) in subClass not being called on mouse event

My goal is:
define a subClass of Sprite called Ship
use an event at runtime to call a function within this new class
It seems that I've figured out how to create my Ship class using a package in a linked .as file. But I can't seem to access the function within that class. Can anyone see what I'm doing wrong?
var ShipMc:Ship = new Ship();
addChild(ShipMc);// This successfully adds an instance, so I know the class is working.
addEventListener(MouseEvent.CLICK, ShipMc.addShip);//But this doesn't seem to run the function
This code works fine for instantiating a Sprite, but the code in the Ship.as file, specifically the function, is not working. No runtime errors, but nothing traced to the output window, either.
package
{
import flash.display.Sprite
public class Ship extends Sprite
{
public function addShip():void
{
trace("running addShip function")
}
}
}
The last time a coded anything in flash it was AS2!
I'll just mention that I've tried using addShip():void and just addShip(). Same response with both. It should be with :void, right? Anyway, the fact that neither one throws, tells me that this section of code isn't even getting read, I think.
Any help is much appreciated! Pulling my hair out.
Your code is not working because it contains some problems, so let's see that.
You should know that you are attaching the MouseEvent.CLICK event listener to the main timeline which didn't contain any clickable object yet now (it's empty), so let's start by adding something to your Ship class to avoid that :
public class Ship extends Sprite
{
// the constructor of your class, called when you instantiate this class
public function Ship()
{
// this code will draw an orange square 100*100px at (0, 0)
graphics.beginFill(0xff9900);
graphics.drawRect(0, 0, 100, 100);
graphics.endFill();
}
public function addShip():void
{
trace("addShip function run");
}
}
N.B: You can attach the MouseEvent.CLICK event listener to the stage, which will work even if you have nothing in the stage.
Now, if you test your app, you'll get an clickable orange square at the top left corner of your stage, but the compiler will fire an error (ArgumentError) because it's waiting for a listener function (the Ship.addShip() function here) which accept an MouseEvent object.
So to avoid that error, your Ship.addShip() function can be like this for example :
public function addShip(e:MouseEvent):void
{
trace("addShip function run");
}
Then your code should work.
You can also simplify things by using another listener function in your main code which can call the Ship.addShip() function, like this for example :
var ShipMc:Ship = new Ship();
addChild(ShipMc);
addEventListener(MouseEvent.CLICK, onMouseClick);
function onMouseClick(e:MouseEvent): void
{
ShipMc.addShip();
}
For more about all that, you can take a look on AS3 fundamentals where you can find all what you need to know about AS3.
Hope that can help.

Making a simple tamagoci game getting no compiler errors but receiving no output

Kind of new Actionscript and I'm just trying to make a simple tamagoci game. I've wrote all the code out but and receiving no compiler errors but for some reason I'm also not receiving any output messages for my mouse event listeners. Here is all my code, I really can't find the problem and any help would be greatly appreciated. Thanks.
package{
import flash.display.MovieClip;
import flash.events.MouseEvent;
public class Main extends MovieClip{
public var feedButton:MovieClip;
public var tamagoci:MovieClip;
public var disButton:MovieClip;
public var dietButton:MovieClip;
public function Main() {
this.init();
}
private function init():void {
this.feedButton.addEventListener(MouseEvent.MOUSE_DOWN, onfeedMouseDownHandler);
this.disButton.addEventListener(MouseEvent.MOUSE_DOWN, ondisMouseDownHandler);
this.dietButton.addEventListener(MouseEvent.MOUSE_DOWN, ondietMouseDownHandler);
}
private function onfeedMouseDownHandler(event:MouseEvent)void{
this.tamagoci.scaleX += 0.1;
this.tamagoci.scaleY += 0.1;
}
private function ondisMouseDownHandler(event:MouseEvent)void{
this.tamagoci.gotoAndPlay(5);
}
private function ondietMouseDownHandler(event:MouseEvent)void{
this.tamagoci.scaleX -= 0.1;
this.tamagoci.scaleY -= 0.1;
}
Are you using Flash Professional?
You're declaring your variable types in your class here;
public var feedButton:MovieClip;
public var tamagoci:MovieClip;
public var disButton:MovieClip;
public var dietButton:MovieClip;
But then in your constructor, all you are doing is running init();
public function Main() {
this.init();
}
So, this could one of a few things. The most likely is that you have declared your variables, but you haven't initialised them. You've created the variables to hold your objects, but according to your code, they're empty. More specifically, a variable or class property that doesn't assign an object to a variable of an object type will contain a default value of null.
You could prove this in your code by simply putting a condition inside your init(); method;
if(tamagoci == null){
trace("I haven't been assigned an object of type class yet!")
}
So it could be 1 of these 3 things:
1: If you have written your own classes for these class properties/variables, then you need to instantiate them with the new keyword. The general syntax is;
variable_name = new ClassName(parameter_1, parameter_2);
If you are using classes you have written yourself, you have to create an instance of the object, assign it to a variable, and then add it to the stage using addChild();. For example, lets say you've written your own Tamagoci class;
tamagoci = new Tamagoci();
tamagoci.x = 100; // set the x location
tamagoci.y = 200; // set the y location
addChild(tamagoci);
Notice the use of Tamagoci. This is just an example, but this is the class name, which shouldn't be confused with variable/property name. It could just have easily been;
tamagoci = new MovieClip();
But then, this is just an empty MovieClip. It needs a property to display on the screen. A Shape, A Bitmap, or another container class object like MovieClip or Sprite (container classes allow you to nest display objects inside them). But on a basic level, it must contain a visual component to appear on the stage.
2:
Have you made Main your document class? This is the class which will get automatically called when your Flash movie plays. To set this, click on your stage, and in the properties dialogue box on the right, under PUBLISH, type in the name of your class, which is "Main".
3:
If you have created MovieClips in your library in Flash Professional, then you need to go to your library, right click the MovieClips, and select properties. From there, you need to make sure Export for Actionscript is ticked.
Now, if you click on your MovieClips on the stage, then open the Properties tab in the top right of Flash Professional's default layout, then right at the top should be a text field, and if you hover over it, Instance name will pop up as a tool tip. This is where you name your stage objects. Once that is done, you have access to them in your timeline.
If this is how you've done this, then you don't need to declare the variables in your main class, as they are already declared on your stage by Flash Professional and instantiated automatically.

universal collision detection for action script 3

I'm writing a game where you have to go through a maze. I want this game to have different levels. But for each level, the maze is going to be different. So I drew other walls. But I do not want to write my collision detection method 50 times if I have 50 different levels.
I thought of a way of fixing it, but it's not working. I created a new symbol with nothing in it and named it wall. I think that I can make my wall = wall1 (another symbol I converted, and exported for as), and just do stage.addChild(wall). But I can't find a way to do that. So I need help!
Make a generic class e.g. Wall and make your library symbols use that for their base class. You won't need to create them at runtime using ActionScript for this inheritance to work, you can still just place your MovieClips on the stage.
The next thing you need to do is store these Walls somewhere. Because you seem inexperienced with ActionScript, and want to avoid writing code for new levels, you can automate this process using a manager type class. We will call this class WallManager and it will look like this:
public class WallManager
{
private static var _walls:Vector.<Wall> = new <Wall>[];
internal static function register(wall:Wall):void
{
_walls.push(wall);
}
public static function reset():void
{
_walls = new <Wall>[];
}
public static function get walls():Vector.<Wall>{ return _walls; }
}
Then we'll create your Wall class. Within the constructor for this class, we will automatically have the Wall add itself into the WallManager listing:
public class Wall extends Sprite
{
public function Wall()
{
WallManager.register(this);
}
public function touchingMouse(mouseX:int, mouseY:int):Boolean
{
// For this example I am checking for collisions with the
// mouse pointer. Replace this function with your own collision
// logic for whatever it is that is supposed to collide with
// these walls.
if(parent === null) return false;
var bounds:Rectangle = getBounds(parent);
return bounds.contains(mouseX, mouseY);
}
}
This setup is not 'best practice', but it is suitable in your situation because your project seems small, you appear to be working on it alone, it's simple and it gets the job done.
At the end of each level, use WallManager.reset() to remove the walls from the previous level. For checking collisions across all walls, just use a loop like this:
for each(var i:Wall in WallManager.walls)
{
var collision:Boolean = i.touchingMouse(mouseX, mouseY);
if(collision)
{
// There was a collision.
//
//
}
}
You can make one MovieClip with 50 frames saying stop() on the first frame and do your code like this:
private var wallnum:int;
public function Main()
{
stop();
wallnum = 1;
var wallobj = new Wall();
addChild(wallobj);
wallobj.gotoAndStop(wallnum);
}
For collision detection, I recommend Pixel Perfect Collision Detection (https://code.google.com/p/master-air-controller/source/browse/trunk/master-air-controller/src/PixelPerfectCollisionDetection.as?spec=svn6&r=6)

movie clip class parameters ane null

I have a movie clip with an external class attached.
here is the MC code (I've shorten it only for the relevant part...)
package {
//all the imports here...
public class mc_masterChapter extends MovieClip {
public function mc_masterChapter() {
trace (picFile,strChapTitle);
}
//Properties
public var picFile:String;
public var strChapTitle:String;
}
}
In the main class file I'm adding this object to stage using addChild:
var masterChapter:mc_masterChapter = new mc_masterChapter;
masterChapter.picFile = "pic_Chap1.jpg";
masterChapter.strChapTitle = "ABCD:
addChildAt(masterChapter,1);
now, the trace in the MC class code gives nulls to both parametes but if i put a trace inside the MC timeline (instead of the attached class code), it gives the right value!
how can I access the values from the MC class itself without getting nuls?
Thank you.
It works! Let me explain:
var masterChapter:mc_masterChapter = new mc_masterChapter; // Calls class constuctor
// so calls trace() too!
// You will get null null
masterChapter.picFile = "pic_Chap1.jpg"; // Assign the variables
masterChapter.strChapTitle = "ABCD"; // so they can be read
trace(masterChapter.picFile, masterChapter.strChapTitle); // Should trace pic_Chap1.jpg ABCD
If you add the following method to your class:
public function test():void {
trace(picFile, strChapTitle);
}
Then call masterChapter.test() it will successfully trace those two properties. So yes, the class can read its properties.
Make the var you use in your main class public static vars.
OK!
I solved the mystery.
I put two traces. one in the main MC class saying "hey, I'm inside the MC - the picFile="
and one in the put Function saying "I'm putting this file into picFile:"
well this is what I've got:
hey, I'm inside the MC - the picFile=null
I'm putting this file into picFile:image.jpg
got it!?! at the moment I asked him to give birth to an instance of the MC (even before putting it on stage - just defining the object (with this line:)
var masterChapter:mc_masterChapter = new mc_masterChapter;
it allready run the class, so of course that in this stage the parameters were not defined allready and were null.
the definition code came right after that line (in the main.as)
masterChapter.pic="pic_Chap1.jpg";
so what I did, was to move all the code from the main class of the MC object to a public function inside the same package called init(). Then I called this function manually from the parent main class.
By that I can decide when to call it (after I declare all the parameters of course).
That's it.
god is hiding in the small details : )
tnx for all the helpers.
Possibly a better solution would be to use a getter/setter pair, so you can know at the exact moment the properties are set:
protected var _picFile:String:
public function get picFile():String {
return _picFile;
}
public function set picFile(value:String):void {
if (value != _picFile) {
_picFile=value;
trace('picFile set to', _picFile);
}
}

AS3 layer order

I created two empty Sprites to serve as layers, bottom_spr and top_spr
When clicking a button, a MovieClip appears and follows your mouse, untill you click, then its position is fixed.
As soon as the button is clicked, I addChild the MovieClip to the correct Sprite.
Unfortunately, the layer system doesn't see to work, because they are layered in the order I place them, the Sprites don't seem to influence it.
How is this possible?
private var ground_spr:Sprite;
private var units_spr:Sprite;
public function Game() {
addEventListeners();
ground_spr = new Sprite();
units_spr= new Sprite();
addChild(ground_spr);
addChild(units_spr);
}
private function addEventListeners(){
groundBtn.addEventListener(MouseEvent.CLICK, clickGroundBtn);
unitBtn.addEventListener(MouseEvent.CLICK, clickUnitBtn);
}
private function clickGroundBtn(event:MouseEvent){
var ground = new Ground_mc();
follow();
ground_spr.addChild(ground);
}
private function clickUnitBtn(event:MouseEvent){
var unit = new Unit_mc();
follow();
units_spr.addChild(unit);
}
Your question is very vague but I will attempt to answer it. If you clarify how you want your objects ordered exactly, I can better answer your question. It is fine to add layer of abstraction over the depth handling, if you need it. In this case I dont see much of a need, but I will show you a few things you could do.
To add an object to the back of the screen:
this.setChildIndex(objName, 0);
To add an object to the front of the screen:
this.setChildIndex(objName, this.numChildren - 1);
To swap the depths of two objects:
this.swapChildren(objA, objB);
//Note this is expecting two DisplayObjects so you may have to do:
this.swapChildren(objA as DisplayObject, objB as DisplayObject);