PDA

View Full Version : [AS3] Collision


organburner
09-26-2009, 04:53 PM
Hi
I'm trying to make a game, but I am having some small problems.
I've been following some tutorials trying to get movement, collision and scrolling right but the tutorials are all pretty different.

Anyway, I have two problems. The biggest one is that the jumping function is.... Sketchy at best. Sometimes if you jump the player sprite will fall through the level when you hit something, sometimes the player will go through half a block before stopping and sometimes it will look fine. I've tried to find out why this is, but it seems to be completely random.

I would also appreciate some suggestions as to how I would integrate walls that work when it comes to stopping the character. I have an idea for this which would be to set the speed variable to 0 whenever the player hits a block and then reset it every time the move function is enabled again (This was how I did it without the scrolling) but I do not know how to integrate it here.


Anyway, the code is sort of messy. (Also, if it's relevant the player is 32 pixels long and 64 tall)
//********************************************
//********************************************
//*******Misc variable list*******************
//********************************************
//********************************************
//Defines the true or false value of keys
var varRight:Boolean = false;
var varLeft:Boolean = false;
var varUp:Boolean = false;
var varDown:Boolean = false;


//Defines player speed
var speed:Number = 10;


//Jumping variables
var jumping:Boolean = false;
var jumpSpeedLimit:int = 25;
var jumpSpeed:Number = jumpSpeedLimit;
var playerOnGround:Boolean = false;


//Event listeners checking if events happen
stage.addEventListener(Event.ENTER_FRAME, movement);
stage.addEventListener(KeyboardEvent.KEY_DOWN , checkKeys);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUps);



//********************************************
//********************************************
//*******Player code and functions************
//********************************************
//********************************************

//Checks if keys are down
function checkKeys(event:KeyboardEvent){
if (event.keyCode == 68) {

varRight = true;
}
if (event.keyCode == 87) {

varUp = true;
}
if (event.keyCode == 65) {

varLeft = true;
}
if (event.keyCode == 83) {

varDown = true;
}
}



//Checks if keys are up
function keyUps(event:KeyboardEvent) {
if (event.keyCode == 68) {
event.keyCode = 0;
varRight=false;

}
if (event.keyCode == 87) {
event.keyCode = 0;
varUp=false;

}
if (event.keyCode == 65) {
event.keyCode = 0;
varLeft=false;

}
if (event.keyCode == 83) {
event.keyCode = 0;
varDown=false;

}
}



//jumping function
function jump():void{
//if player isn't already jumping
if(!jumping){
//then start jumping
jumping = true;
jumpSpeed = jumpSpeedLimit*-1;
blockHolder.y -= jumpSpeed;
} else {
//then continue jumping if already in the air
//crazy math that I won't explain
if(jumpSpeed < 0){
jumpSpeed *= 1 - jumpSpeedLimit/125;
if(jumpSpeed > -jumpSpeedLimit/5){
jumpSpeed *= -1;
}
}
if(jumpSpeed > 0 && jumpSpeed <= jumpSpeedLimit){
jumpSpeed *= 1 + jumpSpeedLimit/50;
}
blockHolder.y -= jumpSpeed;
for(var i:int = 0;i<blockHolder.numChildren; i++){
//getting the current block
var hitBlock:DisplayObject = blockHolder.getChildAt(i);
//checking hit test
if(player.hitTestObject(hitBlock)){
//if player is falling down
if(jumpSpeed > 0){
//stop jumping
jumping = false;
//and set the guys coordinates to be on top of the block
player.y = hitBlock.y - player.height/2;
//he's on solid ground
playerOnGround = true;
//break out of the loop
break;
} else {
jumpSpeed = Math.abs(jumpSpeed);
//making the main guy get away from the block
player.y = hitBlock.y + hitBlock.height + 1;
}

}
}
}
}

