AS3 - Movie Clip animations (undesirably) bob up and down. [Playable SWF included] - actionscript-3

Im making a game 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. Plus a 50 pixel stage boundary.
_character has five key frames, each with an animation inside, which plays when the four direction buttons are pressed, plus the red stationary animation when no keys are pressed. While moving the characters body and head should be still, with the legs moving. Example below
_character Right Animation
However my problem is that the Movie clip bobs up and down at different areas around the stage, then is fine in others.
In the SWF example below you’ll see the characters mouth and shoulders bobbing up and down around the stage, but strangely enough its back to normal at the bottom of the play area. (Apart from in-between the two boxes to the lower right.)
Rookies Game SWF
This is the embedded SWF featuring all frames. The only thing that should change is the body colour and the eyes and legs moving. The head and shoulders dont bob up and down.
ChAracter Resource SWF
Does anyone have any idea what this is or why its happening? I triple checked my character swf just in case there is a miss-positioned frame to create the bouncing/bobbing animation, but they are all correct, the swf should not be doing that.
If I remove some boxes, the bobbing effect stops in some areas, but comes back in others. Sometimes when it touches a box it bobs and other sides of boxes it doesnt(?) Strangely enough, the bobbing returns when I press down at the bottom of the play area. In the other SWF the bottom of the stage was one of the few areas where the MovieClip didnt bob/bounce.
Rookies Game SWF w/ less boxes
If I remove all the boxes, the bobbing stops except when I press down on the bottom of the playable area. But only that one side causes the bobbing. If I remove the stage boundaries also, the bobbing completely stops presumably because there is nothing for the MovieClip to react to.
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
{
//Add them to stage.
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);
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 show the sprites. Note that the grid background is a single image. The game is not tile based..
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!
//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.
Im also asking a question about the jump/shudder the Movieclip does when crossing gaps in the maze. If any of that info helps you, or you're smart enough to know the solution to that too, the question is HERE

Related

Trying to add keyboard events to a child movieclip I call to the stage in code

So this is my first semester in school coding and right now I'm trying to make a little 2D game with a character who I need to move up and down.
So far, I've been able to create a titlescreen and then when you click start it goes to the next screen, where my main character is.
I add him to the stage manually through the code, and then I tried to make him move up down left and right with the arrow keys but he only appears, and does not move.
This is my code so far
package lib.fly
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
public class FlyGame extends MovieClip
{
public var mainCharacter:MovieClip;
public var vx:Number;
public var vy:Number;
public function FlyGame()
{
trace ("Initiate");
init();
}
private function init():void
{
vx = 0;
vy = 0;
addEventListener(Event.ENTER_FRAME, onEnterFrame);
stage.addEventListener(KeyboardEvent.KEY_DOWN, moveAround);
stage.addEventListener(KeyboardEvent.KEY_UP, dontMove);
//var dx:Number = speed* Math.cos(angle);
//var dy:Number = speed* Math.sin(angle);
trace ("Keyboard Event Listeners");
}
private function moveAround(event:KeyboardEvent):void
{
trace ("Actual Keyboard Events");
if (event.keyCode == Keyboard.LEFT)
{
vx = -5;
}
else if (event.keyCode == Keyboard.RIGHT)
{
vx = 5;
}
else if (event.keyCode == Keyboard.UP)
{
vy = - 5;
}
else if (event.keyCode == Keyboard.DOWN)
{
vy = 5;
}
}
private function dontMove(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.LEFT || event.keyCode == Keyboard.RIGHT)
{
vx = 0;
}
else if (event.keyCode == Keyboard.UP || event.keyCode == Keyboard.DOWN)
{
vy = 0;
}
}
public function onEnterFrame(event:Event):void
{
mainCharacter = new BoyFlying();
mainCharacter.x = 20;
mainCharacter.y = 150;
mainCharacter.x += vx;
mainCharacter.y += vy;
addChild(mainCharacter);
}
}
}
The output produces the trace statements up until my "Actual Keyboard Events"
Sorry, I'm brand new to this so any help would be appreciated. Thank you for your time
Try this logic below and see if it helps your program to work as expected...
Adjust function init()
private function init():void
{
vx = vy = 0; //chain them since same value
mainCharacter = new BoyFlying(); //create once here and control in other functions
mainCharacter.x = 20;
mainCharacter.y = 150;
mainCharacter.addEventListener(Event.ENTER_FRAME, onEnterFrame);
addChild(mainCharacter);
stage.addEventListener(KeyboardEvent.KEY_DOWN, moveAround);
//stage.addEventListener(KeyboardEvent.KEY_UP, dontMove); //what is it good for?
trace ("added... Keyboard Event Listeners");
//var dx:Number = speed* Math.cos(angle);
//var dy:Number = speed* Math.sin(angle);
}
Adjust function moveAround()
private function moveAround(event:KeyboardEvent):void
{
trace ("Actual Keyboard Events");
if (event.keyCode == Keyboard.LEFT)
{ vx -= 5; }
if (event.keyCode == Keyboard.RIGHT)
{ vx += 5; }
if (event.keyCode == Keyboard.UP)
{ vy -= 5; }
if (event.keyCode == Keyboard.DOWN)
{ vy += 5; }
}
Adjust function onEnterFrame()
public function onEnterFrame(event:Event):void
{
//# no need for += here since function moveAround() changes these vx and vy values on key press
//# infact your character could be moved (x/y) just by keyboard event instead of per FPS screen update (eg: not with EnterFrame)
mainCharacter.x = vx;
mainCharacter.y = vy;
}

