So I would like to add velocity to my swipe gesture. Currently I have it moving 10 px on swipe, but I want it to move with a velocity so the user can toss the object around on the screen. Here's the code I am currently using with the object moving the 10 px.
function onSwipe (e:TransformGestureEvent):void{
player_mc.gotoAndStop(5);
if (e.offsetX == 1) {
//User swiped towards right
player_mc.x += 10;
}
if (e.offsetX == -1) {
//User swiped towards left
player_mc.x -= 10;
}
if (e.offsetY == 1) {
//User swiped towards bottom
player_mc.y += 10;
}
if (e.offsetY == -1) {
//User swiped towards top
player_mc.y -= 10;
}
if(collision(player_mc.cp, level_mc))
{
player_mc.x = player_mc.prevX;
player_mc.y = player_mc.prevY;
}
}
Thanks for the help
Here is a way you can do this: (you'll want to swap the mouse events for touch events if using on mobile)
player_mc.addEventListener(MouseEvent.MOUSE_DOWN,startSwipe);
player_mc.addEventListener(MouseEvent.MOUSE_UP,endSwipe);
var velocity:Point = new Point(); //this stores the current velocity of the object
var previous:Point = new Point(); //this stores the previous frames x/y of the object.
var isDragging:Boolean = false;
var friction:Number = .85; //this how quickly to slow down the object once the mouse is released - smaller the number (must be less than 1) the quicker the object will slow/stop
function startSwipe(e){
isDragging = true;
player_mc.startDrag(false);
this.addEventListener(Event.ENTER_FRAME,enterFrameHandler);
}
function enterFrameHandler(e):void {
if(isDragging){
velocity.x += player_mc.x - previous.x; //we're adding the new velocity to the old one, then dividing in half to average the value - this makes it seem smoother
velocity.y += player_mc.y - previous.y;
velocity.x *= .5; //dividing in half
velocity.y *= .5;
previous.x = player_mc.x;
previous.y = player_mc.y;
}else{
velocity.x *= friction; //gradually slow down the object
velocity.y *= friction;
player_mc.x += velocity.x;
player_mc.y += velocity.y;
if(velocity.x < .05 && velocity.y < .05){ //once it gets slow enough, stop the enter frame handler
this.removeEventListener(Event.ENTER_FRAME,enterFrameHandler);
}
}
trace(velocity);
}
function endSwipe(e){
player_mc.stopDrag();
isDragging = false;
}
Related
I'm very new to ActionScript3 and am making an asteroids-type game. Right now, the ship continues floating in a straight line when you let go of the movement buttons, and I want to be able to stop that from happening. I'm thinking either a dedicated button for braking, like the b key, or if the keys are not pressed to stop movement, whichever would be easier. Like I said I'm really new to AS3 so not even sure what part of my code is making them keep flying in a straight line. Here is the code to control movement for reference:
// register key presses
public function keyDownFunction(event:KeyboardEvent) {
if (event.keyCode == 37) {
leftArrow = true;
} else if (event.keyCode == 39) {
rightArrow = true;
} else if (event.keyCode == 38) {
upArrow = true;
//Add event listener for down arrow
} else if (event.keyCode == 40) {
downArrow = true;
// show thruster
if (gameMode == "play") ship.gotoAndStop(2);
} else if (event.keyCode == 32) { // space
var channel:SoundChannel = shootSound.play();
newMissile();
} else if (event.keyCode == 90) { // z
startShield(false);
var channel:SoundChannel = shieldSound.play();
}
}
// register key ups
public function keyUpFunction(event:KeyboardEvent) {
if (event.keyCode == 37) {
leftArrow = false;
} else if (event.keyCode == 39) {
rightArrow = false;
} else if (event.keyCode == 38) {
upArrow = false;
//Add listener for down arrow
} else if (event.keyCode == 40) {
downArrow = false;
// remove thruster
if (gameMode == "play") ship.gotoAndStop(1);
}
}
// animate ship
public function moveShip(timeDiff:uint) {
// rotate and thrust
if (leftArrow) {
ship.rotation -= shipRotationSpeed*timeDiff;
} else if (rightArrow) {
ship.rotation += shipRotationSpeed*timeDiff;
} else if (upArrow) {
shipMoveX += Math.cos(Math.PI*ship.rotation/180)*thrustPower;
shipMoveY += Math.sin(Math.PI*ship.rotation/180)*thrustPower;
//Added down arrow movement to allow player to move backwards
} else if (downArrow) {
shipMoveX -= Math.cos(Math.PI*ship.rotation/180)*thrustPower;
shipMoveY -= Math.sin(Math.PI*ship.rotation/180)*thrustPower;
}
// move
ship.x += shipMoveX;
ship.y += shipMoveY;
I agree that there is a little logic problem in your code. Your ship will move on 'til
judgement day because the two variables responsible for the speed of it's motion - shipMoveX
and shipMoveY - aren't automatically degraded over time.
Now there are literally thousands of ways of how this could be achieved but let's keep things
simple.
You are using a class variable called thrustPower - make sure to set it to 0.1 and that the value of both shipMoveX & shipMoveY is 0.
Additionally add these class variables:
private var thrustHorizontal:Number = 0;
private var thrustVertical:Number = 0;
private var speed:Number = 0;
private var maxSpeed:Number = 5;
private var decay:Number = 0.97;
Replace the moveShip function with this:
public function moveShip(timeDiff:uint):void
{
thrustHorizontal = Math.sin(Math.PI * ship.rotation / 180);
thrustVertical = Math.cos(Math.PI * ship.rotation / 180);
// rotate and thrust
if (leftArrow)
{
ship.rotation -= shipRotationSpeed * timeDiff;
}
else if (rightArrow)
{
ship.rotation += shipRotationSpeed * timeDiff;
}
else if (upArrow)
{
shipMoveX += thrustPower * thrustHorizontal;
shipMoveY += thrustPower * thrustVertical;
}
else if (downArrow)
{
shipMoveX -= thrustPower * thrustHorizontal;
shipMoveY -= thrustPower * thrustVertical;
}
if (!upArrow && !downArrow)
{
shipMoveX *= decay;
shipMoveY *= decay;
}
speed = Math.sqrt((shipMoveX * shipMoveX) + (shipMoveY * shipMoveY));
if (speed > maxSpeed)
{
shipMoveX *= maxSpeed / speed;
shipMoveY *= maxSpeed / speed;
}
ship.x += shipMoveX;
ship.y -= shipMoveY;
}
As you can see, there is this new if-block:
if (!upArrow && !downArrow)
{
shipMoveX *= decay;
shipMoveY *= decay;
}
Here we're handling the case, if the player neither pressed up nor down and multiply
the spaceships horizontal/vertical speed by decay. If you scroll back a bit, you notice
it's value is 0.97.
You can generally say, if you multiply a positive number x by 0 < y < 1, x will become smaller.
So if you're spaship is currently moving horizontally at 3 pixels per frame (shipMoveX=3 ; shipMoveY=0)
it will become 2.91 the next frame. The next frame it will be 2.8227, then 2.738019 ... and so on before it will finally reach zero in infinity.
I am making a platformer game in Flash (AS3) and the code I have below works. I want my character to jump high enough to allow it time to reach a platform. The only problem with code below is the speed at which it jumps up and down and the height of the jump. Tthe space bar is what triggers the function to run.
Please help as I would much appreciate it! :)
Player.addEventListener(Event.ENTER_FRAME, fl_MoveInDirectionOfKey);
stage.addEventListener(KeyboardEvent.KEY_DOWN, fl_SetKeyPressed);
stage.addEventListener(KeyboardEvent.KEY_UP, fl_UnsetKeyPressed);
function fl_MoveInDirectionOfKey(event:Event)
{
if (spacePressed){
var gravity:Number = 9.8;
var jumping:Boolean = false;
var jumpVar:Number = 0;
if(jumping != true)
{
jumpVar = -70;
jumping = true;
}
if(jumping)
{
spacePressed = false;
Player.y += jumpVar;
jumpVar += gravity;
}
Player.addEventListener(Event.ENTER_FRAME, drop);
function drop(event:Event)
{
Player.y -= jumpVar;
jumpVar -= gravity;
if(Player.y > 350){
Player.y = 350;
}
}
Player.removeEventListener(Event.ENTER_FRAME, fl_MoveInDirectionOfKey);
Player.addEventListener(Event.ENTER_FRAME, fl_MoveInDirectionOfKey);
/*var frameNumb:Number = 0;
Player.addEventListener(Event.ENTER_FRAME, jumpup);
spacePressed = false;
function jumpup(event:Event)
{
while(frameNumb < 30){
spacePressed = false;
Player.y -= 1;
frameNumb += 0.5;
}
Player.removeEventListener(Event.ENTER_FRAME, jumpup);
Player.addEventListener(Event.ENTER_FRAME, jumpdown);
function jumpdown(){
while(frameNumb > 0){
spacePressed = false;
Player.y += 1;
frameNumb -= 0.5;
}
}
}*/
}
if (leftPressed)
{
Player.x -= speed;
Player.gotoAndStop("left");
}
if (rightPressed)
{
Player.x += speed;
Player.gotoAndStop("right");
}
}
Thanks
Your use of 9.8 for gravity is meters-per-second-per-second. Since drop() is executed every frame, you're going to get some serious fast-forward gravity, unless the program is doing only 1 FPS. So, assuming you want more fluidity than 1 FPS, consider doing
jumpVar += gravity/fps;
However, to get the exact velocity required to lift you to a height, I think the calculation is...
initialVelocityInMetersPerSecond = Math.sqrt( 2 * gravity * metersToJump )
So instead of jumpVar = -70, you would do something like...
// get posititive distance since we'll use to get a square root
var metersToJump:Number = Player.y - platform.y;
jumpVar = -Math.sqrt( 2 * gravity * metersToJump );
...and then in the ENTER_FRAME handler...
Player.y += jumpVar / fps;
jumpVar += gravity / fps;
From your example it's not the case, but if you place the platform below the Player, it won't work as you can't get the root of a negative number!
In my example code I am not fixing the height of the platform, so how you decide on the target platform is a completely separate matter.
Ok, so I have an object on the stage that moves on the "world" movieclip. I'm trying to make it so that when you're moving right. If the movieclip inside the moving movieclip("dude") called hitD collides with the walls in world, the dude stops moving forward.
Screen shots if it might help.
General stage dude object selected
http://prntscr.com/5bgjfq the world is everything but the ball
http://prntscr.com/5bgjuh
hitD
If anyone has any way they can modify these collision physics since my current code is sketchy as hell, all suggestions and ideas are welcome.
var started:Boolean;
const NUMLEVELS = 3;
var status:String;
stage.focus = stage;
if (! started)
{// Only ever do this once!
status = "falling";
started = true;
var speedX:Number = 5;
var speedY:Number = 0;
var topSpeedY:Number = 50;
var start_x:Number = dude.x;
var start_y:Number = dude.y;
var keysDown:Object = new Object();
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
stage.addEventListener(KeyboardEvent.KEY_UP, keyReleased);
stage.addEventListener( Event.DEACTIVATE, appDeactivate );
dude.addEventListener(Event.ENTER_FRAME, moveDude);
var W:Number = 15;
var snows:Array = new Array();
}
for (var b:int = 0; b < 50; b++)
{
var snow:Snow = new Snow();
snows.push(snow);
addChild(snow);
}
function cleanup()
{
stage.removeEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
stage.removeEventListener(KeyboardEvent.KEY_UP, keyReleased);
stage.removeEventListener( Event.DEACTIVATE, appDeactivate );
dude.removeEventListener(Event.ENTER_FRAME, moveDude);
}
function keyIsDown(key:uint):Boolean
{
return Boolean(key in keysDown);
}
function keyPressed(e:KeyboardEvent):void
{
keysDown[e.keyCode] = true;
}
function keyReleased(e:KeyboardEvent):void
{
delete keysDown[e.keyCode];
}
function appDeactivate( event:Event ):void
{
// Get rid of all keypress info when app loses focus
keysDown=new Object();
}
function moveDude(e:Event):void
{
var obj:Object = e.target; //setting dude as object
// for now, if you get off the top of the screen you win
if (obj.y < 0)
{
cleanup();
nextScene();
return;
}
// if character dies, restart
if (obj.y > stage.stageHeight + 100)
{
gotoAndStop(1);
obj.x = start_x;
obj.y = start_y;
}
if (death!=null)
{
if (obj.hitTestObject(death))
{
trace("Dead");
}
}
if (status=="falling")
{
speedY++;
if (speedY>topSpeedY)
{
speedY = topSpeedY;
}
for (i = 0; i<2*speedY; i++)
{
obj.y++;
if (world.hitTestPoint(obj.x - obj.width / 2,obj.y,true) || world.hitTestPoint(obj.x + obj.width / 2,obj.y,true))
{
status = "ground";
break;
}
}
}
else if (status == "jumping")
{
speedY--;
for (i = 0; i<2*speedY; i++)
{
obj.y--;
if (world.hitTestPoint(obj.x - obj.width / 2,obj.y - obj.height,true) || world.hitTestPoint(obj.x + obj.width / 2,obj.y - obj.height,true))
{
speedY = 0;
break;
}
}
if (speedY==0)
{
status = "falling";
}
}
else if (status == "ground")
{
if (! world.hitTestPoint(obj.x - 8,obj.y,true) && ! world.hitTestPoint(obj.x + 8,obj.y + 4,true))
{
speedY = 0;
status = "falling";
}
if (keyIsDown(Keyboard.UP))
{
status = "jumping";
speedY = 10;
}
}
if (keyIsDown(Keyboard.DOWN)&&status=="ground")
{
dude.gotoAndStop("duck");
}
else
{
if (keyIsDown(Keyboard.SHIFT))
{
speedX = 10;
}
else
{
speedX = 5;
}
if (keyIsDown(Keyboard.LEFT))
{
for (i = 0; i<speedX; i++)
{
obj.x--;
dude.ball.rotation--; //dude.ball is a movieclip similar to dude.hitD, it spins when you move.
if (world.hitTestPoint(obj.x - obj.width / 2 + 4,obj.y - 8,true) || world.hitTestPoint(obj.x - obj.width / 2,obj.y - obj.height + 8,true))
{
dude.ball.rotation++;
obj.x++;
break;
}
}
}
else if (keyIsDown(Keyboard.RIGHT))
{
//dude.gotoAndStop("right");
//obj.scaleX = 1;
for (i = 0; i<speedX; i++)
{
obj.x++;
dude.ball.rotation++;
// The number in obj.y-4 affects the climbing ability
if (status == "ground")
{
//dude.height+= 0.1;
//dude.width += 0.1;
}//so here I'm checking if it hits the lower corner or top right corner or hitD
if (world.hitTestPoint(dude.hitD.x + obj.hitD.width/2 , obj.hitD.y,true) || world.hitTestPoint(obj.hitD.x + obj.hitD.width/2,obj.hitD.y - obj.hitD.height ,true))
//if (world.hitTestObject(obj))
{
dude.ball.rotation--;
obj.x--;
break;
}
}
}
dude.gotoAndStop(1);
}
while (status == "ground" && (world.hitTestPoint(obj.x-8, obj.y-1, true) || world.hitTestPoint(obj.x+8, obj.y-1, true)))
{
obj.y--;
}
const BORDER = 50;
var diff:int;
// Check right border:
diff = obj.x + BORDER - stage.stageWidth;
if (diff>0 && world.x>=stage.stageWidth-world.width)
{
obj.x -= diff;
world.x -= diff;
background1.x -= diff;
if (death != null)
{
death.x -= diff;
}
}
// Check left border:
diff = obj.x - BORDER;
if (diff<0 && world.x<=0)
{
obj.x -= diff;
world.x -= diff;
background1.x -= diff;
if (death != null)
{
death.x -= diff;
}
}
// Check bottom border:
diff = obj.y + BORDER - stage.stageHeight;
if (diff>0)
{
obj.y -= diff;
world.y -= diff;
background1.y -= diff;
if (death != null)
{
death.y -= diff;
}
}
// Check top border:
diff = obj.y - BORDER;
if (diff<0)
{
obj.y -= diff;
world.y -= diff;
background1.y -= diff;
if (death != null)
{
death.y -= diff;
}
}
if (obj.x > stage.stageWidth - 25)
{
if (currentFrame<NUMLEVELS)
{
gotoAndStop(currentFrame+1);
obj.x = 25;
}
else
{
obj.x = stage.stageWidth - 25;
}
}
else if (obj.x<25)
{
if (currentFrame>1)
{
gotoAndStop(currentFrame-1);
obj.x = stage.stageWidth - 25;
}
else
{
obj.x = 25;
}
}
}
Thanks in advance for any help you can provide :)
For player physics, it's more clear approach to make a central ENTER_FRAME handler function that just for calculating the transformations to be applied to player.
You can still get information from out, but you just process the final output there. Else, it could be problematic, especially when things gets more complex and when you want to add some more feature.(e.g. Imagine in the future, you wanted to add fans on the ground that blows air up, and player have to rise when on them. There you have a lot to change, and probably with many problems.
For collision detection, this function will provide you this information: to which direction(s) the player can't go with variables 'UpColl', 'DownColl', 'Right Coll' and 'LeftColl'.
Then you can refer to this information from your main function that applies the transformation to your player. I'll give example to that also below.
function collEveryFrame(event:Event):void
{
// capture player positions
player_x = WORLD.player.x;
player_y = WORLD.player.y;
// the movie clip object where you store your solid objects. Remember, ALL MovieClip objets inside this MovieClip will taken as solid objects in your game, and regardless their shape, their boundingBox will be taken as collison. So they will all be square.
collContainer = WORLD.cW;
// your player's collision object
playerColl = WORLD.player;
// RIGHT SQUARE COLLISION DETECTION
for (var i:int; i < collContainer.numChildren; i++)
{
// Check if any collision object colliding with player
if (playerColl.hitTestObject(collContainer.getChildAt(i)))
{
// One collision detected. Check 'from which side' does the player colliding with the object;
if (collContainer.getChildAt(i).y > playerColl.y + playerColl.height - p1MoveSpeed)
{
playerColl.y = collContainer.getChildAt(i).y - playerColl.height;
DownColl = true;
}
else if (collContainer.getChildAt(i).y + collContainer.getChildAt(i).height < playerColl.y + p1MoveSpeed)
{
playerColl.y = collContainer.getChildAt(i).y + collContainer.getChildAt(i).height;
UpColl = true;
}
else if (collContainer.getChildAt(i).x + collContainer.getChildAt(i).width < playerColl.x + p1MoveSpeed)
{
playerColl.x = + collContainer.getChildAt(i).x + collContainer.getChildAt(i).width;
LeftColl = true;
}
else if (collContainer.getChildAt(i).x > playerColl.x + playerColl.width - p1MoveSpeed)
{
playerColl.x = + collContainer.getChildAt(i).x - playerColl.width;
RightColl = true;
}
}
}
// RIGHT SQUARE COLLISION DETECTION [End]
}
Transformation function;
function playerMovement(event:Event):void
{
// (apply this for all sides)
// if nothing keeps player from going right;
if (! RightColl)
{
// Apply everything currently pushing the player to right
if (keyIsDown(Keyboard.RIGHT))
{
movement_Right = 15;
}else{
movement_Right = 0;
}
// example fictional wind function returns wind speed
windSpeed = getWindSpeed();
player.x += movement_Right + windSpeed + etc + etc;
// say windSpeed is -5 (Wind is coming from right, so pushing the player to left)
// so if user pressing right arrow key, player will move to right 10px for every frame, else 5px to left, etc.
}
}
In this way, everything about physics will be easy to implement.
For example, when calculating the movement to down, add gravity and jump etc.
I am having problems with getting the character to jump/fail when the up arrow is pressed. I'm trying to make it so when the up arrow key is pressed once it will jump a certain height then fall.
Here is my movement code:
public var gravity:int = 2;
public function fireboyMovement(e:KeyboardEvent):void
{
if (e.keyCode == 37) //right
{
fireboy1.x = fireboy1.x -5;
checkBorder()
}
else if (e.keyCode == 39) //left
{
fireboy1.x = fireboy1.x +5;
checkBorder()
}
if (e.keyCode == 38) //up
{
fireboy1.y = fireboy1.y -20;
fireboy1.y += gravity;
checkBorder()
}
Your issue is you need to increment the players position over time (and not all at once).
You can either use a tweening engine (like tweenlite), or roll your own timer or enter frame handler.
Here is an example of the latter:
if (e.keyCode == 38) //up
{
if(!isJumping){
isJumping = true;
velocity = 50; //how much to move every increment, reset every jump to default value
direction = -1; //start by going upwards
this.addEventListener(Event.ENTER_FRAME,jumpLoop);
}
}
var isJumping:Boolean = false;
var friction:Number = .85; //how fast to slow down / speed up - the lower the number the quicker (must be less than 1, and more than 0 to work properly)
var velocity:Number;
var direction:int = -1;
function jumpLoop(){ //this is running every frame while jumping
fireboy1.y += velocity * direction; //take the current velocity, and apply it in the current direction
if(direction < 0){
velocity *= friction; //reduce velocity as player ascends
}else{
velocity *= 1 + (1 - friction); //increase velocity now that player is falling
}
if(velocity < 1) direction = 1; //if player is moving less than 1 pixel now, change direction
if(fireboy1.y > stage.stageHeight - fireboy1.height){ //stage.stageheight being wherever your floor is
fireboy1.y = stage.stageHeight - fireboy1.height; //put player on the floor exactly
//jump is over, stop the jumpLoop
this.removeEventListener(Event.ENTER_FRAME,jumpLoop);
isJumping = false;
}
}
I have an animated MovieClip of a fly that spawns at a random location and moves across the screen by bouncing off the walls. But every time the animation starts over, it seems to "jump" to a random location. Here is the code I have for when it spawns:
private function beginClass(e:Event):void{
_root = MovieClip(root);
do {
xRandom = Math.floor(Math.random() * 500);
yRandom = Math.floor(Math.random() * 350);
this.x = xRandom;
this.y = yRandom;
} while (Math.abs(xRandom - mouseX) > 20 && Math.abs(yRandom - mouseY) > 20);
}
And this is the code for its movement:
//Bouncing the fly off of the walls
if(this.x >= stage.stageWidth-this.width){
//if the fly hits the right side
//of the screen, then bounce off
flyXSpeed *= -1;
}
if(this.x <= 0){
//if the fly hits the left side
//of the screen, then bounce off
flyXSpeed *= -1;
}
if(this.y >= stage.stageHeight-this.height){
//if the fly hits the bottom
//then bounce up
flyYSpeed *= -1;
}
if(this.y <= 0){
//if the fly hits the top
//then bounce down
flyYSpeed *= -1;
}
How do I fix it so that the fly continues moving in its appropriate path every time the animation starts over?
If I understand the problem correctly, when starting the animation you have to check if it has already been started before.
A simple boolean variable would do:
private var hasStarted:Boolean = false;
private function beginClass(e:Event):void{
_root = MovieClip(root);
if (!hasStarted) {
hasStarted = true;
do {
xRandom = Math.floor(Math.random() * 500);
yRandom = Math.floor(Math.random() * 350);
this.x = xRandom;
this.y = yRandom;
} while (Math.abs(xRandom - mouseX) > 20 && Math.abs(yRandom - mouseY) > 20);
}
}
This way it'll only execute the random placing code once.