问题
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
回答1:
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;
}
来源:https://stackoverflow.com/questions/22544010/as3-friction-causing-movie-clip-to-jump-temporarily-alter-path-playable-s