MouseUpEvent stops working while Dragging MovieClip - actionscript-3

There is a mouseUpEvent listener attached to the stage in the main class, while dragging the movieClip the mouseUpEvent doesnot trigger the handler and the movieClip gets sticks to the mouse. While the item is being dragged and the mouse is moved away from the movieClip i.e somewhere not on the item but on the stage the mouseUp is detected.
Edit: Here is the scenario I am using a static (Singleton) class as a movieClip as a "DragManager". Whenever a movieClip has to be dragged it is passed to the DragManager and is added as a child, when a mouseUp from stage is detected another static function of dragManager is called to stop the drag and put the movieClip on the appropriate layer. Here is the static function in the DragManager which is called on MouseDown from variouslayers.
public static function startDragMethod(item:Item):void
{
instance.addChild(item); //This is the instance of the DragManager
var boundArea:Rectangle = new Rectangle(0,0,610,760);
item.startDrag(false,boundArea);
}
In the constructor of the main class I add the eventHandler for the MouseUpEvent
this.addEventListener(MouseEvent.MOUSE_UP,stageMouseUpHandler);
The MouseUpHandler in the main class
private function stageMouseUpHandler(event:MouseEvent):void
{
DragManager.itemMouseUpHandler(event);
}
If there is something wrong with technique please guide me, my goal is to implement drag drop between various layers and with as less coupling as possible.

Well there are many ways to get the task done. Put some condition at your static listener function or when the object is dragged.
like
public static function startDragMethod(item:Item):void
{
instance.addChild(item); //This is the instance of the DragManager
var boundArea:Rectangle = new Rectangle(0,0,610,760);
item.startDrag(false,boundArea);
check = true;
}
private function stageMouseUpHandler(event:MouseEvent):void
{
if(check==true)
{
DragManager.itemMouseUpHandler(event);
check = false;
}
}

Related

Replacing a movieclip with another movieclip, keeping the same instance name

I'm new to actionscript so this question might be a stupid one.
I'm trying to replace a movieclip with another movieclip, while keeping the instance name of the previous.
I have a menu with a selection of buttons, each leading to the same screen with a movieclip and a scrubber bar. I tried defining the movieclip through a variable, then tried redefining it through an event listener function, but I'm guessing I can't do like this:
var MC: movieclipsymbol1 = new movieclipsymbol1;
private function selectionscreen(): void {
selectionscreenbutton1.addEventListener(MouseEvent.CLICK, screenbutton1);
selectionscreenbutton2.addEventListener(MouseEvent.CLICK, screenbutton2);
private function screenbutton1(event: MouseEvent): void {
var MC: movieclipsymbol1 = new movieclipsymbol1;
movieclipscreen();
}
private function screenbutton2(event: MouseEvent): void {
var MC: movieclipsymbol2 = new movieclipsymbol2;
movieclipscreen();
}
}
public function movieclipscreen(): void {
stage.addChild(MC);
}
Because of the scrubber bar code I did, I need to keep the instance for the movieclips the same. Is the approach I'm using completely off?
You have to remove var MC from both handlers, as you want your new MC to be accessible from outside of the handlers. But also you need to change the type of class variable MC so that it could hold either movieclipsymbol1 or movieclipsymbol2. The most common choice for the type in there is MovieClip. So, you have to change your functions like this:
var MC:MovieClip = new movieclipsymbol1();
private function screenbutton1(event: MouseEvent): void {
clearOldMC();
MC = new movieclipsymbol1();
movieclipscreen();
}
private function screenbutton2(event: MouseEvent): void {
clearOldMC();
MC = new movieclipsymbol2();
movieclipscreen();
}
private function clearOldMC():void {
if (MC.parent) MC.parent.removeChild(MC);
}
The new function removes the previously displayed movie clip, regardless of its type.
Use "name" property of display object to give the instance name to movieclip.

Action Script 3.0 Mouse Event in a class package

