#include "parameters.h" #include "level.h" #include "player.h" #include #include #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; iw; i++) { for(int j=0; jh; 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; unblayers-!drawforeground;u++) { for(int i=0; iw; i++) { for(int j=0; jh; 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; iA.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; iA.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; AB.x = B.x - A.x; AB.y = B.y - A.y; libnum::num32 t = AB.Dot( AB ); if (t==0) { (*R).x = A.x; (*R).y = A.y; return t; } Vector2D Pv, Av; Pv.x = P.x; Pv.y = P.y; Av.x = A.x; Av.y = A.y; libnum::num32 t2 = (Pv.Dot(AB) - Av.Dot(AB)) / t; if (t2libnum::num32(1)) t2 = libnum::num32(1); Av.Add( AB, t ); (*R).x = A.x; (*R).y = A.y; 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; iA, 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; iw-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 ); } } }