as3 - How to make two movieclips share the same code? - actionscript-3

I have four movieclips (the player, one arm, another arm, and a weapon) the arms are placed to player and the weapon is placed to the arms. The player should have one arm that displays below it. And the weapon and the other arm that should display on top of it.
However, I have two arms as two different movieclips but they both have the same exact code. If I kept both in the same movieclip, both arms would display on top the player or both would display below the player. And you can't have one movieclip splitting into two layers. And you can't have two movieclips sharing the same class.
So I would like to know if I can make these two arms share the same code without having to write it twice.

The cleanest approach would be to make a base class. You can make a PlayerArmBase.asfile beside your .fla file, and have it look something like this:
package {
import flash.display.MovieClip;
import flash.events.Event;
public class PlayerArmBase extends MovieClip {
public function PlayerArmBase(){
//don't do anything until this item has been added to stage/timeline
this.addEventListener(Event.ADDED_TO_STAGE, addedToStage, false,0,true);
}
protected function addedToStage(e:Event):void {
//this is the equivalent of where timeline code runs
//put your code here for your arms
//for example:
this.addEventListener(Event.ENTER_FRAME, enterFrame, false, 0, true);
}
protected function enterFrame(e:Event):void {
//do something every frame tick like point to the mouse position
}
}
}
Now, you can make both your arms extend this base class. To do so, right click each arm in flash pro, and go their properties. Check the "Export For Actionscript" check box in the advanced settings, then in the "Base Class" field type the name of your class.
Now all the code in that class will apply to both arm MovieClips.
Alternatively, you could put all the common code in the base class, then make another 2 classes (one for each arm) and put specific code in those and have them extend the base class. This is the same as the graphic above, except instead of the base class field, put LeftArm in the class field.
package {
import flash.events.Event;
public class LeftArm extends PlayerArmBase {
public function LeftArm(){
}
//we can override the addedToStage function from the base class
override protected function addedToStage(e:Event):void {
super.addedToStage(e); //call the base class version of this function
//do stuff specific to the left arm
}
}
}
This way you have code specific to each arm in it's own class, but have all the common code in 1 place. Super classes can access all functions and vars that are declared with the public or protected keywords. protected is like private except super classes can still access it. private can only be used in the class you defined it in.

Like I had said in the comments, I don't like to code inside the MovieClips, but if you prefer working in that way, do the next:
Put the code inside an empty MovieClip, then put that MovieClip inside each arm MovieClip and make a variable that reference to the parent to do the transformations that you need.
Here you have an example

Related

Making a button that goes to a random frame (from an array) on the main timeline. How to do from a movie clip?

I saw plenty of questions that asked how to make a button in a movie clip that leads to a frame in the main timeline, and took a look at them. But is it different if you want to go to a random frame in a specific set of frames? I've never really used AS3 aside from simple things like stop(); or gotoAndPlay.
Here's what my main timeline looks like at the moment:
Here's the code I've got so far by using Google:
var frameB:Array=[1,28,45,56,71,91,106,126];
blue_circle1.addEventListener(MouseEvent.CLICK, choose);
function choose1(event:MouseEvent):void {
var randomFrame:Number = frameB[Math.floor(Math.random() * frameB.length)];
trace(randomFrame);
gotoAndPlay(randomFrame);
}
The code works fine when I use it on the rotation buttons in the main timeline. But it doesn't work when I put it in a button in a movie clip. I need to change it so it works. If there is a better way of doing this, I'm willing to try it.
Edit: I should clarify things more. I got rectangle on wheels that moves left to right. It does this in a movie clip. I want the button to move with it. But when I place the button into said movie clip, the code on the button stops working. I hope I didn't end up making things more confusing.
When you place the button and/or code inside the movieClip it changes the movieClip that gotoAndPlay() is referring to. You need to specify which movieClip you are calling gotoAndPlay() on. For the main timeline gotoAndPlay() works, but inside a movieClip you must use this:
parent.gotoAndPlay(randomFrame);
Or you may need to set parent's type to a MovieClip like this:
MovieClip(parent).gotoAndPlay(randomFrame);
However, it's best to use external .as files as it gives you the most control over your code.
Save the code below in a file called 'MyFlashAnimation.as'
Create a folder called 'mycodefolder' and put it in the same directory/folder as your .fla.
Use the 'MyFlashAnimation.as' as your document class. In the Flash/Animate IDE find the Properties panel, then the Publish section
In the Publish section where it says 'Class' enter: mycodefolder.MyFlashAnimation (do not add the .as)
CODE:
package mycodefolder {
import flash.display.MovieClip;
import flash.events.MouseEvent;
public class MyFlashAnimation {
private var animationClip:MovieClip;
private var blueCircle1:Button;
private var frameB:Array = [1,28,45,56,71,91,106,126];
// constructor
public function MyFlashAnimation() {
// this your main robot/car animation
// this assumes animation_clip is on the main stage
animationClip = this.animation_clip;
// this is your button. this assumes blue_circle1 is a child of
// your animation_clip. update the path if necessary.
// for example, it might be: animationClip.robot_body.blue_circle1
blueCircle1 = animationClip.blue_circle1;
// add listener
blue_circle1.addEventListener(MouseEvent.CLICK, choose);
}
function choose1(event:MouseEvent):void {
var randomFrame:Number = frameB[Math.floor(Math.random() * frameB.length)];
trace(randomFrame);
// tell animation clip to gotoAndPlay
animationClip.gotoAndPlay(randomFrame);
}
}
}
That should work. If you have all your movieClip paths correct.
"The code works fine when I use it on the rotation buttons in the main timeline. But it doesn't work when I put it in a button in a
movie clip."
What is the instance name of the MClip you paste the button into? That MC name will "add" to the final path of your button.
Examples:
(1) If your blue_circle1 on stage (you already can do this) :
blue_circle1.addEventListener(MouseEvent.CLICK, choose);
versus...
2) If your blue_circle1 is inside another MClip (with example name as: thingMC) :
thingMC.blue_circle1.addEventListener(MouseEvent.CLICK, choose);

AS3 Multiple Rollover objects

example image
Very new to AS3. Sorry if this question is really basic, I tried looking around for the right answer but only found semi-related questions. Please help!!
Objective: I want multiple rollover MovieClips on the same stage that play out their animations independently.
So far, I have only 1 MovieClip object that behaves properly. If I add another, the first one behaves properly but the second doesn't appear at all. I understand that it's probably only calling the instance that I first dropped into the stage and that I need to change my code to have a "master" or parent MovieClip and that the instances should be the children, but I'm not sure how to write that in code. Eventually, the idea is that I add my children movieclips, and then slightly change the content in each clip.
My code so far:
import flash.events.MouseEvent;
clip_boxes.removeEventListener(MouseEvent.ROLL_OUT, clipOut);
clip_boxes.addEventListener(MouseEvent.ROLL_OVER, clipOver);
function clipOver(event:MouseEvent):void {
clip_boxes.addEventListener(MouseEvent.ROLL_OUT, clipOut);
clip_boxes.removeEventListener(MouseEvent.ROLL_OVER,clipOver);
clip_boxes.gotoAndPlay("Over");
};
function clipOut(event:MouseEvent):void {
clip_boxes.addEventListener(MouseEvent.ROLL_OVER, clipOver);
clip_boxes.removeEventListener(MouseEvent.ROLL_OUT, clipOut);
clip_boxes.gotoAndPlay("Out");
};
There are a few ways you can do this. I'll list in order of worst to best.
Manually add listeners to each instance.
When you drag a new MovieClip onto the timeline, you need to give it an instance name (found in the properties panel). I'm not sure if clip_boxes is a parent timeline that you intend to have all your movie clips on, or if it is one of your movie clips itself.
Assuming you have 3 clips with the instance names: MC1,MC2,MC3, you could do this (on the first frame of the timeline that contains them)
MC1.addEventListener(MouseEvent.ROLL_OVER, clipOver);
MC2.addEventListener(MouseEvent.ROLL_OVER, clipOver);
MC3.addEventListener(MouseEvent.ROLL_OVER, clipOver);
//If you had a whole bunch, you could also use a loop to add all the listeners
//you use event.currentTarget to get a referce to the object the listener was attached to - this way you only need this one handler function
function clipOver(event:MouseEvent):void {
MovieClip(event.currentTarget).addEventListener(MouseEvent.ROLL_OUT, clipOut);
MovieClip(event.currentTarget).gotoAndPlay("Over");
};
function clipOut(event:MouseEvent):void {
MovieClip(event.currentTarget).removeEventListener(MouseEvent.ROLL_OUT, clipOut);
MovieClip(event.currentTarget).gotoAndPlay("Out");
};
Use Inheritance
This would involve creating a base class file (.as file) that you can then attach to all your MovieClips so they inherit all the code within. Here is an example of a class file that would do this for you: (lets assume this is a file called SubClass.as in your root directory)
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
public class SubClass extends MovieClip {
public function SubClass(){
this.addEventListener(MouseEvent.ROLL_OVER, rollOver,false,0,true);
}
public function rollOver(event:MouseEvent):void {
this.addEventListener(MouseEvent.ROLL_OUT,rollOut,false,0,true);
this.gotoAndPlay("Over");
}
public function rollOut(event:MouseEvent):void {
this.removeEventListener(MouseEvent.ROLL_OUT,rollOut,false);
this.gotoAndPlay("Out");
}
}
}
Now, when you create your movieClips (or right click in the library and select properties), you can set a baseClass for them. If you set the base class to the class above, they automatically use the code above and have the mouse over/out attached. (as long as they have the Out/Over frame labels it will just work).
Can you also post the code where you add clip boxes to the stage? Did you add them in the GUI by dragging and dropping or in code?
If so, you might need to make instances of each of the clip boxes inside the larger movieclip that contains all of them together. Then you'll need to refer to each one with clip_boxes.box1, etc.
EDIT:
Oh, I see you had an image there. My bad. Make sure you give each clip box its own unique instance name. You'll need to have clip_box_1, clip_box_2, etc. Then in code you use clip_box_1.addEventListen.....etc.

