The problem is that I don't even understand what is wrong. I at least need help debugging my code.
EDIT: Here is my code.
package CopperCrew.Gameplay.PlayerStates {
import CopperCrew.Gameplay.*;
import CopperCrew.Gameplay.Entities.*;
import CopperCrew.Controls.*;
import HTools.Math.sgn;
use namespace playerInternal;
public class PlayerState {
protected var maxXSpeed:Number=15;
protected var maxYSpeed:Number=Infinity;
protected var runSpeed:Number=10;
protected var forwardAccl:Number=0.2;
protected var backwardAccl:Number=-2;
protected var coastAccl:Number=-0.2;
protected var gravity:Boolean=true;
protected var gravityAccl:Number=0.8;
protected var canJump:Boolean=true;
protected var jumpImpulse:Number=17;
protected var player:Player;
protected var animName:String;
protected var animLoops:Boolean=true;
protected var autoMirror:Boolean=true;
public function PlayerState(player:Player) {
if(!player) throw new ArgumentError("Player can't be null!");
this.player=player;
}
public function init():void {
player.char.currentAnimName=animName;
player.char.currentAnimInst.loop=animLoops;
}
public function deinit():void {}
public function pretick():void {
selectState();
}
public function tick():void {
xMovement();
yMovement();
}
protected function selectState():void {
const absSpeed:Number=Math.abs(player.xSpeed);
if(player.onFloor) {
if(absSpeed<0>=runSpeed){
player.setState("run");
} else {
player.setState("walk");
}
}
}
protected function xMovement():void {
horizontalControl();
//cap the speed
if(player.xSpeed>maxXSpeed) { player.xSpeed=maxXSpeed; }
else if(player.xSpeed< -maxXSpeed) { player.xSpeed= -maxXSpeed; }
if(autoMirror) {
if(player.xSpeed<0>0) {
player.char.scaleX=1;
}
}
player.x+=player.xSpeed;
player.applyCollisions(true,false);
}
protected function yMovement():void {
if(canJump && player.onFloor) {
jumpControl();
}
if(gravity) {
player.ySpeed+=gravityAccl;
}
player.onFloor=false;
if(player.ySpeed>maxYSpeed) { player.ySpeed=maxYSpeed; }
else if(player.ySpeed< -maxYSpeed) { player.ySpeed= -maxYSpeed; }
player.y+=player.ySpeed;
player.applyCollisions(false,true);
}
protected function horizontalControl():void {
var xDir:int=sgn(player.xSpeed);
var controlXDir:int=0;
if(controls.kDown(Keys.LEFT)) {
controlXDir--;
}
if(controls.kDown(Keys.RIGHT)) {
controlXDir++;
}
if(xDir==0) xDir=controlXDir;
if(controlXDir==0) {
player.xSpeed+=xDir*coastAccl;
} else if(controlXDir==xDir) {
player.xSpeed+=xDir*forwardAccl;
} else if(controlXDir==-xDir) {
player.xSpeed+=xDir*backwardAccl;
}
if(Math.abs(player.xSpeed)<0.1) player.xSpeed=0;
}
protected function jumpControl():void {
var yDir:int=sgn(player.ySpeed);
if(controls.kHit(Keys.JUMP)) {
player.ySpeed-=jumpImpulse;
if(Math.abs(player.xSpeed)<runSpeed) {
player.setState("jump");
} else {
player.setState("jump");
}
}
}
public function get name():String { return "Base State"; }
protected final function get controls():Controls { return player.controls; }
}
}
package CopperCrew.Gameplay.Entities {
import starling.display.*;
import starling.events.*;
import CopperCrew.Chars.Man.Man;
import CopperCrew.Chars.Woman.Woman;
import CopperCrew.Chars.Robot.Robot;
import CopperCrew.Chars.BaseChar;
import CopperCrew.Chars.Markers.*;
import CopperCrew.Controls.*;
import CopperCrew.Gameplay.PlayerStates.*;
import CopperCrew.Gameplay.*;
import HTools.Starling.*;
import HTools.Starling.Tilemap.*;
import flash.geom.Rectangle;
import flash.display.DisplayObject;
use namespace playerInternal;
public class Player extends GameEntity {
public var char:BaseChar;
private var state:PlayerState;
private var states:Object;
playerInternal var xSpeed:Number=0;
playerInternal var ySpeed:Number=0;
playerInternal var onFloor:Boolean;
public function Player(gameplay:Gameplay) {
super(gameplay);
cameraIntrest=100;
name="player";
loadPlayerChar("robot");
loadStates();
setState("idle");
}
private function loadPlayerChar(charName:String) {
var cl:Class={woman:Woman, man:Man, robot:Robot}[charName];
if(!cl) throw new ArgumentError("Bad character name");
char=new cl();
vis=char;
}
public override function tick():void {
state.pretick();
state.tick();
char.tick();
}
playerInternal function applyCollisions(xDir:Boolean,yDir:Boolean):void {
const basePlatformingBox:Rectangle=currentPlatformingBox;
var platformingBox:Rectangle=basePlatformingBox.clone();
platformingBox.x+=x;
platformingBox.y+=y;
if(yDir) {
checkFloor(platformingBox);
}
if(xDir) {
checkWall(platformingBox,-1);
checkWall(platformingBox,1);
}
x=platformingBox.x-basePlatformingBox.x;
y=platformingBox.y-basePlatformingBox.y;
}
private function checkFloor(platBox:Rectangle):Boolean {
const tileMap:ITileMap=gameplay.level.bgTileMap;
const tileWidth:Number=gameplay.level.bgTileSet.tileWidth;
const tileHeight:Number=gameplay.level.bgTileSet.tileHeight;
const leftTile:int=platBox.left/tileWidth;
const endTile:int=Math.ceil(platBox.right/tileWidth)+1;
const tileY:int=platBox.bottom/tileHeight;
var tileRect:Rectangle=new Rectangle(0,tileY*tileHeight,tileWidth,tileHeight);
var hit:Boolean=false;
for(var tileX:int=leftTile;tileX<endTile;tileX++) {
var endLoop:Boolean=false;
var tileData:TileData=tileMap.tileAt(tileX,tileY);
if(!tileData) continue;
tileRect.x=tileX*tileWidth;
var intersection:Rectangle=tileRect.intersection(platBox);
if(intersection.width==0) continue;
var tileInfo:TileSetTileData=gameplay.level.bgTileSet.tiles[tileData.tileId];
//trace("Floor collision",tileRect);
var solid:Boolean=false;
if(tileInfo.attributes.solid) solid=true;
if(tileInfo.attributes.floor) {
if(tileInfo.attributes.oneWayFloor) {
if(ySpeed>=0) solid=true;
} else {
solid=true;
}
}
if(solid) {
//nudge the platBox up to one pixel above the tileRect
platBox.y-=intersection.height;
ySpeed=0;//hitting solid ground imedetly cancels the y speed
//endLoop=true;// won't be any other hits, since only one row was scanned
hit=true;
onFloor=true;
dispatchEventWith("floorHit");
}
if(endLoop) break;
}
return hit;
}
private function checkWall(platBox:Rectangle,dir:int):Boolean {
const tileMap:ITileMap=gameplay.level.bgTileMap;
const tileWidth:Number=gameplay.level.bgTileSet.tileWidth;
const tileHeight:Number=gameplay.level.bgTileSet.tileHeight;
const startY:int=platBox.top/tileHeight;
const endY:int=Math.ceil(platBox.bottom/tileHeight);
const tileX:int=(
(dir==-1)?
Math.floor(platBox.left/tileWidth):
Math.floor(platBox.right/tileWidth)
);
var hit:Boolean=false;
var tileRect:Rectangle=new Rectangle(tileX*tileWidth,0,tileWidth,tileHeight);
for(var tileY:int=startY;tileY<endY;++tileY) {
var endLoop:Boolean=false;
var tileData:TileData=tileMap.tileAt(tileX,tileY);
if(!tileData) continue;
tileRect.y=tileY*tileHeight;
var intersection:Rectangle=tileRect.intersection(platBox);
if(intersection.height==0) continue;
var tileInfo:TileSetTileData=gameplay.level.bgTileSet.tiles[tileData.tileId];
//trace("Wall collision",tileRect);
var solid:Boolean=false;
if(tileInfo.attributes.solid) solid=true;
if(tileInfo.attributes.wall) solid=true;
if(solid) {
if(dir==-1) {//moving left
platBox.x+=intersection.width;
} else {//moving right
platBox.x-=intersection.width;
}
xSpeed=0;
endLoop=true;// won't be any other hits, since only one row was scanned
hit=true;
dispatchEventWith("wallHit");
}
if(endLoop) break;
}
return hit;
}
playerInternal function get currentPlatformingBox():Rectangle {
const markers:Vector.<MarkerData>=char.markers;
for each(var marker:MarkerData in markers) {
if(!marker) continue;
if(marker.type=="Platforming") {
return Rectangle(marker.marker);
}
}
return null;
}
private function loadStates():void {
states={
"idle": new IdleState(this),
"walk": new WalkState(this),
"run": new RunState(this),
"jump": new JumpState(this),
"fall": new FallState(this)
};
}
public function setState(stateName:String):void {
if(state && state.name==stateName) return;
var newState:PlayerState=states[stateName];
if(!newState) throw new ArgumentError("Invalid player state name!");
if(state) {
state.deinit();
}
state=newState;
state.init();
}
playerInternal function get controls():Controls { return gameplay.controls; }
public override function get debugReprensentation():flash.display.DisplayObject {
return char.makeDebugReprensentation();
}
}
}
I don't get why I sometimes get stuck in walls and/or floors.