ActionScript3: What code should I use to stop the player controlled sprite from moving? - actionscript-3

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.

Related

Character jumping but not returning to ground platform game AS3

I am making a platform game where the main character moves right and left and jumps however my character jumps and does not return to the ground but stays on top of the stage.My characters movie-clip symbol is called 'naruto' and my ground symbol is called 'ground'.
Here is my code:
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.display.MovieClip;
import flash.events.Event;
import flash.display.Stage;
naruto.gotoAndStop("stance");
var rightPressed:Boolean = new Boolean(false);
var leftPressed:Boolean = new Boolean(false);
var upPressed:Boolean = new Boolean(false);
var downPressed:Boolean = new Boolean(false);
var narutoSpeed:Number = 10;
stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownHandler);
stage.addEventListener(KeyboardEvent.KEY_UP,keyUpHandler);
stage.addEventListener(Event.ENTER_FRAME,gameLoop);
function keyDownHandler(keyEvent:KeyboardEvent):void
{
if (keyEvent.keyCode == Keyboard.RIGHT)
{
rightPressed = true;
}
else if(keyEvent.keyCode == Keyboard.LEFT)
{
leftPressed = true;
}
else if(keyEvent.keyCode == Keyboard.UP)
{
upPressed = true;
}else if(keyEvent.keyCode == Keyboard.DOWN)
{
downPressed = true;
}
}
function keyUpHandler(keyEvent:KeyboardEvent):void
{
if (keyEvent.keyCode == Keyboard.RIGHT)
{
rightPressed = false;
naruto.gotoAndStop("standright")
}
else if(keyEvent.keyCode == Keyboard.LEFT)
{
leftPressed = false;
naruto.gotoAndStop("standleft")
}
else if(keyEvent.keyCode == Keyboard.UP)
{
upPressed = false;
naruto.gotoAndStop("stance")
}else if(keyEvent.keyCode == Keyboard.DOWN)
{
downPressed = false;
naruto.gotoAndStop("stance")
}
}
function gameLoop(loopEvent: Event): void {
//If the right key is pressed, and the left key is NOT pressed
if (rightPressed && !leftPressed) {
naruto.x += narutoSpeed;
naruto.gotoAndStop("right");
}
if(leftPressed && !rightPressed) {
naruto.x -= narutoSpeed;
naruto.gotoAndStop("left");
}
var jumpHeight =0;
var defaultJumpSpeed = 20;
var jumpSpeed = 20;
if(upPressed && naruto.hitTestObject(ground))
{
trace("HELLO!");
naruto.y -= jumpSpeed;
jumpSpeed-= 4;
}
if(upPressed)
{
trace("HELLO!");
jumpHeight++;
naruto.y -= jumpSpeed;
if(jumpHeight>10)
jumpSpeed -= 4;
}
if(naruto.hitTestObject(ground))
{
trace("HELLO!");
jumpHeight =0;
jumpSpeed = defaultJumpSpeed;
}
}
Here is the link for my work: https://www.mediafire.com/?8d5opy49fuqmup5
Here is the problem:
The main issue, is in your current code, the player can only possible be in 3 positions:
Whatever the ground position is
16 (up is pressed and the character was not touching the ground
12 (up is pressed and the character was touching the ground)
Please see the code comments next to your original code to explain what is happening:
//you have this var inside the game loop, so every loop it resets to 20
var jumpSpeed = 20;
//so here, if up is pressed and the character is touching the ground
//you initiate a jump
if(upPressed && naruto.hitTestObject(ground))
{
trace("HELLO!");
naruto.y -= jumpSpeed;
jumpSpeed-= 4; //since you reset jumpSpeed to 20 every loop, this value will always just be 16
}
if(upPressed)
{
trace("HELLO!");
jumpHeight++;
//if naruto is touching the ground
//you are subtracting jumpSpeed above and right here again.
//so now the y position is 12 if touching the ground (or 16 if not touching the ground)
//since you reset jumpSpeed to 20 every loop, it always be one of those two values
naruto.y -= jumpSpeed;
if(jumpHeight>10)
jumpSpeed -= 4; //this serves no purpose, as your not using the value again and it gets reset to 20 next time the game loop runs
}
//this hit test will succeed in addition to the first one above when your jump starts.
if(naruto.hitTestObject(ground))
{
trace("HELLO!");
jumpHeight =0;
jumpSpeed = defaultJumpSpeed;
}
To remedy your jumping, you'll need to do something along these lines:
//initialize these vars outside of the game-loop for efficient and proper scoping (so their values don't reset every frame)
var isJumping:Boolean = false; //a flag to know if a jump is in progress
var jumpSpeed:Number = 0; //the current velocity of the jump
var defaultJumpSpeed:Number = 20; //the initial force (speed) of a jump
var jumpGravity:Number = 2; //subtract this from the speed every frame to slow the jump over time and fall
var onGround:Boolean = false; //a helper var for efficiency
function gameLoop(loopEvent: Event): void {
//If the right key is pressed, and the left key is NOT pressed
if (rightPressed && !leftPressed) {
naruto.x += narutoSpeed;
naruto.gotoAndStop("right");
}
if (leftPressed && !rightPressed) {
naruto.x -= narutoSpeed;
naruto.gotoAndStop("left");
}
//only do the hit test once per frame for efficiency (store the result)
onGround = naruto.hitTestObject(ground);
if (upPressed && onGround) {
trace("START JUMP");
isJumping = true;
jumpSpeed = defaultJumpSpeed; //set the initial jump velocity
}
if(isJumping){ //if jumping
naruto.y -= jumpSpeed; //move the player based off the current jump velocity
jumpSpeed -= jumpGravity; //slow the jump every frame (eventually causing it to be negative making the player fall)
}
//touching the ground and the up key is not pressed
//it's very important to put !upPressed so this doesn't run at the time as the initial jump above
if (!upPressed && onGround) {
//stop any jump motion
jumpSpeed = 0;
isJumping = false;
//you probably also want to snap the player to the ground
naruto.y = ground.y - naruto.height + 2; //the plus 2 ensures that the ground and the player touch so the hit test succeeds
}
}

as3 - player moves through objects

So I'm making a collision detection when player touches an object. When it touches the object, you move and stop when colliding, but for example, if I press the D key to go right, and I press the A key and let go, then the player starts moving through the object.
This is my player moving code.
public function onKeyDown(event: KeyboardEvent): void
{
if (event.keyCode == Keyboard.D)
{
isRight = true;
}
if (event.keyCode == Keyboard.A)
{
isLeft = true;
}
if (event.keyCode == Keyboard.W)
{
isUp = true;
}
if (event.keyCode == Keyboard.S)
{
isDown = true;
}
}
private function onKeyUp(event: KeyboardEvent): void
{
if (event.keyCode == Keyboard.A || event.keyCode == Keyboard.D)
{
vx = 0;
}
else if (event.keyCode == Keyboard.S || event.keyCode == Keyboard.W)
{
vy = 0;
}
}
public function onEnterFrame(event: Event): void
{
if (isRight)
{
vx = 5;
x += vx;
}
if (isLeft)
{
vx = 5;
x -= vy;
}
if (isUp)
{
vx = 5;
y -= vy;
}
if (isDown)
{
vx = 5;
y += vy;
}
//collision detection
if (player.collisionArea.hitTestObject(wall0))
{
player.x -= vx;
player.y -= vy;
}
}
Your issue, is that vx is always 5. So one direction you subtract 5 from the x, the other direction you add it.
Yet in your collision if statement, you are always subtracting it from the player's x (which if moving left, would keep moving the player left until it's past the object it's colliding with).
Also, in your isLeft check, you are subtracting the vy value, but I imagine you want to actually subtract the vx value. On that same note, in your isUp/isDown checks, your set the vx var to 5, but it seems like you should be setting the vy.
As it's unclear what x and y affect in context to the player, it's hard to give you an exact code example.
Most likely, you just need to move the player to the wall edge, and choose the side based off the direction of the player:
//collision detection
if (player.collisionArea.hitTestObject(wall0))
{
//if the player x is colliding
if(player.x + player.width > wall0.x && player.x < wall0.x + wall0.width){
player.x = isRight ? wall0.x - player.width : wall0.x + wall0.width;
}else if(player.y + player.height > wall0.y && player.y < wall0.y + wall0.height){
player.y = isDown ? wall0.y - player.height : wall0.y + wall0.height;
}
}

Platformer game hit test

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.

AS3 Character jumping/falling problems

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;
}
}

