as3 hittestobject will activate without running parameters - actionscript-3

Alright the problem is that I'm trying to make a sphere disappear only when it is touching my crosshair, the problem is that the sphere will disappear whether the crosshair is touching it or not.
My symbols are:
crosshair with an instance of crosshair on the stage
target with an instance of targetBlue on the stage
Mouse.hide();
crossHair.startDrag(true);
stage.addEventListener(MouseEvent.CLICK, _onStageMouseDown);
function _onStageMouseDown(e:MouseEvent):void
{
if (crossHair.hitTestObject(targetBlue), true)
{
targetBlue.visible = false;
trace("the mouse is in the target");
} else if (crossHair.hitTestObject(targetBlue), false){
trace("the mouse is not in the target");
}
}

Your If-Statement is kinda weird.
Try it like this:
if (crossHair.hitTestObject(targetBlue) == true) {
targetBlue.visible = false;
trace("the mouse is in the target");
} else {
trace("the mouse is not in the target");
}
Btw, since you're probably making some sort of shooting game, I suggest you check out the hitTestPoint() function, which will be much more suitable for this.

Related

Flash CS3 AS3 Movieclips carrying over to other frames

OK so I am having a weird issue. I have some movieclips on screen, 4 of them, each with the following code (with different instance names of course):
stage.addEventListener(MouseEvent.MOUSE_DOWN,globalMouseDown,false,0,true); //add a global mouse listener
function globalMouseDown(e:Event):void {
//find out if the target is a descendant of this, if not, then something else was clicked.
var parent:DisplayObject = e.target as DisplayObject;
while(parent && parent != stage){
if(parent == this) return;
parent = parent.parent;
}
//something else was clicked that wasn't this, so go to the up state
gotoAndStop(1);
}
stop();
addEventListener(MouseEvent.MOUSE_DOWN, onHs1Press);
addEventListener(MouseEvent.MOUSE_OVER, onHs1Over);
addEventListener(MouseEvent.MOUSE_OUT, onHs1Out);
function onHs1Press(event:MouseEvent):void
{
// toggle between frame 1 and 3 on button press
gotoAndStop(this.currentFrame == 3 ? 1 : 3);
parent.addChild(this)
}
function onHs1Over(event:MouseEvent):void
{
if (currentFrame != 3)
{
gotoAndStop(2);
}
}
function onHs1Out(event:MouseEvent):void
{
// only switch back to UP state if the button is "pressed"
if (currentFrame != 3)
{
gotoAndStop(1);
}
}
Basically it lets you hover your mouse and the movieclip changes and then when you click on it a little pop up window appears until you click the movieclip again to close it.
There is also a button on screen that allows you to move forward or backwards to other frames with this code:
Next.addEventListener(MouseEvent.CLICK,Nclick);
function Nclick(event:MouseEvent):void {
nextFrame();
}
Back.addEventListener(MouseEvent.CLICK,Bclick);
function Bclick(event:MouseEvent):void {
prevFrame();
}
The button code is on the main timeline and the movieclip code is on the movieclip's timeline.
For some reason if you have the movieclip in the DOWN state (with the popup window open) and you click the button to go to the next frame, the movieclip follows onto the next and any other frames instead of just going away.
I have this same code present on other frames and none of the other ones behave this way, it's really weird.
You can even click it still when its on the other frames and bring up the popup window where the movieclip and code aren't even present.
What's going on with it?
I tried testing this, and could reproduce your issue. If you add a movieclip to the stage in FlashPro, after changing it's index or parentage, it will from that point on be treated like an object created from code and the timeline will ignore it and even create another instance of it on a frame where it is created.
You'll have to manually remove the buttons from the display list.
function Nclick(event:MouseEvent):void {
nextFrame();
removeBtns();
}
function Bclick(event:MouseEvent):void {
prevFrame();
removeBtns();
}
function removeBtns():void {
if(currentFrame != 2){ //whatever the frame of your buttons is
if(btn1 && btn1.parent) removeChild(btn1); //btn1 being whatever your button instnace name is
if(btn2 && btn2.parent) removeChild(btn2); //repeat for all buttons
}
}
OR If you'd prefer to have encapsulated code, instead of the above, put this on your button class/timeline:
var myFrame:int = MovieClip(parent).currentFrame;
this.addEventListener(Event.ENTER_FRAME,enterFrameHandler);
this.addEventListener(Event.REMOVED_FROM_STAGE,removedHandler);
function enterFrameHandler(e:Event):void {
if(MovieClip(parent).currentFrame != myFrame){
parent.removeChild(this);
}
}
function removedHandler(e:Event):void {
this.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
this.removeEventListener(Event.REMOVED_FROM_STAGE, removedHandler);
}

Animated presentation navigation by arrows - AS3