am having problem with using mouse click event inside a class, i am an absolute beginner to Action Script.
what i want is that if i click the btn_MClick button it should run the script, but everytime i click it i get error message that btn_MClick is undefined.
btn_MClick is on stage and with the instance name if btn_MClick
public class gunShip1 extends MovieClip
{
var moveCount = 0;
public function gunShip1()
{
stage.addEventListener(KeyboardEvent.KEY_DOWN, moveGunShip1);
stage.addEventListener(KeyboardEvent.KEY_DOWN, ShootGunShip1)
btn_MClick.addEventListener(MouseEvent.MOUSE_DOWN.KEY_DOWN, ShootGunShip1);;
}
function ShootGunShip1(evt: MouseEvent)
{
var s_Bullet:survBullet = new survBullet();
var stagePos:Point = this.localToGlobal (new Point(this.width / 2-10, this.height));;
s_Bullet.x = stagePos.x;
s_Bullet.y = stagePos.y;
parent.addChild(s_Bullet);
//play sound
var gun_sound:ricochetshot = new ricochetshot();
gun_sound.play();
}
}
Please, i have absolutely no idea what to do, and somehow it feels like the whole process is wrong.
Your class gunShip1 does not have the property btn_MClick, the root, or document class does.
Basically what's happening is that you've placed your button on the stage, which makes it an instance that belongs to the root container. At the moment, you're trying to refer to the button as a property of gunShip1.
What you should really do here is have the button click managed separately to gunShip1, and have that separate code invoke methods of gunShip1. For example, you could have this in your document class:
public class Game extends MovieClip
{
private var _ship:gunShip1;
public function Game()
{
_ship = new gunShip1();
// The Document Class will have reference to objects on the stage.
btn_MClick.addEventListener(MouseEvent.CLICK, _click);
}
private function _click(e:MouseEvent):void
{
_ship.shoot();
}
}
And then your updated shoot method in gunShip1:
public function shoot():void
{
var s_Bullet:survBullet = new survBullet();
var stagePos:Point = this.localToGlobal (new Point(this.width / 2 - 10, this.height));
s_Bullet.x = stagePos.x;
s_Bullet.y = stagePos.y;
parent.addChild(s_Bullet);
var gun_sound:ricochetshot = new ricochetshot();
gun_sound.play();
}
The idea is that the gunShip1 should not be responsible for dealing with user input (mouse, keyboard, etc). Instead, that should be a separate class which informs gunShip1 that it should do something.

ActionScripting Issue: adding/removing children