AS3 - Friction(?) causing Movie Clip to jump, temporarily alter path (playable SWF included)

Im making a game in FlashBuilder where the player controls a movieclip (_character) around the stage with the arrows or WASD. On the stage there are squares/boxes with collision detection and a 50 pixel border around.
While testing Ive noticed that if I hold a direction key, then switch to another AND the MovieClip is travelling past a gap in the boxes, the movieclip will jump a few pixels in the previous pressed direction, then back down again quickly.
It’s a split second flicker but creates a distracting jumpy, stutter effect. This happens with multiple key presses, but not if I press a button, release it, then press the other direction button.
The yellow crosses on the image below show some of the areas where this happens.
The larger the Friction number in my code, the more noticeable it is. But if I lower the friction too much (0.8ish) The Movie Clip moves too slowly around the stage and the game is unplayable.
I currently have the friction at 0.88 which lessens the jump, but it is still noticeable. Does anyone know why this is happening and/or how I could stop it? (while keeping the fluid movement of the movieclip of course.)
This SWF shows friction at 0.94 so the effect is very noticeable, especially in the top right corner. (Move character around stage with arrows or WASD.)
0.94 Friction SWF
This SWF has friction at 0.88, less noticeable, but it still happens!
0.88 Friction SWF
This problem doesn’t happen if I’m going UP to DOWN or LEFT to RIGHT, traveling past gaps. It only happens when two diagonal linked direction buttons are pressed, traveling past a gap.
If I travel UP then LEFT the MovieClip will jump upwards. If I travel DOWN, then LEFT and go across a gap the movieclip will jump a few pixels downwards, like the character is squatting(?)
Current Code
Rookies game/Application class is used as a level switcher to put levelOne onto the stage.
package
{
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
[SWF(width="650", height="450", backgroundColor="#FFFFFF", frameRate="60")]
public class RookiesGame extends Sprite
{
private var _levelOne:LevelOne;
//public static var gameMute:Boolean = false;
public function RookiesGame()
{
_levelOne = new LevelOne(stage);
stage.addChild(_levelOne);
stage.addEventListener("levelOneComplete",levelTwoSwitchHandler);
}
private function levelTwoSwitchHandler(event:Event):void
{
}
}
}
Level One contains most of the code, and majority of the work.
package
{
//import statements
public class LevelOne extends Sprite
{
//Declare the variables to hold the game objects
private var _character:Character = new Character();
private var _background:Background = new Background();
private var _box1:Box = new Box();
//Other box vars
//A variable to store the reference to the stage from the application class
private var _stage:Object;
//Control System
private var _bUp:Boolean = false;
private var _bDown:Boolean = false;
private var _bLeft:Boolean = false;
private var _bRight:Boolean = false;
public function LevelOne(stage:Object)
{
_stage = stage;
this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
}
private function addedToStageHandler(event:Event):void
{
startGame();
this.removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
}
private function startGame():void
{
addGameObjectToLevel(_background, 0, 0);
addGameObjectToLevel(_box1, 300, 200);
//Other boxes added to Level
//Add character
this.addChild(_character);
_character.x = 300;
_character.y = 50;
_character.gotoAndStop(1);
playGame();
}
private function playGame():void
{ //EVENT LISTENERS////////////////////////
_stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
_stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
this.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
private function enterFrameHandler(event:Event):void
{
_character.accelerationX = 0;
_character.accelerationY = 0;
_character.friction = 0.94;
var _updown:Boolean=Boolean(!(_bUp==_bDown));
var _leftright:Boolean=Boolean(!(_bLeft==_bRight));
if (!_updown && !_leftright)
{ // not moving anywhere
_character.gotoAndStop(1);
_character.accelerationX = 0;
_character.accelerationY = 0;
_character.friction = 0.94;
_character.vy=0;
_character.vx=0;
}
else
{
if (_bUp)
{
_character.accelerationY = -0.5;
_character.gotoAndStop(2);
}
else if (_bDown)
{
_character.accelerationY = 0.5;
_character.gotoAndStop(3);
}
if (_bLeft)
{
_character.accelerationX = -0.5;
_character.gotoAndStop(4);
}
else if (_bRight)
{
_character.accelerationX = 0.5;
_character.gotoAndStop(5);
}
}
//Apply friction
_character.vx *= _character.friction;
_character.vy *= _character.friction;
//Apply acceleration
_character.vx += _character.accelerationX;
_character.vy += _character.accelerationY;
//Limit the speed
if (_character.vx > _character.speedLimit)
{
_character.vx = _character.speedLimit;
}
if (_character.vx < -_character.speedLimit)
{
_character.vx = -_character.speedLimit;
}
if (_character.vy > _character.speedLimit)
{
_character.vy = _character.speedLimit;
}
if (_character.vy < -_character.speedLimit)
{
_character.vy = -_character.speedLimit;
}
//Force the velocity to zero after it falls below 0.1
if (Math.abs(_character.vx) < 0.1)
{
_character.vx = 0;
}
if (Math.abs(_character.vy) < 0.1)
{
_character.vy = 0;
}
//Move the character
_character.x += _character.vx;
_character.y += _character.vy;
checkStageBoundaries(_character);
//Box Collisions
Collision.block(_character,_box1);
//All other box collisions
}
private function checkStageBoundaries(gameObject:MovieClip):void
{
if (gameObject.x < 50)
{
gameObject.x = 50;
}
if (gameObject.y < 50)
{
gameObject.y = 50;
}
if (gameObject.x + gameObject.width > _stage.stageWidth - 50)
{
gameObject.x = _stage.stageWidth - gameObject.width - 50;
}
if (gameObject.y + gameObject.height > _stage.stageHeight - 50)
{
gameObject.y = _stage.stageHeight - gameObject.height - 50;
}
}
public function replay():void
{
_stage.removeEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
_stage.removeEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
this.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
startGame();
}
private function keyDownHandler(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.LEFT || event.keyCode == 65 )
{
_bLeft=true;
}
else if (event.keyCode == Keyboard.RIGHT || event.keyCode == 68)
{
_bRight=true;
}
else if (event.keyCode == Keyboard.UP || event.keyCode == 87 )
{
_bUp=true;
}
else if (event.keyCode == Keyboard.DOWN || event.keyCode == 83)
{
_bDown=true;
}
if (event.keyCode == Keyboard.ENTER)
{
replay();
}
}
private function keyUpHandler(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.LEFT || event.keyCode == Keyboard.RIGHT
|| event.keyCode == 65 || event.keyCode == 68)
{
_bLeft=false;
_bRight=false;
}
else if (event.keyCode == Keyboard.DOWN || event.keyCode == Keyboard.UP
|| event.keyCode == 87 || event.keyCode == 83 )
{
_bUp=false;
_bDown=false;
}
}
private function addGameObjectToLevel(gameObject:Sprite, xPos:int, yPos:int):void
{
this.addChild(gameObject);
gameObject.x = xPos;
gameObject.y = yPos;
}
}
}
_character is an instance of the Character Class.
The SWF has five key frames, each with an animation inside, which plays when the four direction buttons are pressed, plus the red stationary animation when nothing is being pressed.
package
{
import flash.display.MovieClip;
import flash.display.DisplayObject
[Embed(source="../swfs/characterResource.swf", symbol="Character")]
public class Character extends MovieClip
{
//Public properties
public var vx:Number = 0;
public var vy:Number = 0;
public var accelerationX:Number = 0;
public var accelerationY:Number = 0;
public var speedLimit:Number = 4;
public var friction:Number = 0.94;
public function Character()
{
}
}
}
The Box and Background classes are the same, they just embed the png and add the sprites. Note that the grid background is a single image. The game is not tile based..
And finally the Collision Class. When _character collides with a box, it calls the Collision.block function.
package
{
import flash.display.Sprite;
public class Collision
{
static public var collisionSide:String = "";
public function Collision()
{
}
static public function block(r1:Sprite, r2:Sprite):void
{
//Calculate the distance vector
var vx:Number
= (r1.x + (r1.width / 2))
- (r2.x + (r2.width / 2));
var vy:Number
= (r1.y + (r1.height / 2))
- (r2.y + (r2.height / 2));
//Check whether vx
//is less than the combined half widths
if(Math.abs(vx) < r1.width / 2 + r2.width / 2)
{
//A collision might be occurring! Check
//whether vy is less than the combined half heights
if(Math.abs(vy) < r1.height / 2 + r2.height / 2)
{
//A collision has ocurred! This is good!
//Find out the size of the overlap on both the X and Y axes
var overlap_X:Number
= r1.width / 2
+ r2.width / 2
- Math.abs(vx);
var overlap_Y:Number
= r1.height / 2
+ r2.height / 2
- Math.abs(vy);
//The collision has occurred on the axis with the
//*smallest* amount of overlap. Let's figure out which
//axis that is
if(overlap_X >= overlap_Y)
{
//The collision is happening on the X axis
//But on which side? _v0's vy can tell us
if(vy > 0)
{
collisionSide = "Top";
//Move the rectangle out of the collision
r1.y = r1.y + overlap_Y;
}
else
{
collisionSide = "Bottom";
//Move the rectangle out of the collision
r1.y = r1.y - overlap_Y;
}
}
else
{
//The collision is happening on the Y axis
//But on which side? _v0's vx can tell us
if(vx > 0)
{
collisionSide = "Left";
//Move the rectangle out of the collision
r1.x = r1.x + overlap_X;
}
else
{
collisionSide = "Right";
//Move the rectangle out of the collision
r1.x = r1.x - overlap_X;
}
}
}
else
{
//No collision
collisionSide = "No collision";
}
}
else
{
//No collision
collisionSide = "No collision";
}
}
}
}
Any help would be much appreciated. I'm a beginner so its always possible the problem is something simple I've missed.
Im also asking a question about the unwanted bobbing of the animations. If any of that info helps you, or you're smart enough to know the solution to that too, the question is HERE
have you tried this?
if (event.keyCode == Keyboard.LEFT || event.keyCode == 65 )
{
_bLeft=true;
_bRight=false;
_bUp=false;
_bDown=false;
}
else if (event.keyCode == Keyboard.RIGHT || event.keyCode == 68)
{
_bRight=true;
_bLeft=false;
_bUp=false;
_bDown=false;
}
else if (event.keyCode == Keyboard.UP || event.keyCode == 87 )
{
_bUp=true;
_bRight=false;
_bLeft=false;
_bDown=false;
}
else if (event.keyCode == Keyboard.DOWN || event.keyCode == 83)
{
_bDown=true;
_bRight=false;
_bLeft=false;
_bUp=false;
}