#include "parameters.h" #include "level.h" #include "player.h" #include #include #include "AzurShaders.h" #include #include "utilities.h" #include #include #include "player.h" #define TILESIZE 16 extern struct Map map_level0; extern struct Map map_level1; extern struct Map map_level2; extern struct Map map_level3; extern struct Map map_level4; extern struct Map map_level5; extern bool drawbackground; extern bool drawforeground; extern bool drawnormals; extern bool drawborders; extern bool textbacktile; extern bool textforetile; extern uint16_t tilecolor; extern uint16_t backcolor; extern std::vector MyLevelBorders; extern Player MyPlayer; struct Map *map_level; int tileXmin, tileXmax; int tileYmin, tileYmax; int XinTile, YinTile; extern bopti_image_t img_selected; Level::Level() { map_level = &map_level0; this->UpdateDataMap(); } Level::~Level() {} void Level::ChangeMap(int level) { if (level == 0) map_level = &map_level0; else if (level == 1) map_level = &map_level1; else if (level == 2) map_level = &map_level2; else if (level == 3) map_level = &map_level3; else if (level == 4) map_level = &map_level4; else if (level == 5) map_level = &map_level5; else map_level = &map_level0; this->UpdateDataMap(); } void Level::UpdateDataMap(void) { for (int i = 0; i < map_level->w; i++) { for (int j = 0; j < map_level->h; j++) { uint16_t index = j * map_level->w + i; uint16_t currentTile = map_level->layers[1][index]; if (currentTile == 31) { MyPlayer.currx = ((float)(i + 0.5f)) * 16.0f; MyPlayer.curry = ((float)(j + 0.5f)) * 16.0f; MyPlayer.vx = 0; MyPlayer.vy = 0; MyPlayer.Update(0); } } } } void Level::Render(void) { for (int u = !drawbackground; u < map_level->nblayers - !drawforeground; u++) { for (int i = 0; i < map_level->w; i++) { for (int j = 0; j < map_level->h; j++) { uint16_t index = j * map_level->w + i; int16_t currentTile = map_level->layers[u][index]; if (currentTile != -1) { uint16_t xtile = (currentTile % map_level->tileset_size) * 16; uint16_t ytile = (currentTile / map_level->tileset_size) * 16; if (u == 0) azrp_subimage_rgb16_dye(i * 16, j * 16, map_level->tileset, xtile, ytile, 16, 16, IMAGE_DYE | IMAGE_NOCLIP_INPUT, tilecolor); else azrp_subimage_rgb16(i * 16, j * 16, map_level->tileset, xtile, ytile, 16, 16, DIMAGE_NONE | IMAGE_NOCLIP_INPUT); #if (DEBUG_MODE) if (textbacktile) azrp_draw_text(i * 16, j * 16, "%d", GetTileBackgroundINT(i, j)); if (textforetile) azrp_draw_text(i * 16 + 8, j * 16 + 8, "%d", GetTileForegroundINT(i, j)); #endif } } } } #if (DEBUG_MODE) if (drawborders) for (unsigned int i = 0; i < MyLevelBorders.size(); i++) azrp_line((int)MyLevelBorders[i]->A.x, (int)MyLevelBorders[i]->A.y, (int)MyLevelBorders[i]->B.x, (int)MyLevelBorders[i]->B.y, MyLevelBorders[i]->color); if (drawnormals) for (unsigned int i = 0; i < MyLevelBorders.size(); i++) azrp_line( ((int)MyLevelBorders[i]->A.x + (int)MyLevelBorders[i]->B.x) / 2, ((int)MyLevelBorders[i]->A.y + (int)MyLevelBorders[i]->B.y) / 2, ((int)MyLevelBorders[i]->A.x + (int)MyLevelBorders[i]->B.x) / 2 + (int)MyLevelBorders[i]->N.x / 2, ((int)MyLevelBorders[i]->A.y + (int)MyLevelBorders[i]->B.y) / 2 + (int)MyLevelBorders[i]->N.y / 2, C_BLUE); #endif } void Level::Update(float dt) { UpdateBorders(); } /*RETURN the type of tile located in the background for the point x, y using * player coordinates (x=[0..25], y=[0..14]) */ /*the x and y correspond to hte integer part of MyPlayer.x and MyPlayer.y*/ int Level::GetTileBackgroundINT(uint8_t x, uint8_t y) { uint16_t index = y * map_level->w + x; uint16_t currentTile = map_level->layers[0][index]; return currentTile; } /*RETURN the type of tile located in the foreground for the point x, y using * player coordinates (x=[0..25], y=[0..14]) */ /*the x and y correspond to hte integer part of MyPlayer.x and MyPlayer.y*/ int Level::GetTileForegroundINT(uint8_t x, uint8_t y) { uint16_t index = y * map_level->w + x; uint16_t currentTile = map_level->layers[1][index]; return currentTile; } /*RETURN the type of tile located in the background for the point x, y using * screen coordinates (x=[0..396], y=[0..223]) */ int Level::GetTileBackground(uint16_t x, uint16_t y) { uint8_t tileX = x >> 4; uint8_t tileY = y >> 4; uint16_t index = tileY * map_level->w + tileX; uint16_t currentTile = map_level->layers[0][index]; return currentTile; } /*RETURN the type of tile located in the foreground for the point x, y using * screen coordinates (x=[0..396], y=[0..223]) */ int Level::GetTileForeground(uint16_t x, uint16_t y) { uint8_t tileX = x >> 4; uint8_t tileY = y >> 4; uint16_t index = tileY * map_level->w + tileX; uint16_t currentTile = map_level->layers[1][index]; return currentTile; } // Compute the intersection Point between segments [AB] and [CD] // if there is an intersection, return true and store the result into Point R bool CollisionSegSeg(Vector2D A, Vector2D B, Vector2D N, Vector2D C, Vector2D D, Vector2D *R) { Vector2D I = B - A; Vector2D J = D - C; libnum::num32 det = I.Det(J); if (det == 0) return false; // the segments are parallel libnum::num32 m = (I.Det(A) - I.Det(C)) / det; libnum::num32 k = (J.Det(A) - J.Det(C)) / det; if ((m >= libnum::num32(0) && m <= libnum::num32(1) && k >= libnum::num32(0) && k <= libnum::num32(1))) { if (J.Dot(N) >= libnum::num32(0)) return false; else { //(*R).x = C.x + k*J.x; //(*R).y = C.y + k*J.y; *R = C + k * J; return true; } } else return false; // intersection of the lines, but not of the segments } libnum::num32 ClosestPointOnSegment(Vector2D A, Vector2D B, Vector2D P, Vector2D *R) { Vector2D AB = B - A; libnum::num32 t = AB.Dot(AB); if (t == 0) { *R = A; return t; } libnum::num32 t2 = (P.Dot(AB) - A.Dot(AB)) / t; if (t2 < libnum::num32(0)) t2 = libnum::num32(0); if (t2 > libnum::num32(1)) t2 = libnum::num32(1); *R = A; (*R).Add(AB, t2); return t2; } /*RETURN true if the player can go in the target position*/ bool Level::CanGo(void) { Vector2D PlayerOrigin, PlayerTarget; PlayerOrigin.x = MyPlayer.currx; PlayerOrigin.y = MyPlayer.curry; PlayerTarget.x = MyPlayer.nextx; PlayerTarget.y = MyPlayer.nexty; if (PlayerTarget.x == PlayerOrigin.x && PlayerTarget.y == PlayerOrigin.y) return true; // velocity is 0 so Player.next = Player.Curr so we can stay // here, that's obvious if (MyLevelBorders.size() == 0) return true; // there is no surrounding border so no need to check if there // are collisions (also obvious) for (unsigned int i = 0; i < MyLevelBorders.size(); i++) { Vector2D I; // Detection de collision entre [A,B] et [Player.Curr, Player.Next] if (CollisionSegSeg(MyLevelBorders[i]->A, MyLevelBorders[i]->B, MyLevelBorders[i]->N, PlayerOrigin, PlayerTarget, &I)) { MyLevelBorders[i]->color = C_RED; MyPlayer.nextx = I.x; MyPlayer.nexty = I.y; MyPlayer.vx = libnum::num32(0); MyPlayer.vy = libnum::num32(0); return false; } } return true; } Border *Level::MakeBorder(libnum::num32 DX, libnum::num32 DY, libnum::num32 x1, libnum::num32 y1, libnum::num32 x2, libnum::num32 y2) { Border *Bord = new Border(); Bord->A.x = DX + libnum::num(15) * x1; Bord->A.y = DY + libnum::num(15) * y1; Bord->B.x = DX + libnum::num(15) * x2; Bord->B.y = DY + libnum::num(15) * y2; Bord->N.x = Bord->A.y - Bord->B.y; Bord->N.y = Bord->B.x - Bord->A.x; Bord->color = C_GREEN; return Bord; } void Level::ConvertTileToBorder(int16_t currentTile, libnum::num32 DeltaX, libnum::num32 DeltaY) { Border *B1; switch (currentTile) { case -1: break; // Empty background case 0: break; // No borders (filling tile) case 1: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(0), libnum::num32(0), libnum::num32(1)); MyLevelBorders.push_back(B1); B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(1), libnum::num32(1), libnum::num32(1)); MyLevelBorders.push_back(B1); B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(1), libnum::num32(1), libnum::num32(0)); MyLevelBorders.push_back(B1); B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(0), libnum::num32(0), libnum::num32(0)); MyLevelBorders.push_back(B1); break; // 45° diagonals case 2: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(1), libnum::num32(1), libnum::num32(0)); MyLevelBorders.push_back(B1); break; case 3: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(0), libnum::num32(1), libnum::num32(1)); MyLevelBorders.push_back(B1); break; case 12: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(1), libnum::num32(0), libnum::num32(0)); MyLevelBorders.push_back(B1); break; case 13: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(0), libnum::num32(0), libnum::num32(1)); MyLevelBorders.push_back(B1); break; // 22.5° diagonals case 4: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(1), libnum::num32(1), libnum::num32(1) / libnum::num32(2)); MyLevelBorders.push_back(B1); break; case 5: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(1) / libnum::num32(2), libnum::num32(1), libnum::num32(0)); MyLevelBorders.push_back(B1); break; case 6: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(0), libnum::num32(1), libnum::num32(1) / libnum::num32(2)); MyLevelBorders.push_back(B1); break; case 7: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(1) / libnum::num32(2), libnum::num32(1), libnum::num32(1)); MyLevelBorders.push_back(B1); break; case 14: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(1) / libnum::num32(2), libnum::num32(0), libnum::num32(0)); MyLevelBorders.push_back(B1); break; case 15: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(1), libnum::num32(0), libnum::num32(1) / libnum::num32(2)); MyLevelBorders.push_back(B1); break; case 16: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(1) / libnum::num32(2), libnum::num32(0), libnum::num32(1)); MyLevelBorders.push_back(B1); break; case 17: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(0), libnum::num32(0), libnum::num32(1) / libnum::num32(2)); MyLevelBorders.push_back(B1); break; // 67.5° Diagonals case 24: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1) / libnum::num32(2), libnum::num32(1), libnum::num32(1), libnum::num32(0)); MyLevelBorders.push_back(B1); break; case 34: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(1), libnum::num32(1) / libnum::num32(2), libnum::num32(0)); MyLevelBorders.push_back(B1); break; case 25: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(0), libnum::num32(1) / libnum::num32(2), libnum::num32(1)); MyLevelBorders.push_back(B1); break; case 35: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1) / libnum::num32(2), libnum::num32(0), libnum::num32(1), libnum::num32(1)); MyLevelBorders.push_back(B1); break; case 26: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1) / libnum::num32(2), libnum::num32(1), libnum::num32(0), libnum::num32(0)); MyLevelBorders.push_back(B1); break; case 36: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(1), libnum::num32(1) / libnum::num32(2), libnum::num32(0)); MyLevelBorders.push_back(B1); break; case 27: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(0), libnum::num32(1) / libnum::num32(2), libnum::num32(1)); MyLevelBorders.push_back(B1); break; case 37: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1) / libnum::num32(2), libnum::num32(0), libnum::num32(0), libnum::num32(1)); MyLevelBorders.push_back(B1); break; // Blocks with 3 sides case 8: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(1), libnum::num32(1), libnum::num32(1)); MyLevelBorders.push_back(B1); B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(1), libnum::num32(1), libnum::num32(0)); MyLevelBorders.push_back(B1); B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(0), libnum::num32(0), libnum::num32(0)); MyLevelBorders.push_back(B1); break; case 9: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(0), libnum::num32(0), libnum::num32(1)); MyLevelBorders.push_back(B1); B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(1), libnum::num32(1), libnum::num32(0)); MyLevelBorders.push_back(B1); B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(0), libnum::num32(0), libnum::num32(0)); MyLevelBorders.push_back(B1); break; case 18: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(0), libnum::num32(0), libnum::num32(1)); MyLevelBorders.push_back(B1); B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(1), libnum::num32(1), libnum::num32(1)); MyLevelBorders.push_back(B1); B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(1), libnum::num32(1), libnum::num32(0)); MyLevelBorders.push_back(B1); break; case 19: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(0), libnum::num32(0), libnum::num32(1)); MyLevelBorders.push_back(B1); B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(1), libnum::num32(1), libnum::num32(1)); MyLevelBorders.push_back(B1); B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(0), libnum::num32(0), libnum::num32(0)); MyLevelBorders.push_back(B1); break; // Blocks with 2 sides case 28: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(1), libnum::num32(1), libnum::num32(1)); MyLevelBorders.push_back(B1); B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(0), libnum::num32(0), libnum::num32(0)); MyLevelBorders.push_back(B1); break; case 29: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(0), libnum::num32(0), libnum::num32(1)); MyLevelBorders.push_back(B1); B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(1), libnum::num32(1), libnum::num32(0)); MyLevelBorders.push_back(B1); break; case 38: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(0), libnum::num32(0), libnum::num32(1)); MyLevelBorders.push_back(B1); B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(0), libnum::num32(0), libnum::num32(0)); MyLevelBorders.push_back(B1); break; case 39: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(1), libnum::num32(1), libnum::num32(0)); MyLevelBorders.push_back(B1); B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(0), libnum::num32(0), libnum::num32(0)); MyLevelBorders.push_back(B1); break; case 48: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(0), libnum::num32(0), libnum::num32(1)); MyLevelBorders.push_back(B1); B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(1), libnum::num32(1), libnum::num32(1)); MyLevelBorders.push_back(B1); break; case 49: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(1), libnum::num32(1), libnum::num32(1)); MyLevelBorders.push_back(B1); B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(1), libnum::num32(1), libnum::num32(0)); MyLevelBorders.push_back(B1); break; // Blocks with one single side case 10: case 44: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(0), libnum::num32(0), libnum::num32(0)); MyLevelBorders.push_back(B1); break; case 11: case 46: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(1), libnum::num32(1), libnum::num32(1)); MyLevelBorders.push_back(B1); break; case 20: case 47: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(0), libnum::num32(0), libnum::num32(0), libnum::num32(1)); MyLevelBorders.push_back(B1); break; case 21: case 45: B1 = MakeBorder(DeltaX, DeltaY, libnum::num32(1), libnum::num32(1), libnum::num32(1), libnum::num32(0)); MyLevelBorders.push_back(B1); break; default: break; } } void Level::UpdateBorders(void) { for (unsigned int i = 0; i < MyLevelBorders.size(); i++) delete MyLevelBorders[i]; MyLevelBorders.clear(); uint16_t xp = MyPlayer.tileX; uint16_t yp = MyPlayer.tileY; uint16_t xmin = max(xp - 1, 0); uint16_t xmax = min(xp + 1, map_level->w - 1); uint16_t ymin = max(yp - 1, 0); uint16_t ymax = min(yp + 1, map_level->h - 1); // for( int i=10; iw; i++) for (int i = xmin; i <= xmax; i++) { // for( int j=10; jh; j++) for (int j = ymin; j <= ymax; j++) { uint16_t index = j * map_level->w + i; int16_t currentTile = map_level->layers[0][index]; libnum::num DeltaX = libnum::num(i * 16); libnum::num DeltaY = libnum::num(j * 16); ConvertTileToBorder(currentTile, DeltaX, DeltaY); } } }