I'm new to AS3 and although I was looking for a solution to my problem truly long time, I was not successful. I have an animated presentation and I just want to make navigation through that by arrows. Everything is on the main timeline. In the first frame I made this code
var zpet: Number;
if (currentFrame == 1) {
zpet = 1;
}
stage.addEventListener(KeyboardEvent.KEY_DOWN, posun);
function posun(event: KeyboardEvent): void {
if (event.keyCode == 37) {
addEventListener(Event.ENTER_FRAME, playReverse);
function playReverse(event: Event): void {
if (currentFrame == zpet) {
stopPlayReverse();
} else {
prevFrame();
}
}
function stopPlayReverse(): void {
if (hasEventListener(Event.ENTER_FRAME)) {
removeEventListener(Event.ENTER_FRAME, playReverse);
}
}
} else if (event.keyCode == 39) {
if (currentFrame < totalFrames - 1) {
play();
} else {
stop();
}
}
}
stop();
Moving forward works perfect as I put stop(); in every keyframe of the presentation. The problem is how to go back just to the previous keyframe (and I also want to go back in reverse playing). I thought it would be quite easy if I made a variable (called "zpet") and set it the specific number of frame where to go back in each keyframe. But it doesn't work, all the time it's going back to frame 1. For example I put in the frame 26 the code zpet = 13; that should say when playing back from the frame 26 stop at the frame 13. Any ideas how to solve this? I would be really grateful for that..
You can label each keyframe of your animation anything you want directly from the timeline and then something like this :
function playReverse(event: Event): void
{
prevFrame();// You can also use gotoAndStop(currentFrame - 1)
if(currentFrameLabel != null)
stopPlayReverse();
}
Looks cleaner imo, plus you can use labels value later in case you make a scene selection menu.

AS3 collision detection is not recognized

I'm quite new to AS3, and I need some help. I'm trying to make a game like Mario. I've made a character which can jump right now, but I've got some problems with collision detection.
I would like my character to jump on a bar, which is placed higher. My collision detection doesn't work at all I gues..
I've made a cirle which has a instance name mcMain and I've made a MovieClip of it. T also made a rectangle which has a instance name balkje, I also made aMovieClip of it.
I hope you can tell me what is wrong about my code and what I've to change to make the collision detection work! Thanks a lot!
balkje.addEventListener(KeyboardEvent.KEY_DOWN, drag);
stage.addEventListener(KeyboardEvent.KEY_UP, drop);
function drag(e:KeyboardEvent):void
{
e.target.startDrag();
}
function drop(e:KeyboardEvent):void
{
stopDrag();
if (balkje.hitTestObject(mcMain))
{
trace("Collision detected!");
}
else
{
trace("No collision.");
}
}
I think you should be using mouseEvent, not keyboard event.
How can you drag with the keyboard?
balkje.addEventListener(MouseEvent.MOUSE_DOWN, drag);
balkje.addEventListener(MouseEvent.MOUSE_UP, drop);
function drag(e:MouseEvent):void
{
e.target.startDrag();
}
function drop(e:MouseEvent):void
{
e.target.stopDrag();
if (balkje.hitTestObject(mcMain))
{
trace("Collision detected!");
}
else
{
trace("No collision.");
}
}

AS3 Stop character from moving through walls