I have three movie clips all linked to the stage and I want them to behave like a button/ But I am not using a button because I have not found a way to have each part (up, over, down, hit) be animated and not just change when the mouse is in use with it. So far I have been able to have all three appear on my stage and show when I have the mouse over and as well when I click, but I think I'm doing something wrong with removeChild. Each MC should appear one at a time and now all three show up when I hover over and seem to "flash". Here's my code:
var mainMoon:swayingMoon = new swayingMoon();
mainMoon.x = 50;
mainMoon.y = 10;
addChild(mainMoon);
var hoverMoon:glowMoon = new glowMoon();
hoverMoon.x = 50;
hoverMoon.y = 10;
var movieMoon:clickedMoon = new clickedMoon();
movieMoon.x = 50;
movieMoon.y = 10;
mainMoon.addEventListener(MouseEvent.ROLL_OVER, showHoverMoon);
mainMoon.addEventListener(MouseEvent.ROLL_OUT, hideHoverMoon);
hoverMoon.addEventListener(MouseEvent.CLICK, startMovieMoon)
function showHoverMoon(event:MouseEvent):void
{
addChild(hoverMoon);
}
function hideHoverMoon(event:MouseEvent):void
{
removeChild(hoverMoon)
}
function startMovieMoon(event:MouseEvent):void
{
addChild(movieMoon);
}
I don't recommend doing it this way as it can make things needlessly complex. For a single button now, you have 3 times as many movie clips/sprites, add/remove child event handlers, and other variables to check/debug for. Multiply this by however many buttons you have.
Instead, I'd recommend using or extending the SimpleButton{} class or writing your own class to encapsulate the behaviour.
SimpleButton class: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/SimpleButton.html
I think you should encapsulate your three moon states into a separate MovieClip that will control all the moon phase changing by itself. If it's already so, fine. The general principle with such a MovieClip-Button type objects is that the listener is assigned to the parent instance, not the parts of that button.
public class Moon extends Sprite {
private var upState:swayingMoon=new swayingMoon();
private var overState:glowMoon=new glowMoon();
private var downState:clickedMoon=new clickedMoon();
private var areWeClicked:Boolean;
private var areWeOver:Boolean;
public function Moon() {
areWeClicked=false;
areWeOver=false;
addChild(upState);
addEventListener(MouseEvent.ROLL_OVER, showHoverMoon);
addEventListener(MouseEvent.ROLL_OUT, hideHoverMoon);
addEventListener(MouseEvent.CLICK, showClickedMoon);
addEventListener(Event.COMPLETE, hideClickedMoon);
}
private function showHoverMoon(e:MouseEvent):void {
areWeOver=true;
if (areWeClicked) return;
removeChild(upState);
addChild(overState);
}
private function hideHoverMoon(e:MouseEvent):void {
areWeOver=false;
if (areWeClicked) return;
removeChild(overState);
addChild(upState);
}
private function showClickedMoon(e:MouseEvent):void {
if (areWeClicked) {
downState.gotoAndPlay(1);
return;
}
if (overState.parent) removeChild(overState); else removeChild(upState);
addChild(downState);
downState.gotoAndPlay(1); // your clicked moon seems to be a playing MC, so starting it over
areWeClicked=true;
}
private function hideClickedMoon(e:Event):void {
if (e.target!=downState) return; // not our event
if (!areWeClicked) return;
areWeClicked=false;
removeChild(downState);
if (areWeOver) addChild(overState); else addChild(upState);
}
}
Now, your parent class is controlling what happens and when. I was under assumption that your clickedMoon MC will only play once fully, then dispatch an event Event.COMPLETE to itself, so that its parent will get notified and will act.
Originally, your event listener structure prevented you from hiding mainMoon MC, otherwise your other listener will never act, now you are using parent object to listen to events, and can safely remove parts of your moon.
Just for a custom button you are going too much complex way. one movieClip is enough for create the button. First create a movieClip and inside that movieClip's timeline create two more frame for 'hover' and click effect. here is little bit of code to start.
var myButton_btn:CustomButton = new CustomButton();
addChild(myButton_btn);
myButton_btn.x = 100;
myButton_btn.y = 100;
myButton_btn.addEventListener(MouseEvent.ROLL_OVER, onOver);
myButton_btn.addEventListener(MouseEvent.ROLL_OUT, onOut);
myButton_btn.addEventListener(MouseEvent.CLICK, onClick);
function onOver(event:MouseEvent):void {
//trace('over');
event.target.gotoAndStop('hover');
}
function onOut(event:MouseEvent):void {
//trace('normal');
event.target.gotoAndStop('normal');
}
function onClick(event:MouseEvent):void {
//trace('click');
event.target.gotoAndStop('click');
}

ActionScript3, moving objects of type movieclip

Here i am trying to create a new movieclip type object, which is moved when function mvBall is called. When i run the code i get this err: implicit coercion of a value with static type object to a possibly unrelated type flash.display:MovieClip. Later on i want to be able to make the ball bounce back when it colides with another object. I'm new to action script and don't really know how things work so any help would be appreciated. Here's the code:
private function frame(x:Event):void {
var ball:MovieClip = new MovieClip();
ball.addEventListener(Event.ENTER_FRAME, animate);
ball.graphics.beginFill(0xff0000);
ball.graphics.drawCircle(100, 100, 15);
ball.graphics.endFill();
stage.addChild(ball);
}
private function animate(ev:Event):void {
mvBall(ev.target);
}
private function mvBall(mc:MovieClip) {
mc.x += 10;
}
You need to cast the target to MovieClip
private function animate(ev:Event):void {
mvBall(ev.target as MovieClip);
}
With that said it is better to just have one ENTER_FRAME handler and animate your objects in there.
stage.addEventListener(Event.ENTER_FRAME, animate);
private function animate(ev:Event):void
{
mvBall(myBall);
//other object animations
}
You are getting this error because the target property of the Event class is of type object.
In order to not throw the error, you need to cast it as a MovieClip:
mvBall(ev.target as MovieClip);
or
myBall(MovieClip(ev.target));
Something else to consider, is the difference between an Events target and currentTarget properties. If you ball had multiple layers/object inside it (sprites or other movieClips), the target would be whichever one of those sub-elements had the mouse over it during the click. currentTarget refers to the object that you've attached the listener to. In your case they may be the same (if your ball doesn't have any movie clips inside it), but your code could have unexpected results if you have sub-movieClips inside your ball.

