Hi there,
I’m asking for help with 2D collision detection, because my code is getting quite large and I’m wondering if I’m doing this the right way.
I’m making an action adventure top-down game and have 2D collision working (although still a bit buggy) for simple rectangles with a hotwidth and hotheight as large as or smaller than one tile and they can only move up and down, just like the (S)NES zelda games.
I want to expand it to entities with a hotwidth and hotheight larger than one tile, but have the feeling the only way I can come up with will cost me too much processing power.
So I’m already running into processing problems even before I can start experimenting with rotation and polygons (in case I want to make an even cooler game).
Just to give you an example how large this has become (I find it quite large for a simple function),
below is my function of putting an Entity on the map.
onp are the tiles the entity might collide on.
z is the layer
public function move(nwX:int, nwY:int, z:int = 0):void {
var m:Map = (parent as Map);
var o:Array;
var ts:uint = tileSize;
var i:uint;
var j:uint;
var hw:uint = hotwidth;
var hh:uint = hotheight;
var hx:uint = hotx;
var hy:uint = hoty;
var w:uint = Math.ceil((hw - hx) / ts);
var h:uint = Math.ceil((hh - hy) / ts);
o = new Array();
i = 0;
while (i++ < w) {
j = 0;
while (j++ < h) {
o.push(new Point3D(nwX + i - 1, nwY + j - 1, z));
m.hasEnt[x][y][z].push(id);
}
}
ox = (ts - hw - hx) / 2;
oy = (ts - hh - hy) / 2;
x = ts * nwX + ox;
y = ts * nwY + oy;
onp = o.slice();
}
Here’s my collision detection code.
I’ll show the big picture first:
private function processEntities():void {
for(var i:String in ents) {
ents*.direct();
}
for(i in ents) {
if(ents*.isColliding()) {
ents*.collide();
}
}
for(i in ents) {
ents*.step();
}
}
collision detection code.
public function cd():Array {
var m:Map = (parent as Map);
var hasEnt:Array = m.hasEnt;
var obs:Array = m.obs;
var ents:Array = m.ents;
var eid:uint;
var i:String, j:String, n:String;
var nx:int, ny:int, nz:int;
for(i in onp) {
nx = onp*.x;
ny = onp*.y;
nz = onp*.z;
if(obs[nx][ny][nz]) {
coll.push(-1);
}
if (hasEnt[nx][ny][nz].length > 1) {
for(j in hasEnt[nx][ny][nz]){
eid = hasEnt[nx][ny][nz][j];
if (eid != id) {
for (n in ents) {
if (ents[n].getId() == eid) {
if (cdEnt(ents[n])) {
if(coll.indexOf(eid)==-1) {
coll.push(eid);
}
}
}
}
}
}
}
}
return coll;
}
public function cdEnt(ent:Entity):Boolean {
var nx:Number = x + hotx + vx;
var ny:Number = y + hoty + vy;
var rnx:Number = nx + hotwidth;
var dny:Number = ny + hotheight;
var enx:Number = ent.x + ent.hotx + ent.vx;
var eny:Number = ent.y + ent.hoty + ent.vy;
var enxr:Number = enx + ent.hotwidth;
var enyd:Number = eny + ent.hotheight;
if(enxr<=nx) return false;
if(enyd<=ny) return false;
if(enx>=rnx) return false;
if(eny>=dny) return false;
return true;
}
Now here’s my problem,
I have two functions called OffTiling and Ontiling. Offtiling is called after the entity has done it’s “move” (not to confuse with the move function I called this function step).
Ontiling is called as soon as the entity knows it’s velocity.
Here’s my Ontiling code:
public function onTiling():void {
var ts:uint = tileSize;
var o:Array = onp;
if (vx > 0) {
var oxr:Number = ox + hotx + hotwidth;
if (oxr > ts) oxr -= ts;
if (oxr + vx > ts) {
onTile(new Point3D(o[0].x + 1, o[0].y, 0));
}
}
else if (vx < 0) {
if (ox + vx < 0) {
onTile(new Point3D(o[0].x - 1, o[0].y, 0));
}
}
if (vy > 0) {
var oyd:Number = oy + hoty + hotheight;
if (oyd > ts) oyd -= ts;
if (oyd + vy > ts) {
onTile(new Point3D(o[0].x, o[0].y + 1, 0));
}
}
else if (vy < 0) {
if (oy + vy < 0) {
onTile(new Point3D(o[0].x, o[0].y - 1, 0));
}
}
}
As you can see, it only looks at the first point. This is fine dealing with any entity smaller than one tile, but this won’t work on larger entities and so I’m looking for the best way to solve this.
So here are my questions:
Question 1. Is this the right approach for 2D collision detection?
Question 2a. Is it right to use an Array of offsets, one offset for every tile the entity is on in order to determine the new tiles the entity might collide on?
Question 2b. If no, what is the best approach?