Making a movieclip appear when mousing-over a button

I'm trying to create a disclaimer link that, when moused-over, a movie clip (disclaimer window) will show-up on the swf. How do I do this in AS3, please?
I'm new, and I've only gotten this far:
import flash.events.MouseEvent;
import flash.ui.Mouse;
addEventListener(MouseEvent.MOUSE_OVER,showOptions);
function showOptions (e: MouseEvent): void {
}
You can load your disclaimer window movieclip dynamically from your library like so:
function showOptions(e:MouseEvent):void{
var disclaimer:MovieClip = new disclaimerMC();
disclaimer.name = "disclaimer"; //give disclaimer name in case used later
disclaimer.x = 100; //set coordinates of movieclip
disclaimer.y = 100;
this.addChild(disclaimer); //add the disclaimer to the screen
}
Make sure that you go to your disclaimer movieclip in the library, right-click it, go to properties / linkage, and change the Class field. In my example, I changed the Class field to disclaimerMC.
It might also be nice to let Flash know which movieclips the EventListener should apply to. The way your code is now, mousing over anything would call showOptions. As you probably don't want that, you can say
disclaimerLink.addEventListener(MouseEvent.MOUSE_OVER,showOptions);
So then, only when you mouse over disclaimerLink will disclaimer show.
Alternatively, if the disclaimer window will always appear and disappear in the same place, it is quicker to change its transparency value. Your MOUSE_OVER and MOUSE_OUT functions can call disclaimer.alpha=100; and disclaimer.alpha=0;, respectively.

AS3: One class with parameter, or two similar classes

