Actionscript 3: Unintended interruption on MouseOver-listener from moving sprites - actionscript-3

On my stage I have several DisplayObjects. To some of them I have applied a MouseOver functions.
These functions are primarily like this:
this.addEventListener(MouseEvent.MOUSE_OVER, hoverHandler);
private function hoverHandler(evt:MouseEvent):void
{
this.alpha = 2 * this.alpha;
this.addEventListener(MouseEvent.MOUSE_OUT, awayHandler);
}
private function awayHandler(evt:MouseEvent):void
{
this.alpha = this.alpha / 2;
}
This works fine until some of my moving sprites suddenly also is above one of the sprites I have applied Mouseover functions to. Then my MouseOver-function can no longer detect if the mouse is on the sprite.
This is rather disturbing for the usability of my code. Does anyone know how to avoid this?
Thank you!

You can set mouseEnabled and mouseChildren of the Sprites getting in the way to false:
aboveSprite.mouseEnabled = false;
aboveSprite.mouseChildren = false;

Use somethng like:
mc_1.hitTestObject(mc_2);
to determine an overlap. Then discover which MovieClip is 'above' the other with something like
parent.getChildIndex(this)
Then use mouseEnabled = false to de-sensitize the MovieClip that you don't want to respond.
Your exact code may vary somewhat depending on the setup.

Related

AS3 tween object not working with .hitTestObject()

I am having a major problem in my new browser app.
Okay so I made game where different cubes (squares) spawn at the top of the screen and I use the Tween class to make them go down the screen and then disappear.
However I want to detect a collision when a cube hits the player (that is also a flying cube).
I tried everything, truly everything but it does not seem to work. The problematic thing is that when I remove the "Tween" function it does detect collision with the hitTestObject method but when I add the "Tween" line collision won't be detected anymore.
It looks like this:
function enemiesTimer (e:TimerEvent):void
{
newEnemy = new Enemy1();
layer2.addChild(newEnemy);
newEnemy.x = Math.random() * 700;
newEnemy.y = 10;
if (enemiesThere == 0)
{
enemiesThere = true;
player.addEventListener(Event.ENTER_FRAME, collisionDetection)
}
var Tween1:Tween = new Tween(newEnemy, "y", null, newEnemy.y, newEnemy.y+distance, movingTime, true);
}
And the collision detection part:
private function collisionDetection (e:Event):void
{
if (player.hitTestObject(newEnemy))
{
trace("aaa");
}
}
I am desperate for some information/help on the topic, it's been bugging me for days.
Thanks for your time, I would be very happy if someone could help me out^^
First, make sure the "newEnemy" instance and the "player" instance are within the same container. If they are not, their coordinate systems might not match up and could be the source of your problem.
Otherwise, you need to keep a reference to each enemy instance you create. It looks like you are only checking against a single "newEnemy" variable which is being overwritten every time you create a new enemy. This might be why you can successfully detect collision between the player and the most recent "enemy" instance.
So... you need a list of the enemies, you can use an Array for that.
private var enemyList:Array = [];
Every time you create an enemy, push it to the Array.
enemyList.push(newEnemy);
In your "collisionDetection" function, you need to loop through all of the enemies and check if the player is touching any of them.
for(var i:int = 0; i < enemyList.length; i++)
{
var enemy = enemies[i];
if (player.hitTestObject(enemy))
{
trace("Collision Detected!");
enemy.parent.removeChild(enemy); // remove the enemy from the stage
enemies.splice(i, 1); // remove the enemy from the list
}
}
I'd suggest that you move to TweenMax, it just might solve your problem, and in my experience it's much better in every possible way.
Scroll down the following page to see a few variations of this library, I myself use TweenNano, they're completely free of charge:
https://greensock.com/gsap-as
I think some plugins cost money, but I doubt you'll ever need them.

How to use CitrusSprite.velocity