function resetspeed():void{
speed = 10;
}
//Moves the player according to check keys functions.
function movement(event:Event):void{

//The colission checker
for(var i:int = 0;i<blockHolder.numChildren; i++){
//getting the current block
var hitBlock:DisplayObject = blockHolder.getChildAt(i);
//checking hit test and if main is above the brick
if(player.hitTestObject(hitBlock) && player.y < hitBlock.y){
//this time, we just make playerOnGround true
playerOnGround = true;
//and break from the loop
break;
}

playerOnGround = false;
}

//then we make him fall if he isn't on ground
if(!playerOnGround){
jumping = true;
}
//reset speed so player can move again
//resetspeed();

if (varRight == true) {
blockHolder.x -= speed;

}
if (varUp || jumping) {
jump();
}
if (varLeft == true) {
blockHolder.x += speed;

}
}
//********************************************
//********************************************
//*******Level codes and stuff****************
//********************************************
//********************************************
//levelcount
var lvlCurrent:int = 1;
//this variable will hold the character
var X:String = 'PLAYER';
//current row we are creating
var row:int = 0;
//the array for level 1
var lvlArray1:Array = new Array(
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1, 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
);

//this guy will hold all of the blocks
var blockHolder:Sprite = new Sprite();

//then we add him to stage
addChild(blockHolder);
function createLvl():void{
//getting the current level that we are on
var lvlArray:Array = MovieClip(root)['lvlArray'+lvlCurrent];
//we have to find how far this level goes
//this will be used so we know when to move to the next row
//there will always be 24 rows, so this is how we find it out
//of course, this will make the lvl formatting very strict
var lvlColumns:int = Math.ceil(lvlArray.length/24);
//now we must create the level
for(var i:int = 0;i<lvlArray.length;i++){
//checking if we move onto the next row
//this checks if i is divisible by the # of columns
if(i/lvlColumns == int(i/lvlColumns)){
row ++;
}
if(lvlArray[i] == 1){
//making a new block
var newBlock:Block = new Block();
//drawing the block
newBlock.graphics.beginFill(0x000000/*The color for shape*/,1/*The alpha for the shape*/);
//turning the shape into a square
newBlock.graphics.drawRect(0,0,32,32);
//change the coordinates of the block
newBlock.x = (i-(row-1)*lvlColumns)*newBlock.width;
newBlock.y = (row-1)*newBlock.height;
//then finally adding it to stage
blockHolder.addChild(newBlock);
} else if (lvlArray[i] == 'MAIN'){
player.x = (i-(row-1)*lvlColumns)*newBlock.width;
player.y = (row-1)*newBlock.height;
}
}
//reset the row for another use
row = 0;
//then we center the screen on the main character
//this variable will tell us how far away we have to move everything
//400 is about centered for player we'll use that number
//mainmovey is the vertical thing, so just do the right thing
var mainMove:int = 400 - player.x;
var mainMovey:int = 300 - player.y;
//then move player and the entire level to center on him
player.x += mainMove;
blockHolder.x += mainMove;
player.y += mainMovey
blockHolder.y +=mainMovey
}

//running the createlvl funciton
createLvl();



All help is appreciated.

locrizak
09-27-2009, 04:43 AM
I have a couple of tips for you in this situation.