Flash - coordinates keeps reseting to 0

ok I can't make this work no matter what, it keeps resetting coordinates to 0.
I make a ship object on stage and make a class of that ship.
public class Ship extends MovieClip {
private var speedX;
private var speedY;
public function Ship() {
x = 50;
y = 150;
trace(x, y);
stage.addEventListener(KeyboardEvent.KEY_DOWN ,keyDown);
stage.addEventListener(KeyboardEvent.KEY_UP ,keyUp);
stage.addEventListener(Event.ENTER_FRAME, update);
}
public function keyDown(e:KeyboardEvent) {
if(e.keyCode == 37) {
speedX = -5;
}
if(e.keyCode == 38) {
speedY = -5;
}
if(e.keyCode == 39) {
speedX = 5;
}
if(e.keyCode == 40) {
speedY = 5;
}
}
public function keyUp(e:KeyboardEvent) {
trace (x,y);
if(e.keyCode == 37 || e.keyCode == 39) {
speedX = 0;
}
if(e.keyCode == 38 || e.keyCode == 40) {
speedY = 0;
}
}
public function update(e:Event) {
x += speedX;
y += speedY;
}
}
here I set coordinates to 50, 150, the trace shows it right, but it still doesn't work.
the game is working fine except coordinates, what am I doing wrong?
Not sure that this will help, but I would explicitly set the update speed to 0 in the Ship() function.
I would also set the position, based on where you placed it, so that you can just place it in the scene, and then it will start from that location.
public function Ship() {
speedX = 0
speedY = 0
trace(x, y);
stage.addEventListener(KeyboardEvent.KEY_DOWN ,keyDown);
stage.addEventListener(KeyboardEvent.KEY_UP ,keyUp);
stage.addEventListener(Event.ENTER_FRAME, update);
}
I've tested this code on my machine and it works fine. Are there any parts of the code that you're not including?
I also changed the class to accept the main stage object as a parameter. This might solve the problem you're having:
public function Ship(pStage:DisplayObjectContainer):void
{
x = 50;
y = 150;
trace(x, y);
pStage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown);
pStage.addEventListener(KeyboardEvent.KEY_UP, keyUp);
pStage.addEventListener(Event.ENTER_FRAME, update);
}
Wherever you initialize the Ship object, make sure you're passing the stage object from your Main class. This has worked for me with all of my AS3 projects.

Action Script 3. Platform game physics glitch (gravity)