I have the following function in a scene that extends citrus.core.starling.StarlingState - it loads the PlayerRun animation and displays it on the screen. For the most part, this code works: I see the sprite on the screen (it's running in place).
protected final override function DrawScene ():void
{
Player = new CitrusSprite ( "Player" );
Player.velocity = [60, 0]; // Doesn't seem to have an effect
Player.x = 40;
Player.y = 40;
var oClip:MovieClip = new MovieClip ( Resources.getTextures (
"PlayerRun" ), 24 );
Player.view = oClip;
add ( Player );
}
I'm not sure how I'm supposed to use the velocity property - there's no documentation for it and no matter what numbers I use in the code above, it doesn't change the display: the animation plays but the sprite is stationary (it doesn't move horizontally as I would expect it).
Am I using the velocity property incorrectly? Does Citrus support sprite velocity or is this something I'd have to implement myself?
As it turns out, CitrusSprite has a property, updateCallEnabled that's false by default and disables calls to update(). Once I set this property to true, the code started working as expected.
I haven't used Citrus yet, but looking at the source code it should work the way you've gone about it assuming that the update method is called on your player:
You can review the way the velocity property works at these locations:
The getter and setter for velocity.
The update loop for CitrusSprite.
MathVector, the type used for velocity internally.
I suspect you need to add the player to something that will queue it for updating.

AS3 - Trying to declare the value of a Movie Clip

Okay, I have the following code in my Bullet.as file:
public var impact:MovieClip;
public function Bullet():void
{
addEventListener(Event.ADDED_TO_STAGE, whenAdded);
}
function whenAdded(e:Event)
{
if(this is zArrow){
power = -1;
speed = 15;
impact = arrowImpact;
trace(impact);
}
if(this is Dice){
power = -Math.round(Math.random()*5 + 1);
speed = 10;
impact = diceImpact
}
}
See, I am trying to set the value of "public var impact:MovieClip" as the movie clip "arrowImpact" or "diceImpact". What I want is whenever a bullet collides with an enemy, it leaves an impact image behind and I'm trying to change what impact is shown depending on what bullet is colliding.
I am able to change all of the other variables like power and speed using this setup, but I can't declare which impact movie clip the "impact" movie clip variable is.
From the way I understand your question now, you want to pull these specific movie clips from the Library. If I am not mistaken. To do this, you need to pair each of the movie clips in the library to an AS class that extends MovieClip.
Make sure you check "Export for Actionscript" and create the class you want for each. Then, in your code for the Bullet, you can create a new instance of them. So have it say:
impact = new ArrowImpact)();
or DiceImpact depending on your classes.
Hope this is along the lines of what you wanted.
In order to use these, I would recommend creating a getImpact method along the lines of:
public function getImpactMC():MovieClip
{
return impact;
}
Then all you need to do in your main Document is addChild the proper impact from this method. However, be aware that you need to adjust the x and y values of the impactMC before adding it as a child on the stage to make sure that it displays in the proper position.
Glad this helps!

AS3 Determine if MovieClip fills another MovieClip completely

I am trying to determine in AS3 Flash if a draggable movieclip on the stage completely fills another movieclip also on the stage. I looked into another StackOverflow article with this code:
var inter = mcOverlay.getRect(this).intersection(mcLoadedImage.getRect(this));
if ((inter.width * inter.height) == 0) {
return false;
} else {
return true;
}
This code uses the intersect method, it works, but I also want to check that the movieclip is completely covered by the draggable movieclip on the stage.
Any suggestions? Thanks!
I think you could use compare each movieclips rect, ie compare the left, right, top and bottom values.
Instead of using intersection, use Rectangle.contains.
var contains : Boolean = mcContainer.getRect(this).contains(mcContained.getRect(this));
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/geom/Rectangle.html#containsRect()

AS3 layer order

I created two empty Sprites to serve as layers, bottom_spr and top_spr
When clicking a button, a MovieClip appears and follows your mouse, untill you click, then its position is fixed.
As soon as the button is clicked, I addChild the MovieClip to the correct Sprite.
Unfortunately, the layer system doesn't see to work, because they are layered in the order I place them, the Sprites don't seem to influence it.
How is this possible?
private var ground_spr:Sprite;
private var units_spr:Sprite;
public function Game() {
addEventListeners();
ground_spr = new Sprite();
units_spr= new Sprite();
addChild(ground_spr);
addChild(units_spr);
}
private function addEventListeners(){
groundBtn.addEventListener(MouseEvent.CLICK, clickGroundBtn);
unitBtn.addEventListener(MouseEvent.CLICK, clickUnitBtn);
}
private function clickGroundBtn(event:MouseEvent){
var ground = new Ground_mc();
follow();
ground_spr.addChild(ground);
}
private function clickUnitBtn(event:MouseEvent){
var unit = new Unit_mc();
follow();
units_spr.addChild(unit);
}
Your question is very vague but I will attempt to answer it. If you clarify how you want your objects ordered exactly, I can better answer your question. It is fine to add layer of abstraction over the depth handling, if you need it. In this case I dont see much of a need, but I will show you a few things you could do.
To add an object to the back of the screen:
this.setChildIndex(objName, 0);
To add an object to the front of the screen:
this.setChildIndex(objName, this.numChildren - 1);
To swap the depths of two objects:
this.swapChildren(objA, objB);
//Note this is expecting two DisplayObjects so you may have to do:
this.swapChildren(objA as DisplayObject, objB as DisplayObject);