as I am new to as3, I want to implement a MachineGun, that fires while has ammo, and the trigger is pulled, In my case, the MouseEvent.MOUSE_DOWN.
The problem is that this event fires only once.
The closest I get is to this is MouseEvent.MOUSE_MOVE, but it fails my purpose when the mouse position is sustained
EDIT:
I need the updated mouse cursor every frame
When your MouseEvent.MOUSE_DOWN event handler you can create an event listener that listens for the Event.ENTER_FRAME event to be dispatched. Using the Event.ENTER_FRAME event handler you can repeatedly call a method that handles shooting the bullet. The following is an example I modeled after an example at http://www.benoitfreslon.com/actionscript-throw-bullets-to-mouse-direction:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
[SWF(width="500", height="500", frameRate="24", backgroundColor="0xFFFFFF")]
public class Main extends Sprite
{
private var _gun:Gun;
private var _interval:int;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}// end function
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
_gun = new Gun();
_gun.x = stage.stageWidth / 2 - _gun.width / 2;
_gun.y = stage.stageHeight / 2 - _gun.height / 2;
addChild(_gun);
stage.addEventListener(MouseEvent.MOUSE_DOWN, onStageMouseDown);
}// end function
private function onStageMouseDown(e:MouseEvent):void
{
stage.addEventListener(Event.ENTER_FRAME, onStageEnterFrame);
stage.addEventListener(MouseEvent.MOUSE_UP, onStageMouseUp);
}// end function
private function onStageEnterFrame(e:Event):void
{
shootBullet();
}// end function
private function shootBullet():void
{
if (_interval > 5)
{
var bullet:Bullet = new Bullet();
bullet.addEventListener(Event.ENTER_FRAME, onBulletEnterFrame);
bullet.x = _gun.x;
bullet.y = _gun.y;
bullet.angleRadian = Math.atan2(stage.mouseY - _gun.y, stage.mouseX - _gun.x);
bullet.addEventListener(Event.ENTER_FRAME, onBulletEnterFrame);
addChild(bullet);
_interval = 0; // reset
}// end if
_interval++;
}// end function
private function onBulletEnterFrame(e:Event):void
{
var bullet:Bullet = Bullet(e.target);
bullet.x += Math.cos(bullet.angleRadian) * bullet.SPEED;
bullet.y += Math.sin(bullet.angleRadian) * bullet.SPEED;
if ( bullet.x < 0 || bullet.x > 500 || bullet.y < 0 || bullet.y > 500)
{
removeChild(bullet);
bullet.removeEventListener(Event.ENTER_FRAME, onBulletEnterFrame);
}// end if
}// end function
private function onStageMouseUp(e:MouseEvent):void
{
stage.removeEventListener(Event.ENTER_FRAME, onStageEnterFrame);
stage.removeEventListener(MouseEvent.MOUSE_UP, onStageMouseUp);
_interval = 0;
}// end function
}// end class
}// end package
import flash.display.Sprite;
internal class Gun extends Sprite
{
public function Gun()
{
graphics.beginFill(0x000000);
graphics.drawCircle(0, 0, 10);
graphics.endFill();
}// end function
}// end class
internal class Bullet extends Sprite
{
public var angleRadian:Number;
public const SPEED:Number = 10;
public function Bullet()
{
graphics.lineStyle(1, 0x000000);
graphics.drawCircle(0, 0, 10);
graphics.endFill();
}// end function
}// end class
The point of interest is in the onStageEnterFrame() method. There's an if statement that checks whether the _interval property's value is greater than 5, if so, a new bullet is created and shot otherwise the _interval property's value is incremented. The purpose of the _interval property is to space out the bullets being shot.
[UPDATE]
Here is an image of the example flash application running:
The mouse button is being held down in the top right corner hence the bullets being shot in that direction.
On receiving a MouseEvent.MOUSE_DOWN event, run a while loop making the machine gun fire. The loop breaks on receiving a MouseEvent.MOUSE_UP event. Something like this
private function handleMouseDown( event:Event ):void
{
this.addEventListener( MouseEvent.MOUSE_UP , handleMouseUp );
startFiring();
}
private function handleMouseUp( event:Event ):void
{
this.removeEventListener( MouseEvent.MOUSE_UP , handleMouseUp );
this.addEventListener( MouseEvent.MOUSE_DOWN , handleMouseDown);
stopFiring();
}
EDIT: For clarification, the stop and start firing functions are functions that run a loop to keep the machine gun firing animation going however that may be.
add firing action to ENTER_FRAME event when mouse is pressed and remove when mouse is up
this.addEventListener( MouseEvent.MOUSE_DOWN, this.handler_down );
this.addEventListener( MouseEvent.MOUSE_UP, this.handler_up );
private function handler_down(event:Event):void {
super.addEventListener( Event.ENTER_FRAME, this.handler_frame );
}
private function handler_up(event:Event):void {
super.removeEventListener( Event.ENTER_FRAME, this.handler_frame );
}
private function handler_frame(event:Event):void {
this.fire();
}
I have to do this regularly, and instead of using an enter_frame listener, I opt for a Timer() and TimerEvent.Timer listener. That way I have more control over how often the repeat is fired without accounting for frame rate and what not.
private var fireRepeat:Timer;
private function triggerDown(e:MouseEvent):void {
if (!this.fireRepeat) { // create the repeater
this.fireRepeat = new Timer(500, 0);
this.fireRepeat.addEventListener(TimerEvent.TIMER, this.fire);
}
fire(); // fire the first bullet
this.fireRepeat.reset(); // reset the repeater
this.fireRepeat.start(); // start the repeater
}
private function triggerUp(e:MouseEvent):void {
if (this.fireRepeat) { this.fireRepeat.stop(); }
}
public function fire(e:* = null):void {
trace('fire!');
}
Related
So the enemy does drop a coin but i does not get the properties of the coin( if it hits the player it gives him +5 coins)
The coin will be removed if it hits the bottom of the stage, if the player dies or if the player hits it. Sadly, it does not work.
But this does work if i place a coin on the stage before i start the game, it gets all its properties, so then it must be the moment it gets added to the stage that it does not get linked with the coding or something..... and that is where i am right now.
this is the .as file for the coin:
package
{
import flash.display.MovieClip;
import flash.events.Event;
public class Coin1 extends MovieClip
{
private var _root:Object;
private var speed:int = 0;
public function Coin1()
{
addEventListener(Event.ENTER_FRAME, Speed1);
addEventListener(Event.ADDED, beginClass);
addEventListener(Event.ENTER_FRAME, coin1go);
}
private function beginClass(event:Event):void
{
_root = MovieClip(root);
}
private function Speed1(event:Event):void
{
y += speed;
}
private function coin1go(event:Event):void
{
if (this.y > stage.stageHeight)
{
removeEventListener(Event.ENTER_FRAME, coin1go);
_root.removeChild(this);
}
if (hitTestObject(_root.player_mc))
{
_root.coin += 1;
removeEventListener(Event.ENTER_FRAME, coin1go);
_root.removeChild(this);
}
if (_root.playerhealth <= 1)
{
removeEventListener(Event.ENTER_FRAME, coin1go);
_root.removeChild(this);
}
}
}
}
This is the part from where it gets added to the stage:
if (enemy2health <= 0)
{
removeEventListener(Event.ENTER_FRAME, eFrame);
_root.score += _root.Enemy2Score * _root.scoremultiplyer;
stage.addChild(newExplosionSmall)
newExplosionSmall.x = this.x;
newExplosionSmall.y = this.y;
stage.addChild(newCoin1)
newCoin1.x = this.x;
newCoin1.y = this.y;
Ass you can see there is also an addchild for an explosion wich works perfectly fine but that may jus be because it does nothing else than appear and remove itself.
So long story short: enemy drops coin but it does nothing and floats to the bottom of the screen and i get a constant stream of 1009 errors. so does anyone know how to fix this?
You should add an enterframe listener only after receiving a valid stage reference, which only appears when Event.ADDED_TO_STAGE event is received. This is because your enterframe listener refers stage.
public function Coin1()
{
addEventListener(Event.ENTER_FRAME, Speed1);
addEventListener(Event.ADDED_TO_STAGE, beginClass);
}
private function beginClass(event:Event):void
{
_root = MovieClip(root);
addEventListener(Event.ENTER_FRAME, coin1go);
}
I'm creating what should be a very simple, full screen drag and drop game in Flash Develop. It works fine except in one frustrating instance.
I add items to the stage, add MOUSE_DOWN listeners to them and start dragging when one hears that listener. I then add a MOUSE_UP listener to figure out when to stop the drag. Again, this works fine unless mouseX = 0. When the mouse is all the way to the left of the screen and I mouse up or mouse down no listener is fired. I also took it out of full screen mode and if the mouse is at or below 0 no mouse events will fire.
What in the world is going on?
private function itemSelectedHandler(e:MouseEvent):void
{
thisItem = GameItem(e.currentTarget);
thisItem.startDrag();
stage.addEventListener(MouseEvent.MOUSE_UP, itemUnselectedHandler, false, 0, true);
}
private function itemUnselectedHandler(e:MouseEvent):void
{
stopDrag();
stage.removeEventListener(MouseEvent.MOUSE_UP, itemUnselectedHandler);
thisItem.removeEventListener(MouseEvent.MOUSE_DOWN, itemSelectedHandler);
}
You are calling stopDrag on the class and not the dragged sprite. Try something like the following :
package
{
public class Main extends Sprite
{
private var _draggedSprite:Sprite = null;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
for (var i:int = 0; i < 10; i++)
{
createBox();
}
}
private function createBox():void
{
var sp:Sprite = new Sprite();
sp.graphics.beginFill(0xff0000, 1);
sp.graphics.drawRect(0, 0, 30, 30);
sp.graphics.endFill();
sp.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
sp.x = Math.random() * (stage.stageWidth - 30);
sp.y = Math.random() * (stage.stageHeight - 30);
addChild(sp);
}
private function onMouseDown(e:MouseEvent):void
{
var sp:Sprite = e.target as Sprite;
sp.startDrag();
_draggedSprite = sp;
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
private function onMouseUp(e:MouseEvent):void
{
_draggedSprite.stopDrag();
_draggedSprite = null;
stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
}
}
This worked for me when mouseX=0 in fullscreen mode.
I'm really new to flash and as3...
I'm trying to create 2 scenes in flash - one where my movieclip moves away from the mouse whenever it goes near it, and the other where the movie clip is attracted to the mouse. I have found an answer on actionscript 2 but i cannot use this in my as3 file...
Any help or ideas?
Cheers!
Here is an example I made of a display object being "pushed" and "pulled" in relation to the mouse's position.
Main.as(Document class):
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
public class Main extends Sprite
{
public static var PULL:String = "pull";
public static var PUSH:String = "push";
private var _circle:Circle;
private var _force:String;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}// end function
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
_circle = new Circle();
addChild(_circle);
_force = PULL;
stage.addEventListener(MouseEvent.MOUSE_DOWN, onStageMouseDown);
}// end function
private function onStageMouseDown(e:MouseEvent):void
{
stage.addEventListener(MouseEvent.MOUSE_UP, onStageMouseUp);
stage.addEventListener(Event.ENTER_FRAME, onStageEnterFrame);
}// end function
private function onStageMouseUp(e:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_UP, onStageMouseUp);
stage.removeEventListener(Event.ENTER_FRAME, onStageEnterFrame);
_force = (_force == PULL) ? PUSH : PULL;
}// end function
private function onStageEnterFrame(e:Event):void
{
var point1:Point = new Point(_circle.x, _circle.y);
var point2:Point = new Point(stage.mouseX, stage.mouseY);
var point3:Point = point2.subtract(point1);
point3.normalize(10);
if (_force == PULL) {
_circle.x += point3.x;
_circle.y += point3.y;
} else if (_force == PUSH) {
_circle.x -= point3.x;
_circle.y -= point3.y;
}// end else if
}// end function
}// end class
}// end package
import flash.display.Sprite;
import flash.events.Event;
class Circle extends Sprite {
public function Circle() {
draw();
}// end function
private function draw():void {
this.graphics.lineStyle(1);
this.graphics.beginFill(0xFFFFFF);
this.graphics.drawCircle( 0, 0, 20);
this.graphics.endFill();
}// end function
}// end class
In the init() method we add a new display object to the stage, this is the display object we will be "pulling" and "pushing" in relation to the mouse's position.
_circle = new Circle();
addChild(_circle);
Then we set the _force property to our PULL constant. The _force property will determine whether the display object is "pulled" or "pushed".
_force = PULL;
Next we add our mouse event listeners to the stage. On MouseEvent.MOUSE_DOWN we call the onStageMouseDown() event handler. When the handler is called, we add an Event.ENTER_FRAME and MouseEvent.MOUSE_UP event listeners to the stage.
private function onStageMouseDown(e:MouseEvent):void
{
stage.addEventListener(MouseEvent.MOUSE_UP, onStageMouseUp);
stage.addEventListener(Event.ENTER_FRAME, onStageEnterFrame);
}// end function
When the MouseEvent.MOUSE_UP event handler is called, the previous Event.ENTER_FRAME and MouseEvent.MOUSE_UP event listeners are removed from the stage. Then depending on the _force property's value, its value is alternated between PUSH and PULL.
private function onStageMouseUp(e:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_UP, onStageMouseUp);
stage.removeEventListener(Event.ENTER_FRAME, onStageEnterFrame);
_force = (_force == PULL) ? PUSH : PULL;
}// end function
Lastly, the onStageEnterFrame event handler. This is where we calculate the new position of the display object in relation to the mouse.
There are different ways to go about this, but I decided to use the Point class to simplify things. First we have to get a Point object for the display object's position and another Point object for mouse's position.
var point1:Point = new Point(_circle.x, _circle.y);
var point2:Point = new Point(stage.mouseX, stage.mouseY);
Next we have to get the difference between the points using the Point object's subtract() method.
var point3:Point = point2.subtract(point1);
With this new point, we can use the Point object's normalize() method to scale the line segment between the display object's position and the mouse's position to a set length.
point3.normalize(10);
Finally depending on the _force property's value we either subtract or add the point's x and y properties from the display object's x and y properties.
I've 3 different MovieClips that I need to move at the same time across the screen. (From bottom to top)
What is the best way of doing this without using a tweening class like Caurina?
Thank you for tips.
You could add an event listener to the parent container of the display objects which listens for the Event.ENTER_FRAME event. On each Event.ENTER_FRAME event you simply decrement the y property of the display objects like in the following example.
package
{
import flash.display.Sprite;
import flash.events.Event;
[SWF(width="600", height="500")]
public class Main extends Sprite
{
private var _squares:Vector.<Square>;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}// end function
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
_squares = new Vector.<Square>();
var redSquare:Square = new Square(0xFF0000, 100);
redSquare.x = 0;
redSquare.y = 400;
addChild(redSquare);
var greenSquare:Square = new Square(0x00FF00, 100);
greenSquare.x = 300;
greenSquare.y = 300;
addChild(greenSquare);
var blueSquare:Square = new Square(0x0000FF, 100);
blueSquare.x = 500;
blueSquare.y = 100;
addChild(blueSquare);
_squares.push(redSquare, greenSquare, blueSquare);
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}// end function
private function onEnterFrame(e:Event):void
{
for each(var square:Square in _squares)
{
if (square.y > 0) square.y -= 5;
}// end for
}// end function
}// end class
}// end package
import flash.display.Sprite;
internal class Square extends Sprite
{
public function Square(color:uint, size:Number)
{
graphics.beginFill(color);
graphics.drawRect(0, 0, size, size);
graphics.endFill();
}// end function
}// end function
I think you'd be making life easier for yourself though if you simply used Greensock's Tweening platform instead.
You can animate them in Flash IDE with frames and tweenings.
Also you can animate them programmatically yourself. Place every movie clip at the bottom of the screen, write some code that moves your movieClips a little to the top of the screen and gets called periodically (using Timer, EnterFrame event listener or setInterval), stop calling this code when all movieClips reached the top (using Timer.stop(), removeEventListener or clearInterval).
I don't see why you might need to do that because there are many tweening libraries that do all this for you.
I have an array of movie clips that represent buttons the user can click on, and so I need to use addEventListener function so the click can be handled.
I can use a loop and create an addEventListener for each element, I have 26 elements in the array, but I want to try another solution by using only one addEventListener and apply it on the array instead of the elements.
I want to know how to recognize which button was clicked, I mean what's its index in the array.
Thanks.
This is probably a good time to learn about event bubbling. You could just add one listener to the common parent of all your buttons
buttonContainer.addEventListener(MouseEvent.CLICK, buttonContainerClickHandler);
Then try and work out what was clicked
private function buttonContainerClickHandler(e:MouseEvent):void
{
var targetButton:Sprite = e.target as Sprite;
//do something with targetButton.
}
To find out what button was clicked, you could use the indexOf method of your array, and pass it the targetButton.
One thing you will have to do is make sure each of your buttons has mouseChildren set to false, or e.target will return the child assets of the buttons.
Add it to the movieclip. Adding an event listener to an array doesn't make a whole lot of sense. You are basically saying "Hey array, let me know when something about you changes" and Array isn't a subclass of EventDispatcher so that is a no-go. But in any case you don't want to know about the array, you want to know about the movieclip so the logical thing to do is to make the loop and add it to the movieclip.
You can't assign an event listener to an array.
What I think you're doing is applying a different event listener function to each clip in the array.
For each of the clips you can add the same event listener:
clips[i].addEventListener(MouseEvent.CLICK, handleClick);
and the handleClick function looks something like:
function handleClick(e:MouseEvent):void {
trace(clips.indexOf(e.target)) // outputs index the movieclip that was clicked on
}
Create a class for your buttons and add the event listener to the class. This way you don't even have to loop through your movie clips as the method will be part of the class
You can't get out of looping directly -- some loop will have to apply somewhere, but you can get out of looping indirectly -- you can let the VM loop for you. You should look at Array.forEach.
A simple application might be:
// assuming myArr is your array.
myArr.forEach( function(item:*, index:int, array:Array):void
{
item.addEventListener( MouseEvent.CLICK, myClickHandler );
} );
To get the item's index, you might make something more complicated:
myArr.forEach( function(item:*, index:int, array:Array):void
{
item.addEventListener( MouseEvent.CLICK, function( event:Event ):void
{
trace( "my index is", index );
} );
} );
I do have to recommend that you simply cache the array someplace accessible to your listener function and then use Array.indexOf along with event.currentTarget, but if you don't find that acceptable, you can use forEach this way:
myArr.forEach( function(item:*, index:int, array:Array):void
{
item.addEventListener( MouseEvent.CLICK, function( event:Event ):void
{
trace( "my index is", array.indexOf( item ) );
} );
} );
Depending on how often you call those methods, it might not be faster to simply us this:
// probably not best to have this public
protected var myArr:Array = [/* whatever goes in here */]
public function register():void
{
myArr.forEach( addHandler );
}
protected function addHandler( item:IEventListener, index:int, arr:Array ):void
{
item.addEventListener( MouseEvent.CLICK, myClickHandler );
}
protected function myClickHandler( event:MouseEvent ):void
{
trace( event.currentTarget, "is at", myArr.indexOf( event.currentTarget ) );
}
But, I can't be sure without knowing more about your particular use case.
You could create your own custom vector class for IEventDispatcher objects that has a custom method that adds an event listener to all its elements. The best way to do this is to create a proxy class that acts as a wrapper for a Vector.<IEventDispatcher> object. I've created an example to demonstrate this:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.IEventDispatcher;
public class Main extends Sprite
{
private var _eventDispatcherVector:EventDispatcherVector;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}// end function
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
var redCustomButton:CustomButton = new CustomButton("RED", 0xFF0000);
addChild(redCustomButton);
var blueCustomButton:CustomButton = new CustomButton("BLUE", 0x00FF00);
blueCustomButton.x = 100;
addChild(blueCustomButton);
var greenCustomButton:CustomButton = new CustomButton("GREEN", 0x0000FF);
greenCustomButton.x = 200;
addChild(greenCustomButton);
_eventDispatcherVector = new EventDispatcherVector(Vector.<IEventDispatcher>([redCustomButton,
blueCustomButton,
greenCustomButton]));
_eventDispatcherVector.addEventListener(MouseEvent.CLICK, onCustomButtonClick);
}// end function
private function onCustomButtonClick(e:Event):void
{
var customButton:CustomButton = e.target as CustomButton;
trace("You clicked: " + customButton.name + "\n" +
"Its index is: " + _eventDispatcherVector.indexOf(customButton));
}// end function
}// end class
}// end package
import flash.utils.Proxy;
import flash.utils.flash_proxy;
import flash.events.IEventDispatcher;
use namespace flash_proxy;
dynamic internal class EventDispatcherVector extends Proxy
{
private var _eventDispatcherVector:Vector.<IEventDispatcher>;
public function EventDispatcherVector(eventDispatcherVector:Vector.<IEventDispatcher>)
{
_eventDispatcherVector = eventDispatcherVector;
}// end function
override flash_proxy function getProperty(name:*):*
{
return _eventDispatcherVector[name];
}
override flash_proxy function setProperty(name:*, value:*):void
{
_eventDispatcherVector[name] = value;
}// end function
public function indexOf(searchElement:*, fromIndex:*= 0):int
{
return _eventDispatcherVector.indexOf(searchElement, fromIndex);
}// end function
public function addEventListener(type:String,
listener:Function,
useCapture:Boolean = false,
priority:int = 0,
useWeakReference:Boolean = false):void
{
for each(var eventDispatcher:IEventDispatcher in _eventDispatcherVector)
{
eventDispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);
}// end for each
}// end function
}// end class
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
internal class CustomButton extends Sprite
{
public function CustomButton(name:String, color:uint)
{
graphics.beginFill(color);
graphics.drawRect(0, 0, 100, 100);
graphics.endFill();
var textField:TextField = new TextField();
textField.autoSize = TextFieldAutoSize.LEFT;
textField.text = name;
textField.mouseEnabled = false;
textField.x = (100 / 2) - (textField.width / 2);
textField.y = (100 / 2) - (textField.height / 2);
addChild(textField);
this.name = name;
}// end function
}// end class
The output from clicking on the CustomButton objects is the following:
You clicked: RED
Its index is: 0
You clicked: BLUE
Its index is: 1
You clicked: GREEN
Its index is: 2
You can check out Stigglers answer for the question Actionscript 3.0 Best Option for Subclassing Vector Class (Flash Player 10) for more detail.