I recently did some research for work about game movement and I used this idea when I did it.. The array holds all of the info for the level. Right now (correct me if I'm wrong) You are only using the the lvlArray right off the bat to create the level. The way I did it (and it worked great) is kept a record of where the player was in the array at all times. I then calulated which way the player could move based on if there was a 1 on either side , above or below (above and below was retrieved by storing the width of the map, which would be the actual width / how often the numbers int he array are calculated). it would be something like this:



var _north : Boolean = lvlArr[(currentManPos - mapWidth)] == 1 ? false : true;



Just a thought, and it works pretty good. You don't have to kill flash by looking if the man is hitting something in an ENTER_FRAME. Also something you might also want to look at is creating the lvlArray dynamically. Simply draw where the man can't move in a MovieClip ( I used green blocks ) and let the extremely fast BitmapData class to run through that movieclip and get the color of the pixel ( or block ) its on. if its a color push a 1 if not push a 0. This way if you want to add another platform just draw it on the stage and away you go. No messing around with the lvlArray

organburner
09-27-2009, 09:37 AM
Alright, I'll see if I can get it to work that way.

Also, if you have an example of how to dynamically create the array I'd be grateful. I wouldn't be in such a hurry, but the deadline for this was recently cut in half :S


EDIT: Haven't really had that much luck yet integrating that line, mostly because I'm not certain what currentManPos is. I'm assuming its the position of the player.

EDIT2: Also, with the whole jumping thing it pretty much worked (With the exception that I could move through walls) before I enabled the vertical scrolling, so I'm pretty sure I messed something up there in the jump function, but I can't see what.




EDIT3:
Alright, so I kind of got it to work, this is still just a movement thing making sure player doesn't fall through the floor.

The problem is that the player instance is jumping a lot when standing still on a block.
Here's the updated move function (I scrapped the jump function for now, I'm going to work on that later)
//The colission checker
function collcheck():void{
for (var i:int=0; i < blockHolder.numChildren; i++) {
//getting the current block
var hitBlock:DisplayObject = blockHolder.getChildAt(i);
//checking hit test and if main is above the brick
if (player.hitTestObject(hitBlock) && player.y < hitBlock.y) {
//player.y -= 16;
blockHolder.y += 32;
stopscrolly = true;

}
else
{
stopscrolly = false;
}
}
}


//Moves the player according to check keys functions.
function movement(event:Event):void{
//then we check collision
collcheck();
//reset speed so player can move again
resetspeed();
//Gravity effect!
if (stopscrolly == true){
graveff = 0;
}
else
{
graveff = 25;
}
gravity();
if (varRight == true) {
blockHolder.x -= speed;

}
if (varUp || jumping) {
jump();
}
if (varLeft == true) {
blockHolder.x += speed;

}
}

organburner
10-02-2009, 05:37 PM
Alright, so I got the vertical collision to kind of work (Still need to work in a jump function and horizontal collision though)
This is the part of the code I changed
//The colission checker
function collcheck():void{
for (var i:int=0; i < blockHolder.numChildren; i++) {
//getting the current block
var hitBlock:DisplayObject = blockHolder.getChildAt(i);
//checking hit test and if main is above the brick
if (player.hitTestObject(hitBlock) && player.y < hitBlock.y) {
blockHolder.y += player.height/8.7;
stopscrolly = true;
}
else
{
graveff = 15;
stopscrolly = false;
}
}
}


//Moves the player according to check keys functions.
function movement(event:Event):void{
//then we check collision
collcheck();
//reset speed so player can move again
resetspeed();
//Gravity effect!
while (stopscrolly == true){
graveff = 0;
break;
}

Also changed gravity effect to 15. If I change that I need to recalculate the player.height/8.7 line to make it perfect (If I had the gravity to 25 and had the correct calculation however, the player would move 15 or so pixels into the block before stopping)

Anyone have any good ideas about the horizontal collision?

organburner
10-13-2009, 11:29 AM
Double post, but I thought I'd post the way I got it to work properly.

I went into the player symbol, and created four boxes just barely extruding from the player, called them hitbox and then the direction they were facing (So hitboxbottom, hitboxright hitboxleft etc) and then I made them invisible by turning alpha down to zero.

So then all I had to do was to check for player.hitbox collision and then turn that speed down until there was no collision anymore. It's a crude way to do it, and probably not efficient at all, but I am in a hurry to get this done.

I still need to create the jump function (I just need to make it so that the player doesn't teleport 90 pixels into the air instantly)
There also seems to be some bug where the player will go down into the blocks if they are at a certain height.

Anyway, hitboxes.