I have 2 copies of a MovieClip (mcA) on my main timeline. Within mcA, I have 5 more MovieClips (mcB) and this code:
addEventListener(MouseEvent.CLICK, clickedPoint);
function clickedPoint(e:MouseEvent) {
e.target.play();
setStat(e.target.parent);
}
So I toggle the frame of the mcB that was clicked, and I run a function that references the corresponding mcA on the main timeline.
In setStat, I call another function that checks the currentFrame of all the mcBs in the mcA.
getPoints(stat) {
var points = 0;
for(var i = 1; i <= 5; i++)
{
if(stat["pnt"+i].currentFrame == 2) points++;
}
trace(points);
return points;
}
My problem is that the setStat function seems to run before the currentFrame of the mcB that has been clicked on updates.
How should I change my code so that the mcB that is clicked on registers as having changed its currentFrame when I call setStat?
You could call setStat() after the next frame update. A simple way to do this is to add an ENTER_FRAME event handler which removes itself when first invoked:
function clickedPoint(e:MouseEvent) {
e.target.play();
e.target.addEventListener(Event.ENTER_FRAME, function(e:Event):void {
e.target.removeEventListener(Event.ENTER_FRAME, arguments.callee);
setStat(e.target.parent);
});
}
You can encapsulate this behavior in a function that behaves like setTimeout:
function callNextFrame(target:DisplayObject, callback:Function, ...params:Array):void {
target.addEventListener(Event.ENTER_FRAME, function(e:Event):void {
target.removeEventListener(Event.ENTER_FRAME, arguments.callee);
callback.apply(null, params);
});
}
// Usage:
callNextFrame(e.target as DisplayObject, setStat, e.target);
Related
Hi so recently I have been attempting to Drag a movie clip in AS3 but I'm having some trouble picking up with the hit tests anyone got any ideas? Just to clarify, the issue is that when the movieclips hit the drag test object, they're not executing the gotoframe() function.
initDrag() adds action listeners:
MOUSE_DOWN on the object
MOUSE_UP on the stage so it doesn’t matter if you are off the object
endDrag() removes the action listeners; call this (for each object) before you go to another frame
startADrag()create a rectangle within which the object can be dragged (in this case the stage)
call startDrag() on the object
stopADrag() call stopDrag() on the object from currentObject (but only if currentObject is not null).
var currentObject:MovieClip = null;
initDrag(block1);
initDrag(block2);
initDrag(block3);
initDrag(block4);
function initDrag(obj:MovieClip )
{
obj.addEventListener(MouseEvent.MOUSE_DOWN,startADrag);
stage.addEventListener(MouseEvent.MOUSE_UP,stopADrag);
}
function endDrag(obj:MovieClip )
{
obj.removeEventListener(MouseEvent.MOUSE_DOWN,startADrag);
stage.removeEventListener(MouseEvent.MOUSE_UP,stopADrag);
}
function startADrag(e:MouseEvent):void
{
currentObject = (MovieClip)(e.target);
var rect:Rectangle = new Rectangle(0,0,stage.stageWidth - currentObject.width,stage.stageHeight - currentObject.height + 100);
currentObject.startDrag(false,rect);
}
function stopADrag(e:MouseEvent):void
{
if (currentObject != null)
{
currentObject.stopDrag();
}
}
if(block1.hitTestObject(dragtest)){
gotoAndStop("lose");
}
if(block2.hitTestObject(dragtest)){
gotoAndStop(27);
}
if(block3.hitTestObject( dragtest)){
gotoAndStop("lose");
}
if(block4.hitTestObject( dragtest)){
gotoAndStop("lose");
}
thanks for any advice or answers.
The following code should work as expected. The problem is, as i already stated in my comment, that your calls to hitTestObject(obj) only get executed once, at the very beginning of your application. What you need to do though is to check it constantly.
Think about it, if your calls to hitTestObject-calls only get executed once at the beginning, when you didn't even have a chance to drag one of your objects, it will always return false, right? Because your objects are still in their initial position (outside of the dragtest objecti must assume).
With an event listener for Event.ENTER_FRAME you check it once per frame instead. So even if all the results for hitTestObject are false, it will check them all again on the next frame (if you are currently dragging, controlled through a simple boolean called dragging).
var currentObject:MovieClip = null;
var dragging:Boolean = false;
initDrag(block1);
initDrag(block2);
initDrag(block3);
initDrag(block4);
addEventListener(Event.ENTER_FRAME, checkForHit);
function checkForHit(e:Event):void{
if(dragging){
if(block1.hitTestObject(dragtest)){
gotoAndStop("lose");
}
if(block2.hitTestObject(dragtest)){
gotoAndStop(27);
}
if(block3.hitTestObject( dragtest)){
gotoAndStop("lose");
}
if(block4.hitTestObject( dragtest)){
gotoAndStop("lose");
}
}
}
function initDrag(obj:MovieClip )
{
obj.addEventListener(MouseEvent.MOUSE_DOWN,startADrag);
stage.addEventListener(MouseEvent.MOUSE_UP,stopADrag);
}
function endDrag(obj:MovieClip )
{
obj.removeEventListener(MouseEvent.MOUSE_DOWN,startADrag);
stage.removeEventListener(MouseEvent.MOUSE_UP,stopADrag);
}
function startADrag(e:MouseEvent):void
{
currentObject = (MovieClip)(e.target);
var rect:Rectangle = new Rectangle(0,0,stage.stageWidth - currentObject.width,stage.stageHeight - currentObject.height + 100);
currentObject.startDrag(false,rect);
dragging = true;
}
function stopADrag(e:MouseEvent):void
{
if (currentObject != null)
{
currentObject.stopDrag();
dragging = false;
}
}
I was wondering on how to register a Hittest between two Movie Clips only if the MOUSE_DOWN event is equal to true.
So I have a Movie Clip called playerHook that acts as the Mouse and whenever that movie clip comes in contact with another movie clip called octopusBoss and Clicks on it I want it to register a hittest and subtract a point from its health.
Here is what I have so far but not sure what to do next:
In my main constructor function:
playerHook.addEventListener(Event.ENTER_FRAME, playerHookMove);
playerHook.addEventListener(MouseEvent.MOUSE_DOWN, onMDown);
playerHook.addEventListener(MouseEvent.MOUSE_UP, onMUp);
Then I have two booleas set up in the two functions onMDown and onMUp:
private function onMDown(e:MouseEvent):void
{
mouseIsDown = true;
}
private function onMUp(e:MouseEvent):void
{
mouseIsUp = false;
}
Then I have this function which is currently in my gameloop that I would want to happen only if the user clicks on the OctopusBoss:
private function checkPlayerHitOctopusBoss():void
{
if (playerHook.hitTestObject(octopusBoss))
{
trace("Hit Octopus");
octopusBossHealth --;
}else
if (octopusBossHealth <= 0)
{
octopusBoss.destroyOctopusBoss();
}
}
But I am having trouble passing the mouse booleans to the if statement. I know I am missing something crucial!
First you need some name to your octopusBoss like so:
octopusBoss.name = "octopusBoss";
Modify your onMDown function like so:
private function onMDown(e:MouseEvent):void
{
if(e.target.name == "octopusBoss") //Check if octopusBoss is under mouse
mouseIsDown = true;
}
And your checkPlayerHitOctopusBoss function like so:
private function checkPlayerHitOctopusBoss():void
{
if (playerHook.hitTestObject(octopusBoss) && mouseIsDown) // check mouse down
{
trace("Hit Octopus");
octopusBossHealth --;
}else
if (octopusBossHealth <= 0)
{
octopusBoss.destroyOctopusBoss();
}
}
UPDATE:
If it's ok to add MouseEvents directly to octopusBoss like so:
octopusBoss.addEventListener(MouseEvent.MOUSE_DOWN, onMDown);
octopusBoss.addEventListener(MouseEvent.MOUSE_UP, onMUp);
Then, you can also use e.currentTarget.name.
Hey guys I am having a problem with Event Listeners in my AS3 file. I am trying to make this object that lasts for 83 frames to appear in a different location every time the parent (83 frame) movie clip resets. The problem is I have a function that places the object at a random y value which works great once. When it resets the ojbect appears on the same Y point. This is because I removeEventListener the function otherwise the object goes shooting off the screen when it loads. How do I call that event listener again without causing a loop that will shoot the object off screen?
Here is my code:
import flash.events.Event;
stop();
addEventListener(Event.ENTER_FRAME, SeaWeedPostion);
//stage.addEventListener(Event.ADDED_TO_STAGE, SeaWeedPostion);
function SeaWeedPostion(e:Event):void{
// if(newSeaWeed == 1) {
var randUint:uint = uint(Math.random() *500 + 50);
this.seaweedSet.y += randUint;
trace(randUint);
stopPos();
//}else{
//nothing
// }
}
function stopPos():void{
removeEventListener(Event.ENTER_FRAME, SeaWeedPostion);
//var newSeaWeed = 0;
}
function resetSeaWeed():void{
addEventListener(Event.ENTER_FRAME, SeaWeedPostion);
}
I have some // code in there from trying different things.
Anyone have any suggestions?
Thanks!
ENTER_FRAME event is triggered every frame, so rather than changing position on each frame maybe it's better to create a counter, count frames and if it reaches 82 change position of SeaWeed.
var counter:uint = 0;
Now add ENTER_FRAME listener
addEventListener(Event.ENTER_FRAME, onEnterFrame);
function SeaWeedPostion(e:Event):void {
counter++;
//Are we there yet?
if(counter < 83) {
//Nope, carry on
}
else {
//Yey!
changePosition();
counter = 0;
}
}
//Reset SeaWeed position when called
function changePosition() {
var randUint:uint = uint(Math.random() *500 + 50);
this.seaweedSet.y += randUint;
trace(randUint);
}
Upon the click of a button, an animation starts. Then the program directs you to a certain frame when the animation is done.
Is this possible?
So this is what I've got so far: a Movie Clip movQuizIntro and a Button btnBond in Frame 1.
stop()
movQuizIntro.stop()
btnBond.addEventListener(MouseEvent.CLICK, BondQuiz)
btnReg.addEventListener(MouseEvent.CLICK, Registrering)
function BondQuiz (evt:MouseEvent)
{
if (currentFrame == 1)
{
movQuizIntro.alpha = 1
movQuizIntro.play()
}
}
What is the code and proper syntax you need to write in order to go to frame 2 after the animation is done?
`
stop();
movQuizIntro.stop();
int frameCounter=0;
btnBond.addEventListener(MouseEvent.CLICK, BondQuiz);
btnReg.addEventListener(MouseEvent.CLICK, Registrering);
function BondQuiz (evt:MouseEvent)
{
if (currentFrame == 1)
{
movQuizIntro.alpha = 1
movQuizIntro.play()
movQuizIntro.addEventListener(EventType.ENTER_FRAME, onEnterFrame);
}
}
// event handler function, runs every enter frame
private function onEnterFrame(event:Event):Void
{
frameCounter++;
if(frameCounter > movQuizIntro.totalFrames)
{
//Place code here because you know the MovieClip finished playings
//Go to desired frame
}
}
`
I wrote this code outside of an editor nor did I get to compile, so the gist is there and may have some minor errors.
NOTE:This is just a quick way of doing this. If you want something more reusable/cleaner then you would want to consider subclassing or alternate Object Oriented tricks.
In button event handler:
function onClick(e:MouseEvent):void{
ANIMATION_MC.addEventListener(Event.EXIT_FRAME, onFromeExit);
}
function onFrameExit(e:Event):void {
if (ANIMATION_MC.currentFrame == SOME_FRAME) {
ANIMATION_MC.removeEventListener(Event.EXIT_FRAME, onFromeExit);
TARGET.gotoAndPlay(NEW_FRAME);
}
}
And you can just use addFrameScript on ANIMATION_MC too.
I'm calling a timerEvent function from enterFrame, it's running the timerEvent function on everyFrame. Is there a way to control it?
I've got my bullets firing function with timerEvent of 500, so it shoots a bullet every half a second on 24fps. It's working fine for now. Now I want to change bullet speed and skin with respect to weapon.
////////////////////////////////
//this function is called first time within an EnterFrame function
///////////////////////////////
function weaponCheck():void
{
switch (weaponState)
{
case STATE_GUN :
gun();
break;
case STATE_DOUBLE_GUN :
doubleGun();
break;
}
}
function gun():void
{
trace("single gun");
laserTimer = new Timer(600);
laserTimer.addEventListener(TimerEvent.TIMER, timerListener);
laserTimer.start();
function timerListener(e:TimerEvent):void
{
var tempLaser:MovieClip = new Laser();
var tempGunBlast:MovieClip = new Gun_blast_01();
tempLaser.x = player.x +((player.width/2)+12);
tempLaser.y = player.y;
tempGunBlast.x = stage.mouseX + 104;
tempGunBlast.y = tempLaser.y;
Lasers.push(tempLaser);
addChildAt(tempLaser,1);
addChildAt(tempGunBlast, 3);
if (tempGunBlast.currentFrame >= tempGunBlast.totalFrames)
{
removeChild(tempGunBlast);
}
}
}
function doubleGun():void
{
trace("Double gun");
doubleGunTimer = new Timer(400);
doubleGunTimer.addEventListener(TimerEvent.TIMER, timerListener2);
doubleGunTimer.start();
function timerListener2(e:TimerEvent):void
{
var tempLaser:MovieClip = new doubleG();
var tempGunBlast:MovieClip = new Gun_blast_01();
tempLaser.x = player.x +((player.width/2)+12);
tempLaser.y = player.y;
tempGunBlast.x = stage.mouseX + 104;
tempGunBlast.y = tempLaser.y;
Lasers.push(tempLaser);
addChildAt(tempLaser,1);
addChildAt(tempGunBlast, 3);
if (tempGunBlast.currentFrame >= tempGunBlast.totalFrames)
{
removeChild(tempGunBlast);
}
}
}
///////////////////////////////////////////////////
//Following function is called within an enterFrame event function
/////////////////////////////////////////////////
function playGame():void
{
weaponCheck();
blah1();
blah2();
blah3();
testForEnd();
}
function testForEnd():void
{
if (level == 3)
{
laserTimer.stop();
weaponState = STATE_DOUBLE_GUN;
weaponCheck();
}
}
So when the game runs for first time, it works fine and uses the timer event of 600 to hit the bullets, but when level == 3 and weaponState changes, the 2nd firing function doubleGun(); is called but it starts to fire the bullets on a per frame count, not on a controlled timerEvent. Please Help. Thanks.
Why don't you drop timers and use enter frame listener as a manner to count time? You are already calling weaponCheck() from an enterframe listener. Make it so that the actual gun() and doublegun() calls will only generate animation, such as firin' mah lazers and blasts, and the main function will just count time.
function weaponCheck():void
{
this.reloading+=this.weaponFiringSpeed; // you alter this to make your weapon fire slower or faster
if (this.reloading<FULLY_RELOADED) return; // we are not yet ready to fire
this.reloading=0;
switch (weaponState) // and here we fire with the gun state
{
case STATE_GUN :
gun();
break;
case STATE_DOUBLE_GUN :
doubleGun();
break;
}
}
function gun():void
{
trace("single gun");
var tempLaser:MovieClip = new Laser();
var tempGunBlast:MovieClip = new Gun_blast_01();
tempLaser.x = player.x +((player.width/2)+12);
tempLaser.y = player.y;
tempGunBlast.x = stage.mouseX + 104;
tempGunBlast.y = tempLaser.y;
Lasers.push(tempLaser);
addChildAt(tempLaser,1);
addChildAt(tempGunBlast, 3);
}
And similarly double gun. FULLY_RELOADED is a constant, reloading is a variable used to track time, it should be a property of the one who's firing.
Note, this approach requires you to manage your "tempGunBlast"s elsewhere, perhaps in the very weaponCheck function, if so, modify it as follows:
function weaponCheck():void
{
if (tempGunBlast) if (tempGunBlast.currentFrame >= tempGunBlast.totalFrames)
removeChild(tempGunBlast);
this.reloading+=this.weaponFiringSpeed; // you alter this to make your weapon fire slower or faster
if (this.reloading<FULLY_RELOADED) return; // we are not yet ready to fire
... // rest of code unchanged
You will most likely not be able to copypastely implement this, but please try.