Skip to content

Instantly share code, notes, and snippets.

@jonbro
Created December 15, 2013 12:37
Show Gist options
  • Select an option

  • Save jonbro/7972507 to your computer and use it in GitHub Desktop.

Select an option

Save jonbro/7972507 to your computer and use it in GitHub Desktop.
#include "bhPlacement.h"
float BHPlacement::cx;
float BHPlacement::cy;
// lua accessible functions
BHPlacement::BHPlacement(lua_State *l)
{
}
int BHPlacement::AddPiece(lua_State *l)
{
BHRoom *r = new BHRoom();
r->x = luaL_checknumber(l, 1);
r->y = luaL_checknumber(l, 2);
r->w = luaL_checknumber(l, 3);
r->h = luaL_checknumber(l, 4);
lua_pushvalue(l, 5);
// store this stack position in the registry index
r->roomRef = luaL_ref(l, LUA_REGISTRYINDEX);
// store all the edges in the edge table as well
for(int i=0;i<4;i++){
edges.push_back(&r->edges[i]);
r->edges[i].dir = 0;
r->edges[i].owner = r;
}
rooms.push_back(r);
return 0;
}
int BHPlacement::RemovePiece(lua_State *l)
{
//lua_pushvalue(l, 1);
cout << "should be removing room " << endl;
for(int i=edges.size()-1;i>=0;i--){
// retrieve and store room value on stack
lua_rawgeti(l, LUA_REGISTRYINDEX, edges[i]->owner->roomRef);
if(lua_equal(l, -1, -2) == 1){
edges.erase(edges.begin()+i);
cout << "found edge to remove" << endl;
}
// pop the value off the top
lua_pop(l, 1);
}
for(int i=0;i<rooms.size();i++){
lua_rawgeti(l, LUA_REGISTRYINDEX, rooms[i]->roomRef);
if(lua_equal(l, -1, -2) == 1){
luaL_unref(l, LUA_REGISTRYINDEX, rooms[i]->roomRef);
rooms.erase(rooms.begin()+i);
cout << "found room to remove" << endl;
break;
}
lua_pop(l, 1);
}
return 0;
}
bool Overlaps(BHRoom *a, BHRoom *b){
return a->x + a->w > b->x &&
a->x < b->x + b->w &&
a->y + a->h > b->y &&
a->y < b->y + b->h;
}
bool Overlaps(vector<BHRoom*> a, BHRoom *b){
for(int j=0;j<a.size();j++){
if(Overlaps(a[j], b))
return true;
}
}
int BHPlacement::FindPositionForPiece(lua_State *l)
{
// create a block that represents the incoming position
BHRoom *ir = new BHRoom();
ir->x = luaL_checknumber(l, 1);
ir->y = luaL_checknumber(l, 2);
ir->w = luaL_checknumber(l, 3);
ir->h = luaL_checknumber(l, 4);
buildEdgePositions(ir);
// now that the edges have been built and sorted, time to loop through them
bool foundPosition = false;
BHRoom *parent;
for(int i=0;i<edges.size();i++){
BHEdge *v = edges[i];
ir->x = v->px;
ir->y = v->py;
parent = v->owner;
// break;
// check with each room to see if the new ghost block overlaps
bool foundOverlap = false;
for(int j=0;j<rooms.size();j++){
// if this new position (based on the edge)
// overlaps, then we want to fudge it around a bit
if(Overlaps(rooms[j], ir)){
foundOverlap = true;
BHRoom *a = rooms[j];
// do the north south direction first
if(v->dir == 0 || v->dir == 1){
float ox = ir->x;
// push off room that we are overlapping
if(a->x < ir->x)
ir->x = fmin(ir->x+ir->w/4, a->x+ir->w);
else
ir->x = fmax(ir->x-ir->w/4, a->x-ir->w);
// check to see if we are still adjacent to edge, and make sure we aren't overlapping
if(ir->x >= v->owner->x-ir->w &&
ir->x <= v->owner->x + v->owner->w &&
!Overlaps(rooms, ir))
{
foundPosition = true;
}else{
ir->x = ox;
}
}else{
float oy = ir->y;
// push off room that we are overlapping
if(a->y < ir->y)
ir->y = fmin(ir->y+ir->h/4, a->y+ir->h);
else
ir->y = fmax(ir->y-ir->h/4, a->y-ir->h);
// check to see if we are still adjacent to edge, and make sure we aren't overlapping
if(ir->y >= v->owner->y-ir->h &&
ir->y <= v->owner->y + v->owner->h &&
!Overlaps(rooms, ir))
{
foundPosition = true;
}else{
ir->y = oy;
}
}
// not sure if it should check every possible overlap to see if it
// can be fudged or not. Might should break after failing at the first one
}
}
if(foundPosition || !foundOverlap){
cout << "checked " << i << endl;
break;
}
}
// return the x,y positions of the new block, and the parent that we found
lua_pushnumber(l, ir->x);
lua_pushnumber(l, ir->y);
lua_rawgeti(l, LUA_REGISTRYINDEX, parent->roomRef);
return 3;
}
// just declare up front so we save some memory thrashing
float aex, aey, bex, bey, ad, bd;
bool BHPlacement::edgeSort(BHEdge *a, BHEdge *b)
{
aex = a->ex;
aey = a->ey;
bex = b->ex;
bey = b->ey;
ad = distSQ(cx, cy, a->ex, a->ey);
bd = distSQ(cx, cy, b->ex, b->ey);
// if everything is equal, then we do some operation to everything
// called fixpoint in the original code.
// it compresses the edges by one on each side,
// so nothing should be at an overlapping position anymore
// I wonder if I could do this when generating the edges in the first place
// also only the "e" part of the edge is used for meausring distances
// the "p" part doesn't need to be set until the ghost block is being placed
if(ad == bd){
// fix a points
if(a->dir == 0 || a->dir == 1){
if(aex < a->owner->y + a->owner->w/2)
aex++;
else
aex--;
}else{
if(aey<a->owner->y+a->owner->h/2)
aey++;
else
aey--;
}
if(b->dir == 0 || b->dir == 1){
if(bex< b->owner->y+b->owner->w/2)
bex++;
else
bex--;
}else{
if(bey < b->owner->y+b->owner->h/2)
bey++;
else
bey--;
}
return distSQ(cx, cy, a->ex, a->ey) < distSQ(cx, cy, b->ex, b->ey);
}
return ad < bd;
}
void BHPlacement::buildEdgePositions(BHRoom *incomingr)
{
cx = incomingr->x + incomingr->w/2.0f;
cy = incomingr->y + incomingr->h/2.0f;
for(int i=0;i<rooms.size();i++){
BHRoom *r = rooms[i];
BHEdge *n = &r->edges[0];
BHEdge *s = &r->edges[1];
BHEdge *e = &r->edges[2];
BHEdge *w = &r->edges[3];
n->px = fmax(fmin(incomingr->x, r->x+r->w), r->x-incomingr->w);
n->py = r->y-incomingr->h;
n->ex = fmax(fmin(cx, r->x+r->w), r->x);
n->ey = r->y;
s->px = fmax(fmin(incomingr->x, r->x+r->w), r->x-incomingr->w);
// doesn't need recalc;
s->py = r->y+r->h;
s->ex = fmax(fmin(cx, r->x+r->w), r->x);
s->ey = r->y+r->h;
e->px = r->x-incomingr->w;
e->py = fmax(fmin(incomingr->y, r->y+r->h), r->y-incomingr->h);
e->ex = r->x;
e->ey = fmax(fmin(cy, r->y+r->h),r->y);
w->px = r->x+r->w;
w->py = fmax(fmin(incomingr->y, r->y+r->h), r->y-incomingr->h);
w->ex = r->x+r->w;
w->ey = fmax(fmin(cy, r->y+r->h),r->y);
}
// sort the edges
sort(edges.begin(), edges.end(), BHPlacement::edgeSort);
}
const char BHPlacement::className[] = "BHPlacement";
Lunar<BHPlacement>::RegType BHPlacement::methods[] = {
method(BHPlacement, AddPiece),
method(BHPlacement, RemovePiece),
method(BHPlacement, FindPositionForPiece),
{0,0}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment