I'm trying to learn AS3 and have run into a small problem.
I have a Bitmap class to which I add a MouseEvent.CLICK listener, but the event doesn't seem to be dispatched.
I use Flashdevelop to write AS3 code and Flex to compile.
I have two classes, Enemy.as and Player.as
The Player.as looks like this:
package Player
{
import flash.display.Sprite;
import flash.events.MouseEvent;
[Embed(source="../../assets/leek.swf", symbol="Leek")]
public class Player extends Sprite
{
public function Player()
{
trace("Player constructed");
addEventListener(MouseEvent.CLICK, handleClick);
}
private function handleClick(e:MouseEvent):void
{
trace("Clicked Player");
}
}
}
The Enemy.as looks like this:
package enemies
{
import flash.display.Bitmap;
import flash.events.MouseEvent
[Embed(source="../../assets/gardengnome.png")]
public class Enemy extends Bitmap
{
public function Enemy()
{
trace("enemy constructed");
addEventListener(MouseEvent.CLICK, handleClick);
}
private function handleClick(e:MouseEvent):void
{
trace("Clicked Enemy");
}
}
}
The two classes are pretty much identical except that one is a Sprite and I embedded a symbol from a swf file that I got from a tutorial, and the other is a Bitmap and I embedd a png file into that.
The Player class (the one that's a sprite and uses a symbol) fires off the MouseEvent.CLICK when I run the project and click on the Player image, but the Enemy class does not.
There are no compile warnings or errors, so I'm having a hard time understanding what is the issue exactly. Is it because one is a Sprite and the other a Bitmap, or is it because one uses a prepared symbol from a swf, while the other is just a png?
How can I make a Bitmap class respond to MouseEvent?
Thanks for any help!
From ActionScript® 3.0 Reference for the Adobe® Flash® Platform:
The Bitmap class is not a subclass of the InteractiveObject class, so
it cannot dispatch mouse events. However, you can use the
addEventListener() method of the display object container that
contains the Bitmap object.
Unfortunately Bitmap class doesn't dispatch mouse events you will have to wrap it inside a Sprite class.
Related
I'm trying to add the QuickKong class to a game I'm making, as described here: http://www.kongregate.com/forums/90-kongregate-apis/topics/199155-quickkong-easy-kong-api-integration
To call the class, you use:
QuickKong.connectToKong(stage);
However, it keeps giving me:
error 1120: Access of undefined property stage.
Any suggestions? Thanks!
The stage is a property of a DisplayObject. When a DisplayObject is not on the Stage its stage property is undefined.
So, you need to make sure the stage is available when you run QuickKong.connectToKong(stage);.
If you do this in the constructor of your document class it should work just fine. Chances are you're trying to do this in some other class that doesn't have a stage property.
If the class you're trying to run this in extends a DisplayObject such as MovieClip or Sprite you can listen for when it is added to the stage and then run your QuickKong code. Like this:
package {
import flash.display.MovieClip;
import flash.events.Event;
public class Test extends MovieClip {
public function Test() {
addEventListener(Event.ADDED_TO_STAGE, onAdded);
}
private function onAdded(e:Event):void{
// now the stage is available
QuickKong.connectToKong(stage);
}
}
}
Now, if for some reason you are not running your QuickKong code in a class that has access to the stage you should pass a reference to the stage into that class's constructor, like this:
var someClass:SomeClass = new SomeClass(stage);
Lastly, in your document class you could make a static variable reference the stage. Like this:
package {
import flash.display.MovieClip;
public class Main extends MovieClip {
public function Main() {
Main.stage = stage;
}
}
}
Now, you can just say: Main.stage anywhere in your code when you need to talk about the stage:
QuickKong.connectToKong(Main.stage);
I put my code in a out side as3 file and when i try to use the trace it works fine, but when a i add a stop after, it won't work, why?
here is my code:
package {
import flash.display.Sprite;
public class TDSBMaze extends Sprite {
public function TDSBMaze() {
trace("Test");
stop();
}
}
}
And also when i try to just put the code in a frame it also won't work unless i unlink the outside .as file.
Sprites do not have a timeline, so it can't stop since it never plays. If you need a timeline, you should extend MovieClip.
You need to extend MovieClip if you wish to make use of a timeline. Sprites do not have timelines.
package {
import flash.display.MovieClip;
public class TDSBMaze extends MovieClip {
public function TDSBMaze() {
trace("Test");
stop();
}
}
}
I got problem when I am loading external swf which contains added_to_stage method. It execute two times. I don t understand why it is doing ? I am also interesting if both swfs have their own stage ?
Thank you for any answer
I am using greensock library to hanle loading.
Flash preloader:
package {
import flash.display.MovieClip;
import com.greensock.loading.SWFLoader;
public class Preloader extends MovieClip
{
public function Preloader()
{
var loader : SWFLoader = new SWFLoader("Prototype1.swf");
loader.load();
addChild(loader.content);
}
}
}
External SWF:
public class Prototype1 extends MySprite
{
public function Prototype1()
{
addEventListener(Event.ADDED_TO_STAGE, onAdded);
}
private function onAdded(e:Event):void
{
trace("onAdded");
}
}
OUTPUT: onAdded onAdded
The greensock documentation says:
suppressInitReparentEvents: Boolean - If true, the SWFLoader will suppress the REMOVED_FROM_STAGE and ADDED_TO_STAGE events that are normally dispatched when the subloaded swf is reparented into the ContentDisplay (this always happens in Flash when any DisplayObject that's in the display list gets reparented - SWFLoader just circumvents it by default initially to avoid common problems that could arise if the child swf is coded a certain way).
So you can change your code in Preloader.as to:
var loader:SWFLoader = new SWFLoader("Prototype1.swf", {suppressInitReparentEvents: true});
And you'll only get one call to onAdded.
What more can be done if I extend MainClass with MovieClip rather than Sprite. I know that MovieClip extends Sprite and it has Timeline defined under it. but still how it will be usable to me by MovieClip ?
package {
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.display.MovieClip;
import flash.text.TextFieldType;
public class MainClass extends Sprite{
public function MainClass() {
var m:Module=new Module("Admin","John");
var tf:TextField=new TextField();
tf.text=m.info;
tf.border=true;
tf.type=TextFieldType.INPUT;
var myFormat:TextFormat = new TextFormat();
myFormat.size = 3;
tf.defaultTextFormat=myFormat;
addChild(tf);
this.width=500;
this.height=300;
this.x=0;
this.y=10;
}
}
}
class Module{
private var m_mName:String;
private var m_owner:String;
public function Module(mName:String,owner:String):void{
m_mName=mName;
m_owner=owner;
}
public function get info():String{
return owner+' is owner of '+mName;
}
public function get mName():String{
return m_mName;
}
public function get owner():String{
return m_owner;
}
}
Another little question, How to use Timeline if I replace Sprite by MovieClip ?
Quoting from an AS3 book:
Prior to ActionScript 3.0, the MovieClip class was used as an all-purpose graphics container (much like ActionScript 3.0s Sprite class is used). As of ActionScript 3.0, MovieClip is used only to control instances of movieclip symbols created in the Flash authoring tool. Because ActionScript 3.0 does not provide a way to create timeline elements such as frames and tweens, there is no need to create new empty movieclips at runtime in ActionScript 3.0. Instead, all programmatically created graphics should be instances of the appropriate core display class (Bitmap, Shape, Sprite, TextField, etc).
MovieClip is a dynamic class that retains backwards compatibility with AS2. That means that if, while not recommended, require you add a property to a MovieClip, you can simply say myMC.myCustomProperty = "someValue", whereas with a Sprite, that will throw an error.
For this reason, they also say that using Sprites is more effective in terms of performance. You can find a discussion about this in this Adobe Forum post.
I'm trying to play a movie clip when I mouse_over it. I can do it fine by doing:
mc1.addEventListener(MouseEvent.MOUSE_OVER,mover);
function mover(e:MouseEvent):void {
mc1.play();
}
But, I want to use the same function for other movie clips, for example, to play movieclip2, movieclip3 etc.
How would I achieve this?
mc1.addEventListener(MouseEvent.MOUSE_OVER,mover);
mc2.addEventListener(MouseEvent.MOUSE_OVER,mover);
mc3.addEventListener(MouseEvent.MOUSE_OVER,mover);
function mover(e:MouseEvent):void {
e.currentTarget.play();
}
You can make a class to encapsulate your logic for example, to access the MovieClip from the calling function, use the property of the Event object
import flash.display.MovieClip;
import flash.events.MouseEvent;
public class PlayMovieClip {
// register the mouse over event with whatever MovieClip you want
public static function register(mc:MovieClip):void{
mc.addEventListener(MouseEvent.MOUSE_OVER,mover);
}
// unregister the event when you dont need it anymore
public static function unregister(mc:MovieClip):void{
mc.removeEventListener(MouseEvent.MOUSE_OVER, mover);
}
// the MouseEvent will be throw whenever the mouse pass over the registered MovieClip
// and in the MouseEvent property you have the targeted object
// so use it
public static function mover(e:MouseEvent):void{
// check if we have really a MovieClip
var mc:MovieClip=e.currentTarget as MovieClip;
if (mc!==null) {
// we have a MovieClip so we can run the function play on it
mc.play();
}
}
}
usage:
PlayMovieClip.register(mc1);
...
PlayMovieClip.register(mcX);
and to remove the event:
PlayMovieClip.unregister(mc1);
...
PlayMovieClip.unregister(mcX);