I am new to flash and want to make a slider where something moves back and for until you hit space bar in order to make land in the middle which would trigger a new scene. Sort of like a mini game.
Again im really new to actionscript so any help would be nice. I was thinking of calling like a function where the pointer is continuously moving until the space bar is hit. But Im really stuck. Please and thank you for your time.
Make sure your slider has the instance name "slider". Then try this code:
//x position of the most left position of the slider
var left_limit:Number = 50
//x position of the most right position of the slider
var right_limit:Number = 250
var speed:Number = 10
var dir:int = 1
//How close the slider has to be to the middle to trigger the next scene
var tolerance:Number = 10
addEventListener(Event.ENTER_FRAME,loop)
addEventListener(KeyboardEvent.KEY_DOWN,keydown)
function loop(e:Event){
slider.x += speed*dir
if(slider.x>right_limit){
slider.x = right_limit
dir = -1
}else if(slider.x<left_limit){
slider.x = left_limit
dir = 1
}
}
function keydown(e:KeyboardEvent){
if(e.keyCode==Keyboard.SPACE){
removeEventListener(Event.ENTER_FRAME,loop)
if(Math.abs((slider.x-left_limit)-(right_limit-left_limit)/2)<tolerance){
//succeeded go to next scene
gotoAndStop("scene2")
}else{
//failed
}
}
}
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.
I am new in AS3, for one of my assignment, I need to modified the existing code(copy paste and modify) to create certain effect. The effect that I need to create is when I MouseOver on the stage, the mask will form a loop with background image and back to normal(mask layer not visible) when I MouseOut of the stage. Here is the code that need to modifly.
var mymask:Sprite=new Sprite();
var isOver:Boolean=false;
var spotSize:Number=0;
pic2.addChild(mymask);
pic2.mask=mymask;
pic2.mouseEnabled=false;
mymask.x=0;
mymask.y=0;
function drawSpot(r:Number):void{
mymask.graphics.clear();
mymask.graphics.lineStyle(1,0x000000);
mymask.graphics.beginFill (0x00000F);
mymask.graphics.drawRect(0,0,r,900);
mymask.graphics.endFill();
spotSize=r;
}
pic1.addEventListener(MouseEvent.ROLL_OVER, mouseOver);
function mouseOver(e:MouseEvent):void{
isOver=true;
}
pic1.addEventListener(MouseEvent.ROLL_OUT, mouseOut)
function mouseOut(e:MouseEvent):void{
isOver=false;
}
stage.addEventListener(Event.ENTER_FRAME, enter);
function enter(e:Event):void{
var cursorSize:Number=spotSize;
if(isOver==true && cursorSize<1)
drawSpot(cursorSize+999);
if(isOver==false && cursorSize>10)
drawSpot(cursorSize-999);
}
Sounds like you're trying to animate a circular mask by modifying the code above?
If so, this is the code changes needed.
In your drawSpot method, change the line:
mymask.graphics.drawRect(0,0,r,900);
to:
mymask.graphics.drawCircle(pic2.width * .5, pic2.height * .5, r);
Then in your enter method,
function enter(e:Event):void{
var cursorSize:Number=spotSize;
if(isOver==true && cursorSize<999)
drawSpot(cursorSize+1);
if(isOver==false && cursorSize>0)
drawSpot(cursorSize-1);
}
What you're doing is saying IF the mouse is over and the cursorSize is less than the full value (you had 999 before so I kept that) then increment the size by 1. It will keep doing this every frame until the size is 999 or higher (or the mouse is no longer over).
If the mouse isn't over and the mask isn't 0 in size, it will decrease the size by 1 every frame until it's 0 or less.
If you want it to go faster, simply change the +1 and -1 to a higher number
I'm new to actionscript 3. I want to create a textfield that is either N number of pixels from the bottom of the stage or 90% from the top of the stage.
Basically i want the textfield to always appear near the bottom of the stage. What property of the TextField() object do I configure to achieve this?
function updateTextPosition():void
{
var newPositionY:Number = (stage.stageHeight * .90);
myTextField.y = newPositionY;
}
Now if you want to account for the height of the actual text for whatever reason, you change it to this:
function updateTextPosition():void
{
var newPositionY:Number = (stage.stageHeight * .90) - myTextField.textHeight;
myTextField.y = newPositionY;
}
Remember the origin of the field is top left, so the bottom of the text will appear at myTextField.x + myTextField.textHeight;.
Also, you can listen for the RESIZE event on the stage and update your TextField like so:
stage.addEventListener(Event.RESIZE, onStageResized);
function onStageResized(e:Event):void
{
updateTextPosition();
}
Hey gang. Stumped on something.
I have a disc I am rotating with the mouse with event.MOUSE_MOVE, like a jog wheel on some audio equipment. Everything almost works as expected, but the problem I am experiencing is that the disc always jumps to the point where the user clicks on the disc. I need the point on the disc that the user clicks on to remain under the mouse while the user spins the disc but I can't seem to come up with the correct math to make it happen. Here's the code i am using:
var xd = (_knob.x - _stageRef.stage.mouseX);
var yd = (_knob.y - _stageRef.stage.mouseY);
var radAngle = Math.atan2(yd, xd);
_knob.rotation = int(radAngle * 360/(Math.PI * 2) - 90);
_knob is a vector circle wrapped in a movieclip, with the circle centered on the movieclip's reg point. _stageRef represents the main stage.
Any help would be awesome. I've scoured the interweb and can't come up with anything.
Thx!
You are setting _knob rotation to the angle between _knob and mouse cursor. So if rotation was 0, and angle 45, rotation becomes 45, therefore it jumps. What you need is measure changes in this angle, not setting it instantly:
var _mouseAngle:Number;
function getMouseAngle():Number
{
var xd = (_knob.x - _stageRef.stage.mouseX);
var yd = (_knob.y - _stageRef.stage.mouseY);
return Math.atan2(yd, xd);
}
function onMouseDown(event:MouseEvent):void
{
_mouseAngle = getMouseAngle();
}
function onMouseMove(event:MouseEvent):void
{
var newAngle:Number = getMouseAngle();
_knob.rotation += (newAngle - _mouseAngle) * 180.0 / Math.PI; //EDIT: forgot to convert into degrees
_mouseAngle = newAngle;
}
(Code not tested)