In case of creating two similar custom AS3 visual components, ex. Button, with different look, but same function, which methodology is better, more efficient from the aspect of code-execution, speed, performance?
Creating two, almost identical classes, where the only difference is
in the visual components, so I have to write the button-controlling functions two times?
Creating one class, with a parameter input
that defines, which kind of button I would like to have
1:
package {
public class bigButton {
public function bigButton() {
//make a bigButton
}
}
}
and
package {
public class smallButton {
public function smallButton() {
//make a smallButton
}
}
}
or
2:
package {
public class OneKindOfButton {
public function OneKindOfButton(thisIsBigButton:Boolean) {
if (thisIsBigButton == true) {
//make it big
} else {
//make it small
}
}
}
}
In terms of an academic argument about the two structures (not this particular example), I'd have to argue that the first option is "better." Although opinion based posts are generally regarded as worthless by most of the SO community, I have a couple of points to bring up and would like to hear counter arguments.
For the second option of doing it, first off it makes me think that potentially there should be a base class that contains all the original functionality then a sub-class that tweaks some part of the functionality. Secondly it requires a condition in the constructor (and probably elsewhere littered throughout that class) to deal with the two scenarios the one class is handling. I think part of the issue here is that in AS3 there is a tendency to mash up all of the functionality and the view logic into one class, just because it's possible doesn't make it a good idea.
All said, I would probably go the route of having a base class that contains the functionality for the buttons, then make some sub-classes that do things different visually.
Also in terms of run-time efficiency I believe the first scenario will work out better again due to the extra conditions that will have to be checked at run-time with the second scenario. In any case, when performance and optimization is the issue it's always best to just run a test (build a little test app that makes 10,000 of each, run it a couple of times and get an average).
I would just create one kind of button class since you can draw or add other display objects into it. You don't even need a boolean to control that. For example :
public class OneKindOfButton extends Sprite{
public function OneKindOfButton(width:Number,height:Number) {
create(width,height);
}
private function create(width:Number,height:Number):void
{
graphics.clear();
graphics.beginFill(0xff0000,1.0);
graphics.drawRect(0,0,width,height);
graphics.endFill();
}
}
Now you can use this class to create any size of button.
var myButton:OneKindOfButton = new OneKindOfButton(200,20);
myButton.x = 100;
myButton.y = 300;
addChild(myButton);
If you want to use images instead of drawing into the button you can do that too by just adding bitmaps into the button sprite.
I think all these answers kind of miss the point of Flash.
Firstly, I don't think that View classes should ever have constructor arguments in Flash, because right off the bat you're making it impossible to ever use them on the timeline/stage. The Flash player can't (and shouldn't) provide these constructor arguments. The stage and timeline are Flash's biggest strength, so if you're not using them, you're wasting at least 25% of your time (the time where you're setting x, y, width, height, drawing graphics programmatically and all that unnecessary crap). Why lock yourself into a design that actively prevents you from using all the tools at your disposal?
The way I do it is I have one Class that defines the behavior of the button. Then the buttons are differentiated by having a library symbol for the big button, one for the small button, one for the button shaped like a pig, one for the button that looks like a spaceship, whatever. Any of these symbols will have that single Button Class as the Base Class (or more likely, just be defined as a Button in the library, so they subcass SimpleButton). Then I just place an instance of the library symbol on the stage and the variable in whatever parent Class is typed to my Button Class or SimpleButton.
The advantage of doing this is that the parent Classes don't need to know the specific implementation type, just the more general type. This means that the library symbols can have "export for Actionscript in frame N" unchecked, and they can just be compiled in where they are used. This means that initial load time can be reduced to the point that you may not ever need a preloader, depending on what else you have going on.
For more on this approach, see Combining the Timeline with OOP in AS3.
If the only difference between you two buttons is their look, but all the logic is shared, then you should definitely use only one common class.
If you're dealing with spark button, then you can simply specify a different skin for each of your instances (about spark skins).
package
{
import spark.component.Button;
public class MyCustomButton extends Button
{
static public const SMALL:String = "smallButton";
static public const BIG:String = "bigButton";
static private const DEFAULT_SIZE:String = SMALL;
public function MyCustomButton(type:String = DEFAULT_SIZE)
{
super();
if (type == SMALL)
{
setStyle("skinClass", SmallButtonSkin);
}
else
{
setStyle("skinClass", BigButtonSkin);
}
}
}
}
You then have to create to different skin classes where you'll define the visual logic of your buttons.

AS3 subclass not working

Error 5000 "must subclass flash.display.MovieClip" / "must subclass flash.display.SimpleButton" I finally decided to ask after forum hopping for answers. Basically, when I extend MovieClip the error for the movie clip goes away but the simple button error shows up. When I extend simple button, the movie clip error appears. What is the simplest way to include both or otherwise make this work?
//psuedo code
import flash.display.*;
public class classInSession extends MovieClip //or SimpleButton
{
var Btn:SimpleButton;//This needs SimpleButton
public function reception123() {
stop();//This needs MovieClip
Btn.enabled = true;//This needs SimpleButton
Btn.addEventListener(MouseEvent.MOUSE_DOWN, goSomewhere);
function goSomewhere(event:MouseEvent):void{
gotoAndStop(1);//This also needs MovieClip
}
}
}
It doesn't make sense for something to be both a MovieClip (which is for animation) and a SimpleButton (which is for buttons).
What you want is a MovieClip which has a SimpleButton.
The code you posted does that, but I think your main problem is that you didn't actually create Btn, so it is null when that call is made (and therefore doesn't subclass SimpleButton):
Your class should have a constructor;
Inside the constructor, you create the button with Btn = new SimpleButton();.
I did a lot but I believe the arrow that hit the mark was unchecking "automatically declare stage instances" from the publish settings.