I want to stop the movieclips movement when it hits a wall (another movieclip).
The example below works, but after the collision the movieclip 'blocks' all movement to the left...
My question to you is, is this a good way and why isn't it working well?
There will be something wrong in this code, but i'm learning.
For now the example with the leftArrow key;
variables to check the key, if it's hitting the walls and if it's moving or not:
var leftArrow:Boolean;
var speed:int = 10;
var hitting:Boolean;
var ismoving:Boolean;
event listeners for the keys/movement and detecting collision:
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
stage.addEventListener(KeyboardEvent.KEY_UP, keyReleased);
stage.addEventListener(Event.ENTER_FRAME, walking);
stage.addEventListener(Event.ENTER_FRAME, detectHit);
detecting collision function:
function detectHit(e:Event) :void
{
if(char.hitTestObject(bounds))
{
hitting = true;
}
}
function to the left arrow key:
function keyPressed(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.LEFT)
{
leftArrow = true;
}
}
function keyReleased(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.LEFT)
{
leftArrow = false;
}
}
And the reason it's not working is probably here, but I don't understand why not:
function walking(event:Event):void {
if (rightArrow) {
char.x += speed;
}
if (leftArrow && ! hitting) {
char.x -= speed;
}
else
{
ismoving = false
}
if (leftArrow && ! hitting)
char will move if hitting is false. When char.hitTestObject(bounds) is true you are setting hitting to true. You are not setting hitting again to false anywhere. That's why once left wall is hit it stops left movement permanently. You need to figure out suitable condition to set hitting to false again.
Adding an else branch in detectHit should solve the problem.
function detectHit(e:Event):void {
if(char.hitTestObject(bounds))
{
hitting = true;
} else {
hitting = false; // add this
}
}
Allthough Taskinoor's method should work, I would suggest another way to do your hittests.
Since you probably are creating a game (character and bounds), you will have more than one bound. In that case, I would strongly suggest bitmap-hittesting. This way, you can create all your bounds in one movieclip and test for a hit.
I will explain this by using the example of a maze. The maze would then be some lines in a movieclip, randomly put together. If you use HitTestObject and you aren't hitting one of the lines, but your character is over the movieclip, hitTestObject will return true, even though you are not hitting a wall. By using bitmapHitTesting, you can overcome this problem (BitmapHitTest takes transparant pixels into account, whereas hitTestObject does not).
Below you can find an example of how to do bitmapHitTesting. Creating the bitmaps in this function is not necesarry if they do not change shape. In that case, I would suggest placing the code for the bitmapdata in a added_to_stage-method.
private var _previousX:int;
private var _previousY:int;
private var _bmpd:BitmapData ;
private var _physicalBitmapData:BitmapData;
private function walkAround(e:Event):void
{
var _xTo:int = //Calculate x-to-position;
var _yTo:int = //Calculate y-to-position;
//If your character doesn't change shape, you don't have to recalculate this bitmapData over and over.
//I suggest placing it in a ADDED_TO_STAGE-Event in that case.
_bmpd = new BitmapData(char.width, char.height, true, 0);
_bmpd.draw(char);
//If your bounds are static, you don't have to recalculate this bitmapData over and over.
//I suggest placing it in a ADDED_TO_STAGE-Event in that case.
_physicalBitmapData = new BitmapData(bounds.width, bounds.height, true, 0);
_bmpd.draw(bounds);
//The below line is the actual hittest
if(_physicalBitmapData.hitTest(new Point(0, 0), 255, _bmpd, new Point(char.x, char.y), 255))
{
char.x = _previousX;
char.y = _previousY;
}
else
{
char.x = _xTo;
char.y = _yTo;
}
_previousX = char.x;
_previousY = char.y;
}
Look at my hint,
function loop(Event)
{
if(isHit==false)
{
if(isRight==true){head_mc.x+=1}
if(isLeft==true){head_mc.x-=1}
if(isUp==true){head_mc.y-=1}
if(isDown==true){head_mc.y+=1}
}
if(head_mc.hitTestObject(build_mc))
{
isHit=true;
if(isRight==true){head_mc.x-=1}
if(isLeft==true){head_mc.x+=1}
if(isUp==true){head_mc.y+=1}
if(isDown==true){head_mc.y-=1}
}
else
{
isHit=false;
}
}
I use step back to opposite direction instead.

I'm trying to set up my collision detect so that it ignores a child of the target. (Actionscript 3)

So in my game, every 'enemy' movieclip creates a textfield that represents the name of the enemy. The problem is, I want my collision detect engine to detect a collision with the enemy itself, not the textfield.
This is the code that I have currently have on my collision class for detecting a collision with the enemy:
for(var i = 0;i < _enemies.length; i++)
{
if(CollisionEngine.isColliding(_laser, _enemies[i]._enemyNameTextField, _animation))
{
}
else if(CollisionEngine.isColliding(_laser, _enemies[i], _animation))
{
_enemies[i].kill();
_animation._killedEnemy = true;
}
}
The first if clause checks for a collision with the enemy's text field. The else if checks for a collision with the enemy.
The problem with this current implementation is that if the 'laser' hits the textfield first, passes through it, and hits the enemy, it's not detected as a collision.
Any idea on how I could work around this?
Change the order of the checks:
if(CollisionEngine.isColliding(_laser, _enemies[i], _animation))
{
if(!CollisionEngine.isColliding(_laser, _enemies[i]._enemyNameTextField, _animation))
{
_enemies[i].kill();
_animation._killedEnemy = true;
}
}
Note that the above code is equivalent to:
if(CollisionEngine.isColliding(_laser, _enemies[i], _animation) && !CollisionEngine.isColliding(_laser, _enemies[i]._enemyNameTextField, _animation))
{
_enemies[i].kill();
_animation._killedEnemy = true;
}
Alternatively, you can explicitly define a hitArea on all of your enemies so that collisions with the text field aren't considered collisions.
in your enemy have a method like:
public function getCollision():Sprite{
//Where this.body is the main animation for the clip/Hittest area
return this.body
}
or something that returns just the active hit area, then you can run:
if(CollisionEngine.isColliding(_laser, _enemies[i].getCollision(), _animation))