Event isn't removed from Listener in AS3

I'm developing a drag'n'clone feature for my flash app (AS3 and Flash CS5). The clones are created perfectly, but when I try to drag the clone recently created, the app creates a new clone (and allow me to drag it).
I want to remove this behaviour: clone only should be drag and dropped, not cloned. My code is:
public class Car extends MovieClip
{
// imports...
public function Car()
{
addListeners();
}
private function addListeners():void
{
this.addEventListener(MouseEvent.MOUSE_DOWN,clone);
}
private function clone(e:MouseEvent):void
{
// Clone the object
var newcar = new e.target.constructor;
newcar.graphics.copyFrom(this.graphics);
newcar.x = this.x;
newcar.y = this.y;
this.parent.addChild(newcar);
newcar.addEventListener(MouseEvent.MOUSE_MOVE,dragCar);
newcar.addEventListener(MouseEvent.MOUSE_UP,dropCar);
}
private function dragCar(e:MouseEvent):void
{
e.target.startDrag();
}
private function dropCar(e:MouseEvent):void
{
e.target.stopDrag();
// This line doesn't remove the event, and I don't know why
e.currentTarget.removeEventListener(MouseEvent.MOUSE_DOWN,clone);
e.target.removeEventListener(MouseEvent.MOUSE_MOVE, dragCar);
e.target.removeEventListener(MouseEvent.MOUSE_UP,dropCar);
}
}
I hope someone can help me. Thanks!
Here as you are creating a new instance of Car in the clone function, the constructor of that new Car object is called which in turn calls addListeners() and the clone has a MOUSE_DOWN event listener that again clones the clone. That is why you have the problem you describe.
To avoid this you need to add the following line in you clone function (this does not work see below edit)
newcar.removeEventListener(MouseEvent.MOUSE_DOWN,clone);
this removes the clone event listener from the cloned (new) Car instance and avoids cloning again.
Also to start drag you should do it in MOUSE_DOWN instead of MOUSE_MOVE.
Update
OK I see, MOUSE_DOWN is not called Again for the clone, so you need to use MOUSE_MOVE. Thus in this case I would remove the MOUSE_MOVE listener in the listener's body so that it is only called once.
Update
This seems to remove the event listener.
newcar.removeEventListener(MouseEvent.MOUSE_DOWN, newcar.clone);
You have to refer to the newcar instance's clone method newcar.clone to remove the event listener.
Working Code
The following code is working just fine
package{
import flash.display.MovieClip;
import flash.events.*;
public class Car extends MovieClip
{
public function Car()
{
addListeners();
}
private function addListeners():void
{
this.addEventListener(MouseEvent.MOUSE_DOWN,clone);
}
private function clone(e:MouseEvent):void
{
// Clone the object
var newcar = new e.target.constructor;
newcar.graphics.copyFrom(this.graphics);
newcar.x = this.x;
newcar.y = this.y;
this.parent.addChild(newcar);
// remove the clone listener
newcar.removeEventListener(MouseEvent.MOUSE_DOWN, newcar.clone);
// add dragging listeners
newcar.addEventListener(MouseEvent.MOUSE_MOVE, dragCar);
newcar.addEventListener(MouseEvent.MOUSE_UP, dropCar);
// this is used for dragging the clone
newcar.addEventListener(MouseEvent.MOUSE_DOWN, dragCar);
}
private function dragCar(e:MouseEvent):void
{
// if a MOUSE_MOVE event listener is registered remove it
if(e.target.hasEventListener(MouseEvent.MOUSE_MOVE))
e.target.removeEventListener(MouseEvent.MOUSE_MOVE, dragCar);
e.target.startDrag();
}
private function dropCar(e:MouseEvent):void
{
e.target.stopDrag();
// do not remove the listener if you want the clone to be dragable
// e.target.removeEventListener(MouseEvent.MOUSE_UP,dropCar);
}
}
}
Keep clone dragable
For this in the above code I have added a MOUSE_DOWN event listener for dragging the clone
newcar.addEventListener(MouseEvent.MOUSE_DOWN, dragCar);
And commented out the e.target.removeEventListener(MouseEvent.MOUSE_UP,dropCar); in dropCar
Also added a Check before removing MOUSE_MOVE listener as to whether it is there or not, as this function will be called later by MOUSE_DOWN also.