#include "Layer.h" #include #include #include #include "Object.h" #include "Bugsy.h" using namespace std; using namespace wgd; const float Layer::LEDGE_HEIGHT = 0.5f; Layer::Layer(const wgd::OID& oid) : Instance2D(oid) { lines = new Drawable(); } Layer::Layer(Level *level, int width, int height, float top, float alpha) : top(top), alpha(alpha) { //A doste thing - set the type of this object. set(ix::type, type()); lines = new Drawable(); this->level = level; //Create arrays tileData = new TileType[width * height]; heightData = new int[width * height]; waterData = new float[width * height]; //Debugging vars dbgTileMap = new Sprite2D*[width * height]; dbgMaxHeight = 0.0f; //Hard-coded layer data memset(tileData, 0, sizeof(int) * width * height); memset(heightData, 0, sizeof(int) * width * height); memset(waterData, -1, sizeof(float) * width * height); //Create cliff in centre of level for(int x=4; x<=6; x++) for(int y=4; y<=6; y++) { int i = (y * height) + x; heightData[i] = 2; tileData[i] = TILE_MUD; } for(int y=2; y<=6; y++) { int i = (y * height); heightData[i] = 2; } for(int y=2; y<=4; y++) { int i = (y * height) + 1; heightData[i] = 1; } heightData[(6 * height) + 1] = 1; tileData[(5 * height) + 1] = TILE_MUD; for(int y=4; y<=6; y++) tileData[(y * height) + 2] = TILE_MUD; //Create pool/river for(int y=0; y<=7; y++) heightData[(y * height) + 5] = 1; for(int x=0; x<=5; x++) heightData[(8 * height) + x] = 1; for(int x=0; x<=4; x++) for(int y=0; y<=7; y++) { if (heightData[(y * height) + x] ==0) waterData[(y * height) + x] = 1.0f; } //Small deep pond for(int x=6; x<=8; x++) for(int y=0; y<=2; y++) if (x == 7 && y == 1) waterData[(y * height) + x] = 2.0f; else heightData[(y * height) + x] = 2; //Passages heightData[(8 * height) + 3] = 0; heightData[(3 * height) + 5] = 0; static bool layerNum = 0; if (!layerNum) { //Create rock ::Object* rock = new ::Object(new Sprite("objects/rock.png"), this, vector3d(0.4f, 2.0f, 0.4f)); Bugsy::getScene().set("rock", rock); rock->pos(vector3d(8, 0, 9)); } else { //Create rocks ::Object* rock; if (layerNum == 1) { rock = new ::Object(new Sprite("objects/rock.png"), this, vector3d(0.4f, 2.0f, 0.4f)); Bugsy::getScene().set("rock1", rock); rock->pos(vector3d(2, 0, 3)); rock = new ::Object(new Sprite("objects/rock.png"), this, vector3d(0.4f, 2.0f, 0.4f)); Bugsy::getScene().set("rock2", rock); rock->pos(vector3d(5, 0, 8)); } else { rock = new ::Object(new Sprite("objects/rock.png"), this, vector3d(0.4f, 2.0f, 0.4f)); Bugsy::getScene().set("rock3", rock); rock->pos(vector3d(8, 0, 4)); } //Ground for(int i=0; iflags &= ~LIGHTING; lines->flags &= ~DEPTH_TEST; lines->mode = GL_LINES; lines->clearData = false; lines->discard = false; } void Layer::clearTiles(int x, int y, int width, int height) { for(int i=0; igetLevelWidth()) + x + i].clear(); } void Layer::makeTiles(int _x, int _y, int width, int height) { //Remove old tiles in this area, if any exist if (tiles.size()) { clearTiles(_x, _y, width, height); } //Generate Layer from data Sprite2D* tile; vector2d h(32.0f, 16.0f), v(-32.0f, 16.0f), layerPos(0, top); colour tint(1.0f,1.0f,1.0f, alpha); float posX, posY; for(int y=_y; y<_y+height; y++) { for(int x=_x; x<_x+width; x++) { int i = (y * height) + x; //'i' is the index of this tile in a 1D array, such as 'tileData' or 'heightData' TileType tt = tileData[i]; float depth = (float)(x + y + (heightData[i] * LEDGE_HEIGHT)) * -0.1f; //Create tile tile = new Sprite2D(); tile->sprite(Level::getTileSprite(tt, SIDE_TOP)); posX = x - (heightData[i] * LEDGE_HEIGHT); posY = y - (heightData[i] * LEDGE_HEIGHT); tile->position((h * posX) + (v * posY) + layerPos); tile->depth(depth); tile->size(64.0f, 32.0f); tile->colour(tint); tiles[i].push_back(tile); dbgTileMap[i] = (x%2 + y%2 == 0) ? tile : NULL; dbgMaxHeight = heightData[i] > dbgMaxHeight ? heightData[i] : dbgMaxHeight; //Check tile sides //The 'left' side (the tile we get if we increment the tile's y co-ordinate) if (y < height-1 && heightData[i + height] < heightData[i]) { int heightDiff = heightData[i] - heightData[i + height]; //Add an edge tile. Clone the previous tile, and change its sprite. for(int n=1; n<=heightDiff; n++) { vector2d pos = (h * posX) + (v * posY); pos.y += 16.0f * n; tile = new Sprite2D(); tile->sprite(Level::getTileSprite(tt, SIDE_LEFT)); tile->depth(depth - 0.05f); tile->position(pos + layerPos); tile->size(64.0f, 32.0f); tile->colour(tint); tiles[i].push_back(tile); } } //The 'right' side (the tile we get if we increment the tile's x co-ordinate) if (x < width-1 && heightData[i + 1] < heightData[i]) { int heightDiff = heightData[i] - heightData[i + 1]; //Add an edge tile. Clone the previous tile, and change its sprite. for(int n=1; n<=heightDiff; n++) { vector2d pos = (h * posX) + (v * posY); pos.y += 16.0f * n; tile = new Sprite2D(); tile->sprite(Level::getTileSprite(tt, SIDE_RIGHT)); tile->depth(depth - 0.05f); tile->position(pos + layerPos); tile->size(64.0f, 32.0f); tile->colour(tint); tiles[i].push_back(tile); } } //Water Tiles if (waterData[i] > heightData[i]) { //Add a water tile vector2d pos = (h * posX) + (v * posY); pos.y += -10.0f * (waterData[i] - heightData[i]); tile = new Sprite2D(); tile->sprite(Level::getTileSprite(TILE_WATER, SIDE_TOP)); tile->depth(depth - 0.05f); tile->position(pos + layerPos); tile->size(64.0f, 32.0f); tile->colour(tint); tiles[i].push_back(tile); } } } DebugVertex vertex; float hw, hh, col; hw = 10.0f; hh = 10.0f; float scale = 50.0f; vector2d offset = vector2d(scale * 5, scale * 5); lines->deleteData(); for(float x=0; x<10; x++) for(float y=0; y<10; y++) { col = heightData[(int)((y*10)+x)] * (1.0f / dbgMaxHeight); vertex.colour = colour(col, 0.0f, 1.0f - col); vertex.position = vector2d(x * scale + 2, y * scale + 2) - offset; lines->add(vertex); vertex.position = vector2d((x + 1) * scale - 2, y * scale + 2) - offset; lines->add(vertex); vertex.position = vector2d((x + 1) * scale - 2, y * scale + 2) - offset; lines->add(vertex); vertex.position = vector2d((x + 1) * scale - 2, (y + 1) * scale - 2) - offset; lines->add(vertex); vertex.position = vector2d((x + 1) * scale - 2, (y + 1) * scale - 2) - offset; lines->add(vertex); vertex.position = vector2d(x * scale + 2, (y + 1) * scale - 2) - offset; lines->add(vertex); vertex.position = vector2d(x * scale + 2, (y + 1) * scale - 2) - offset; lines->add(vertex); vertex.position = vector2d(x * scale + 2, y * scale + 2) - offset; lines->add(vertex); } refreshRequired = false; } Layer::~Layer() { if (tileData) delete[] tileData; if (heightData) delete[] heightData; if (waterData) delete[] waterData; } void Layer::addObject(::Object* obj) { //Check object doesn't belong to layer already for(unsigned int i=0; ilayer()) obj->layer()->removeObject(obj); //Add object objects.push_back(obj); obj->layer(this); } void Layer::removeObject(::Object* obj) { for(unsigned int i=0; ilayer(NULL); //Remove from layer if (i < objects.size() - 1) objects[i] = objects[objects.size() - 1]; objects.pop_back(); } } void Layer::draw(wgd::SceneGraph& graph, wgd::Camera2D* camera) { list::iterator iter; for(unsigned int i=0; itiles.size(); i++) { for(iter=tiles[i].begin(); iter!=tiles[i].end(); iter++) { Drawable *d = (*iter)->drawable(); d->flags |= ALPHA_TEST; graph.addSolid(d); } } if (Bugsy::debugRender() && level->getCurLayer() == this) { graph.addAlpha(lines); graph.addAlpha(Bugsy::lines); } } void Layer::update(float timeStep) { //printf("%f - %d objects\n", timeStep, objects.size()); if (refreshRequired) makeTiles(refX, refY, refW, refH); for(unsigned int i=0; iupdate(timeStep); //Colisions for objects vector3d overlap; for(unsigned int i=0; igetMoveable() || objects[j]->getMoveable()) && ::Object::checkCollision(objects[i], objects[j])) { //Find object centres vector3d centre1 = objects[i]->pos() + vector3d(0, objects[i]->size().y * 0.5f, 0); vector3d centre2 = objects[j]->pos() + vector3d(0, objects[j]->size().y * 0.5f, 0); //Calculate size of intersection/overlap vector3d distBtwnCentres = centre2 - centre1; vector3d absoluteDist(abs(distBtwnCentres.x), abs(distBtwnCentres.y), abs(distBtwnCentres.z)); vector3d maxAllowableDist = (objects[i]->size() + objects[j]->size()) * 0.5f; vector3d absoluteOverlap = maxAllowableDist - absoluteDist; if (!(absoluteDist.x && absoluteDist.y && absoluteDist.z)) continue; //Find collision normal (the axis along which the overlap is smallest) const float* ao = absoluteOverlap.getArray(), *md = maxAllowableDist.getArray(); int minAxis = 0; for(int k=1; k<3; k++) if (ao[k] / md[k] < ao[minAxis] / md[minAxis]) minAxis = k; //Work out how far we must move object along this axis in order to resolve the collision float offsetDist; offsetDist = distBtwnCentres.getArray()[minAxis]; //First, get current distance between objects offsetDist = -offsetDist / abs(offsetDist); //Normalise, and negate offsetDist *= ao[minAxis]; //Scale by the size of the overlap //Construct offset vector float offsetAxes[3] = {0.0f, 0.0f, 0.0f}; offsetAxes[minAxis] = offsetDist; vector3d offset(offsetAxes); //Resolve collision if (objects[i]->getMoveable() && objects[j]->getMoveable()) { //Move both objects, by half the size of the overlap objects[i]->pos(objects[i]->pos() + (offset * 0.5f)); objects[j]->pos(objects[j]->pos() - (offset * 0.5f)); } else { //Move one of the objects the whole distance if (objects[i]->getMoveable()) objects[i]->pos(objects[i]->pos() + offset); else objects[j]->pos(objects[j]->pos() - offset); } } } } float Layer::getTop() { return top; } float Layer::getAlpha() { return alpha; } void Layer::setTop(float newTop) { if (top != newTop) { vector2d dPos(0, newTop - top); list::iterator iter; for(unsigned int i=0; iposition((*iter)->position() + dPos); top = newTop; //Update object positions for(unsigned int i=0; ipos(objects[i]->pos()); } } void Layer::setAlpha(float newAlpha) { if (alpha != newAlpha) { list::iterator iter; for(unsigned int i=0; icolour(colour(1,1,1, newAlpha)); alpha = newAlpha; } } int Layer::getHeight(int x, int y) { return heightData[(y * level->getLevelWidth()) + x]; } int Layer::getHeight(const wgd::vector3d& pos) { return getHeight((int)pos.x, (int)pos.z); } float Layer::getWaterHeight(int x, int y) { return waterData[(y * level->getLevelWidth()) + x]; } float Layer::getWaterHeight(const wgd::vector3d& pos) { return getWaterHeight((int)pos.x, (int)pos.z); } bool Layer::isWaterAboveTile(int x, int y) { return getWaterHeight(x, y) >= getHeight(x, y); } bool Layer::isWaterAboveTile(const wgd::vector3d& pos) { return isWaterAboveTile((int)pos.x, (int)pos.z); } TileType Layer::getTileType(int x, int y) { return tileData[(y * level->getLevelWidth()) + x]; } void Layer::setHeight(int x, int y, int height) { heightData[(y * level->getLevelWidth()) + x] = height; markForRefresh(x, y, 1, 1); } void Layer::changeHeight(int x, int y, int deltaHeight) { heightData[(y * level->getLevelWidth()) + x] += deltaHeight; markForRefresh(x, y, 1, 1); } void Layer::markForRefresh(int x, int y, int width, int height) { if (!refreshRequired) { refreshRequired = true; refX = x; refY = y; refW = width; refH = height; } else { if (refX > x) { refW += refX - x; refX = x; } if (refY > y) { refH += refY - y; refY = y; } if (refX + refW < x + width) refW = (x + width) - refX; if (refY + refH < y + height) refH = (y + height) - refY; } }