How to detect diagonal swipe gesture in as3 for android - actionscript-3

How do I detect a diagonal swipe gesture which will enable a character jump over the obstacle?

according This tutorial
The function will be able to retrieve the variables offsetX and
offsetY to detect the direction in which the swipe was made from this
way:
if the value of offsetX is positive 1 then the swipe was made from the left to the right, if -1 then the swipe was made from the right to
the left.
if the value of offsetY is positive 1 then the swipe was made from the top to the bottom, if -1 then the swipe was made from the bottom
to the top.
so, for a diagonal swipe, offsetX should be same as offsetY
Multitouch.inputMode = MultitouchInputMode.GESTURE;
stage.addEventListener(TransformGestureEvent.GESTURE_SWIPE , onSwipe);
function onSwipe (e:TransformGestureEvent):void {
if (e.offsetX == e.offsetY) {
// diagonal swipe
}
}

Related

AS3 swipe gesture not very responsive

Here I go:
I'm doing this mobile app using AS3-AIR.
A deck of playing cards is shown in the center of the screen, and using the finger, you are able to flick off the top card to reveal the next one, using a swipe action.
It's a bird view, so only one card is showing, the user will assume that the rest of the deck is beneath the top card.
Cards are face down, so every time the user swipes a card off the screen, the same back image is displayed in the center over and over.
When the user double taps the back of a card, it flips over and the face of the card is revealed.
Here's my code (my questions come right after):
//Adding three same backs of cards to the stage:
addChild(backBlue3); //No event listener will be attached to this card
addChild(backBlue2);
addChild(backBlue1);
//backBlue1 and backBlue2 will alternate their Indexes/depths to create the illusion of an infinite deck of cards. So, when backBlue1 is thrown out of the screen, backBlue2 immediately fills the center of screen.
Multitouch.inputMode = MultitouchInputMode.GESTURE;
backBlue1.addEventListener(TransformGestureEvent.GESTURE_SWIPE, backCard_handler_swipe);
backBlue2.addEventListener(TransformGestureEvent.GESTURE_SWIPE, backCard_handler_swipe);
backBlue1.addEventListener(MouseEvent.DOUBLE_CLICK, cardFlipper);
backBlue2.addEventListener(MouseEvent.DOUBLE_CLICK, cardFlipper);
public function backCard_handler_swipe(e:TransformGestureEvent):void
{
//*********************************** Setting the random positions for swiped off cards ***********************************
//Swipe is done towards the left
if (e.offsetX == -1)
{
randomX = Math.floor(Math.random() * (randomMaxX - randomMinX + 1)) + randomMinX;
}
//Swipe is done towards the right
if (e.offsetX == 1)
{
randomX = Math.floor(Math.random() * (randomMaxX2 - randomMinX2 + 1)) + randomMinX2;
}
randomY = Math.floor(Math.random() * (randomMaxY - randomMinRotation + 1)) + randomMinY;
randomRotation = Math.floor(Math.random() * (randomMaxRotation - randomMinRotation + 1)) + randomMinRotation;
//*********************************** Creating a GreenSock TimeLineMax timeline to tween the "ejected" card ***********************************
var tl15 = new TimelineMax();
tl15.addLabel("cardOnScreen"); //At this point of the Timeline (the very beginning), a "Swiping sound" will be played.
if (e.target == backBlue1)
{
//backBlue1 is tweened off the screen
tl15.to(e.target, 1, {y:randomY, x:randomX, rotation:randomRotation, ease:Circ.easeOut});
//backBlue2 is instantly placed in the center of the screen, behind backBlue1
tl15.to(backBlue2, 0, {y:initialY2, x:initialX2, rotation:0, ease:Linear.easeNone}, "-=1");
tl15.addLabel("cardOffScreen", "-=0.5"); //The exact middle of the backBlue1 tween animation
tl15.addCallback(playSlide, "cardOnScreen"); //Playing the "Swiping Sound".
tl15.addCallback(swapingBacks, "cardOffScreen"); //swapingBacks function is called to place backBlue2 on top of backBlue1
}
if (e.target == backBlue2)
{
tl15.to(e.target, 1, {y:randomY, x:randomX, rotation:randomRotation, ease:Circ.easeOut});
tl15.to(backBlue1, 0, {y:initialY2, x:initialX2, rotation:0, ease:Linear.easeNone}, "-=1");
tl15.addLabel("cardOffScreen", "-=0.5");
tl15.addCallback(playSlide, "cardOnScreen");
tl15.addCallback(swapingBacks, "cardOffScreen");
}
}
public function swapingBacks()
{
swapChildren(backBlue1, backBlue2);
}
public function cardFlipper(e:MouseEvent)
{
//Flipping of the card is working fine
}
Here are my two main problems:
-1-
The swipe gesture is not very responsive: One out of four or five swipes, nothing happens. I have to do the swipe action twice or sometimes even more to finally flick the card off.
I removed the double click listener in case of conflict with the gesture listener, the problem is still there.
Is it the standard AS3 gesture listener that is not performant?
Ideally, the swipe gesture should be as in the TINDER app: very reponsive (and with drag action).
Is there any alternative to the standard GESTURE_SWIPE solution?
Any suggestions to my code above?
-2-
If the user swipes very fast, the SECOND card (beneath the first one) is swiped off, not the first. How can I avoid that?
Thanks a lot for your ideas, and thanks for reading!
BR
UPDATE ON FEBRUARY 10th
So I followed Mark Knol's advice (see answers below) and used a MOUSE_DOWN & MOUSE_UP events handlers instead of SWIPE GESTURE handlers.
The result is better, but not perfect.
The result is better, because the dragging that happens when mouse is down solves the issue of second card flying out the screen.
The result is not perfect because there's a conflict between MOUSE_DOWN/MOUSE_UP events with the DOUBLE_CLICK event: When I double tap a card, the two taps are both detected as two micro-drags of the card but also as a double tap action!!
So I did the following:
For a clear and big drag of the card towards the edges of the screen, the card is tweened off the screen when the mouse/finger is released.
For a small drag of the card, the card is tweened back to its original position. This way, in case of double tap of the card, the flipping will happen from the original position of the card.
I'm still stuck with the following issues:
Why in the ANDROID AIR compiled application, the double clicking is detected, but on windows flash player the double clicking is not detected?
Is there a way to solve the conflict between "double click" & "Click" events? (maybe by delaying the dragging action until the system makes sure it's not a double click occuring?)
backBlue1.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
backBlue2.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
backBlue1.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
backBlue2.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
backBlue1.addEventListener(MouseEvent.DOUBLE_CLICK, cardFlipper);
backBlue2.addEventListener(MouseEvent.DOUBLE_CLICK, cardFlipper);
function mouseDownHandler(e:MouseEvent):void
{
e.target.startDrag();
}
function mouseUpHandler(e:MouseEvent):void
{
e.target.stopDrag();
ecartX = initialX2 - e.target.x; //ecartX is the distance of the final card position with the original one.
if (Math.abs(ecartX) < limitX) //For a very small drag, the card is tweened back to its initial place
{
var tl25 = new TimelineMax();
tl25.to(e.target, 0.5, {y:initialY2, x:initialX2, rotation:0, ease:Linear.easeNone}, "-=0");
}
if (Math.abs(ecartX) > limitX) //For a clear long drag, the card is tweened off the screen
{
//Swipe to the left
if (ecartX > 0)
{
randomX = Math.floor(Math.random() * (randomMaxX - randomMinX + 1)) + randomMinX;
}
//Swipe to the right
if (ecartX < 0)
{
randomX = Math.floor(Math.random() * (randomMaxX2 - randomMinX2 + 1)) + randomMinX2;
}
randomY = Math.floor(Math.random() * (randomMaxY - randomMinRotation + 1)) + randomMinY;
randomRotation = Math.floor(Math.random() * (randomMaxRotation - randomMinRotation + 1)) + randomMinRotation;
var tl15 = new TimelineMax();
tl15.addLabel("cardOnScreen");
if (e.target == backBlue1)
{
tl15.to(e.target, 1, {y:randomY, x:randomX, rotation:randomRotation, ease:Circ.easeOut});
tl15.to(backBlue2, 0, {y:initialY2, x:initialX2, rotation:0, ease:Linear.easeNone}, "-=1");
tl15.addLabel("cardOffScreen", "-=0.5");
tl15.addCallback(playSlide, "cardOnScreen");
tl15.addCallback(swapingBacks, "cardOffScreen");
}
if (e.target == backBlue2)
{
tl15.to(e.target, 1, {y:randomY, x:randomX, rotation:randomRotation, ease:Circ.easeOut});
tl15.to(backBlue1, 0, {y:initialY2, x:initialX2, rotation:0, ease:Linear.easeNone}, "-=1");
tl15.addLabel("cardOffScreen", "-=0.5");
tl15.addCallback(playSlide, "cardOnScreen");
tl15.addCallback(swapingBacks, "cardOffScreen");
}
}
}
public function cardFlipper(e:MouseEvent)
{
//...
}
You could consider to make your own swipe detection. Basically you register a startpoint on DOWN, and check if endpoint is greater on UP, then that is a swipe to right. Of course for a swipe to left, the other end position is lower.
While dragging you move the card at touch position and on UP you tween the card to desired target position.
I also would disable user interaction (mouseEnabled, mouseChildren to false?) on the cards below the current one, enable as soon as possible after a valid swipe.

AS3 - Shooting arrows / targeting

I am creating a game where fairies cross the screen (bottom to top). There is a laser at the bottom of the screen that goes from right to left. I want to shoot the laser, and have the laser bullets to go from bottom to top. The code that I have has it going from top to bottom. I have tried to reverse the direction by changing out the + = 10 to - = 10... This did get the bullets in the right direction, however, it started it towards the top of my screen.
stage.addEventListener(MouseEvent.MOUSE_DOWN, targeting)
function targeting(e:MouseEvent):void{
var newArrow:blackArrow = new blackArrow();
addChild(newArrow);
newArrow.y = 50;
newArrow.x = shooterMC.x;
newArrow.addEventListener(Event.ENTER_FRAME, shoot);
}
function shoot(e:Event):void {
var arrowMC:MovieClip = MovieClip(e.target);
arrowMC.y += 10;
}
Thank you in advance for any help that you can give me.
You have to change this line to your desired position you want to start the laser animation from:
newArrow.y = 50;
The coordinate system starts in the upper left corner. So the lower right corner is window width | window height.

How to determine primary swipe direction (using MultiTouch) in AS3?

I'm trying to implement very simple swipe recognition on a touch screen using AS3. I just need to know whether the swipe is to the left, right, top, or bottom.
First question: would this be easier to do using simple MOUSE_DOWN and MOUSE_UP, and simply calculate the distance(s) moved?
Or would it be easier to do using MultiTouch?
I see code for MultiTouch showing how to implement swipe detection and getting the direction thus:
if (e.offsetY == 1) {
//User swiped towards bottom
square_mc.y += 100;
}
if (e.offsetY == -1) {
//User swiped towards top
square_mc.y -= 100;
}
if (e.offsetX == 1) {
//User swiped towards right
square_mc.x += 100;
}
if (e.offsetX == -1) {
//User swiped towards left
square_mc.x -= 100;
}
but if you need to resolve to ONE direction (that is left OR up, right OR bottom, etc), how do you do that (and if offsetX and offsetY are true offsets, why are they checking for +1 and -1 only? Or is this a function that is called often during the swipe? I'm trying to get one COMPLETE swipe).
I'm thinking skipping MultiTouch might be simpler, but would welcome feedback. Thanks!
You can answer your own question(s) by doing two things...
1 Re-read the tutorial that your code came from.. especially the section headed "Coding the gesture" http://www.republicofcode.com/tutorials/flash/as3swipegesture/
2 Just experiment and learn from observing results. For example...
but if you need to resolve to ONE direction (that is left OR.... how
do you do that?
Well what's wrong with this line in the code YOU provided if (e.offsetX == -1) { square_mc.x -= 100; }. Did you test it? Did square_mc not move left by 100 pixels when you swiped towards left direction? If it worked you have successfully "resolved" one direction, I guess. You can add the other If statements for other directions as needed.

startdrag start point limitations?

I have a slider that controls a movie clip by dragging it through the frames to animate and this works great when dragging from left to right, But i want the slider to start in the middle and drag through the movie clip from a center point being able to go 350 to the right and 350 to the left.
Is this possible?
Heres my code so far and as you can see it drags 350 to the right through dialSpin_mc.
Is there a way to make the slider start at a certain frame and go backwards and forwards?
dialSpin_mc.stop();
slider_mc.knob_mc.buttonMode = true;
slider_mc.knob_mc.addEventListener(MouseEvent.MOUSE_DOWN, onDragKnob);
stage.addEventListener(MouseEvent.MOUSE_UP, onReleaseKnob)
slider_mc.knob_mc.buttonMode = true;
function onDragKnob(myEvent:Event):void
{
slider_mc.knob_mc.startDrag(false, new Rectangle(0,0,350,0));
slider_mc.knob_mc.addEventListener(Event.ENTER_FRAME, onScrubMovie);
}
function onReleaseKnob(myEvent:Event):void
{
slider_mc.knob_mc.stopDrag();
slider_mc.knob_mc.removeEventListener(Event.ENTER_FRAME, onScrubMovie);
}
function onScrubMovie(myEvent:Event):void {
var playHead:int=Math.round((slider_mc.knob_mc.x/350*8)+1);
dialSpin_mc.gotoAndStop(playHead);
}
As discussed in comments this is how you could code the slider functionality without using the startDrag() and stopDrag() functions.
The idea is that when you press the mouse button down over the slider, an ENTER_FRAME listener is created. Every frame the sliders X position will be updated to match the mouseX position, and to make sure it can only travel 175 pixels either way we also check the sliders new position.
After making sure the sliders position is valid, you can use the same code to set the dialSpin_mc frame.
Once the mouse button is released, the enter frame listener is removed.
The sliderOrigin declared at the top of the code will need to be changed to whatever is appropriate for your project (whatever the sliders xposition is when you move it to the middle of the slide area rather than the very left).
var sliderOrigin:int = 150; // The x position the slider is in when in the center of the slide bar
slider_mc.x = sliderOrigin;
slider_mc.addEventListener(MouseEvent.MOUSE_DOWN, mDown);
slider_mc.addEventListener(MouseEvent.MOUSE_UP, mUp);
function mDown(e:MouseEvent):void
{
addEventListener(Event.ENTER_FRAME, UpdateDrag);
}
function mUp(e:MouseEvent):void
{
removeEventListener(Event.ENTER_FRAME, UpdateDrag);
}
function UpdateDrag(e:Event):void
{
slider_mc.x = mouseX;
// Check if the slider is 'out of bounds' and change its position if it is
if(slider_mc.x < sliderOrigin - 175)
slider_mc.x = sliderOrigin - 175;
else if(slider_mc.x > sliderOrigin + 175)
slider_mc.x = sliderOrigin + 175
var playHead:int = Math.round((slider_mc.x/350*8)+1);
dialSpin_mc.gotoAndStop(playHead);
}
Depending on the start position of the slider the range of playHead will change (so if the slider starts at x pos 200 the range would be between 2 and 10, at x pos 400 the range is between 6 and 14 - simple fix by changing the offset from +1 to whatever is necassary).

Correct formula to "invert" rotation (in degrees) in AS3?

I have my player movieclip on the stage, and when the mouse is clicked a bullet is fired and projected at the correct angle to point itself at the mouse location. I also want a "mirroring" enemy, that fires at the complete opposite direction when the player does.
For example, when the player shoots upwards, the enemy should shoot down. Likewise, shooting to the right will cause the enemy to shoot to the left.
Is there a formula to convert the rotation in degrees to it's complete opposite?
Using Matrix is a very simple and exact solution. just multiple a or c with -1 ( to flip vertical and horizontal ).
Sample code:
var _tmpMatrix:Matrix = sprite.transform.matrix;
_tmpMatrix.a *= -1;
if ( _tmpMatrix.a < 0 ) {
_tmpMatrix.tx = sprite.width + sprite.x;
} else {
_tmpMatrix.tx = 0;
}
sprite.transform.matrix = _tmpMatrix;
Wouldn't adding or subtracting 180 degrees point in the opposite direction?
or
obj.scaleX = -1;
will do the same thing. =)