when my player touches the floor, he is unable to move because he is on the floor and being incremented up.
In the main class I have the movement
private function processMovement():void
{
if (touchingGround)
{
if (upKey)
{
character.jumpUp();
}
if (leftKey)
{
character.moveLeft();
}
if (rightKey)
{
character.moveRight();
}
if (!leftKey && !rightKey && !upKey)
{
character.dontMove();
}
}
}
Then in the character class you will see this.
public class player extends OnGround
{
public var canJumpAn:Boolean;
public var attackAn:Boolean;
public var jumpheight:Number = 18;
public function player()
{
addEventListener(Event.ADDED_TO_STAGE, onAdd);
}
private function onAdd(e: Event): void
{
removeEventListener(Event.ADDED_TO_STAGE, onAdd);
}
public function moveLeft():void
{
//decrease VELOCITY
xV -= 2;
if (xV > -7)
{
xV = -7;
}
this.gotoAndStop("run");
//add this to the Mc . x pos baby.
this.x += xV;
this.scaleX = -1;
charIsrunning = true;
}
public function moveRight():void
{
//increase VELOCITY
xV += 2;
if (xV > 7)
{
xV = 7;
}
this.gotoAndStop("run");
//add this to the Mc . x pos baby.
this.x += xV;
this.scaleX = 1;
charIsrunning = true;
}
public function dontMove():void
{
//if no button presses then do this
this.gotoAndStop("stop");
//slowd down ball
xV *= friction;
charIsrunning = false;
isDefending = false;
//stop the ball if you're not moving
if (xV > - 1 && xV < 1)
{
xV = 0;
}
}
override public function positionOnLand():void
{
isJumping = false;
///=gotoAndStop(1);
}
public function defend():void
{
isDefending = true;
this.gotoAndStop("defend");
charIsrunning = false;
}
public function attack():void
{
this.gotoAndStop("attack");
}
public function jumpUp():void
{
if (!isJumping)
{
isJumping = true;
this.gotoAndStop("jump");
//
}
}
}
}
OnGround is another class that player extends, as you can see.
public class OnGround extends MovieClip
{
public var grav:Number;
public var friction:Number;
public var xV:Number;
public var yV:Number;
protected var charIsrunning:Boolean;
protected var isDefending:Boolean;
protected var isJumping:Boolean;
public function OnGround()
{
addEventListener(Event.ADDED_TO_STAGE, init)
charIsrunning = false;
isDefending = false;
//gotoAndStsop("jump");
}
private function init(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
//gravity
grav = 0.6;
//y velocity
yV = 0;
//x velocity
xV = 0;
//
friction = 0.9;
addEventListener(Event.ENTER_FRAME, fall);
}
private function fall(e:Event):void
{
//add grav to y VELOCITY
yV += grav;
trace(yV);
this.y += yV
}
public function incrementUp():void
{
this.y -= 0.1;
//trace("incrementing");
}
public function keepOnGround():void
{
//trace("onGroundBitch");
grav = 0;
yV = 0;
positionOnLand();
}
public function positionOnLand():void
{
//overide
}
}
}
This is a function that's in the main class
for (var c:int = 0; c < childrenOnStage; c++)
{
if (getChildAt(c).name == "player")
{
if (ground.level1Ground.hitTestPoint(getChildAt(c).x + 13, getChildAt(c).y, true) || ground.level1Ground.hitTestPoint(getChildAt(c).x - 13, getChildAt(c).y, true))
{
getChildAt(c).y --;
//OnGround(getChildAt(c)).incrementUp();
OnGround(getChildAt(c)).keepOnGround();
touchingGround = true;
}
else
{
touchingGround = false;
}
The problem is that when the player touches the ground then it's y position is incremented until it isn't touching the ground and then it's suppose to be kept on the ground by turning grav to = 0 and y velocity to 0.
This means gravity is turned off and the players y position will not shift up (when I jump)
or when go down to be kept on ground.
I would appreciate it if someone can lend me a hand or point me in the correct direction.
I'm not sure why you'd have a gravity value per object unless you really intend to have different object instances have individual gravities.
If not I'd reference a gravity constant instead.
Is anti-gravity a feature of the game? if not then I'd avoid setting gravity to 0. It may 'work' (to an extent) but it's not a good model/abstraction of reality.
Rather, what I would do is seperate the force applied and the current momentum:
The (downward) force of gravity is applied at all times.
When you're standing on the ground an upward force equal and opposite to gravity is applied.
When you jump, add a one-off instance of upward force.
Use the current forces to change the current momentum and use the current momentum to change the position.

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

HitTest with movieClips on the stage from within a class

I followed a simple tutorial trying to make a simple top-down game and I have this class so far but I can't figure out how to do a hit test with a movie clip on the stage.
package
{
import flash.display.Stage;
import flash.display.MovieClip;
import flash.events.Event;
import KeyObject;
public class Player extends MovieClip
{
public var stageRef:Stage;
public var key:KeyObject;
public var leftPressed:Boolean = false;
public var rightPressed:Boolean = false;
public var upPressed:Boolean = false;
public var downPressed:Boolean = false;
public var lastMove:String;
public var speed:Number = 5;
public function Player(stageRef:Stage, X:int, Y:int):void
{
this.stageRef = stageRef;
this.x = X;
this.y = Y;
key = new KeyObject(stageRef);
addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
}
public function loop(e:Event):void
{
checkKeypresses();
if(leftPressed){
x -= speed;
if(this.currentFrame < 7 || this.currentFrame > 9){
this.gotoAndPlay("left");
lastMove="left";
checkKeypresses();
}
} else if(rightPressed){
x += speed;
if(this.currentFrame < 12 || this.currentFrame > 14){
this.gotoAndPlay("right");
lastMove="right";
checkKeypresses();
}
}
if(upPressed){
y -= speed;
if(this.currentFrame < 17 || this.currentFrame > 19){
this.gotoAndPlay("up");
lastMove="up";
checkKeypresses();
}
} else if(downPressed){
y += speed;
if(this.currentFrame < 2 || this.currentFrame > 4){
this.gotoAndPlay("down");
lastMove="down";
checkKeypresses();
}
}
}
public function detectPlayer(){
//HOW VVVVVVVVVVV ?
if(lvl.wall_mc.hitTestPoint(this.x,this.y,true)){
if( lastMove == "right"){
this.x -= speed;
}
if( lastMove == "left"){
this.x += speed;
}
if( lastMove == "up"){
this.y += speed;
}
if( lastMove == "down"){
this.y -= speed;
}
}
}
public function checkKeypresses():void
{
if(key.isDown(37) || key.isDown(65)){ // left arrow or A
leftPressed = true;
} else {
leftPressed = false;
}
if(key.isDown(38) || key.isDown(87)){ //up arrow or W
upPressed = true;
} else {
upPressed = false;
}
if(key.isDown(39) || key.isDown(68)){ //right arrow or D
rightPressed = true;
} else {
rightPressed = false;
}
if(key.isDown(40) || key.isDown(83)){ //down arrow or S
downPressed = true;
} else {
downPressed = false;
}
}
}
}
in the line "if(lvl.wall_mc.hitTestPoint(this.x,this.y,true))" I got my problem. please point me in the right direction.
Where is lvl defined? If it is a MovieClip on the stage, then you need to understand that your instance of Player is most likely a sibling of lvl, this means that you need to "go up a level" in order to access it.
Although this is bad design, it should work:
if ( MovieClip( stage.getChildByName("lvl") ).wall_mc.hitTestPoint(this.x,this.y,true) )
What this is doing is it's finding the child named "lvl" on stage, casting it as a MovieClip, then accessing the wall_mc child.
If you would like to improve upon this design to make it less tightly-coupled, you should move this logic up a level into either your Document Class or some other class that has access to both Player and lvl.
UPDATE:
After looking at your full code, there are a few ways to fix your issue.
First, you have Main.as as your Document Class, however in the constructor, you're adding the Player instance to the stage instead of parenting it under Main. This causes Player to be a sibling of your Main document class rather than a child.
One way to fix this would be to add Player to main, then change your detectPlayer method to check against Player's parent:
if ( MovieClip( parent.getChildByName("lvl") ).wall_mc.hitTestPoint(this.x,this.y,true) )
Second, it doesn't appear as though you were ever actually calling the method (detectPlayer) that checks for collision with the walls. To remedy this, you can place a call to detectPlayer at the end of your Player.loop method.
As mentioned before, this is not best practice. Additionally, I noticed that you're passing stage to your Player class and later passing it to a KeyObject, so re-parenting the Player in this way may break some of your intended gameplay.
If you are interested in refactoring for loose coupling, I would suggest modifying your Player.detectPlayer method to accept a DisplayObject as an argument and call that from and ENTER_FRAME listener within your Main class:
package
{
import flash.display.Stage;
import flash.display.MovieClip;
import flash.events.Event;
public class Main extends MovieClip
{
public var player:Player;
public function Main():void
{
player = new Player(stage, 320, 240);
stage.addChild(player);
addEventListener(Event.EXIT_FRAME, loop);
}
private function loop($event:Event):void
{
player.detectPlayer(lvl.wall_mc);
}
}
}
This would require the following change in Player:
public function detectPlayer($testObject:DisplayObject)
{
if ( $testObject.hitTestPoint(this.x, this.y, true) )
{
if( lastMove == "right"){
this.x -= speed;
}
if( lastMove == "left"){
this.x += speed;
}
if( lastMove == "up"){
this.y += speed;
}
if( lastMove == "down"){
this.y -= speed;
}
}
}