#include "isometricMap.h" #include #include #include "tile.h" #include "raymath.h" #include "raylib.h" #include "../DepthSorting/bucket.h" #include "../game.h" #include "../List/list.h" #include "../DepthSorting/mergeSort.h" // returns pointer to IsometricMap Instance IsometricMap * IsometricMapInit(int layer){ IsometricMap* map = malloc(sizeof(IsometricMap)); map->tileTextures[0] = LoadTexture("assets/grass.png"); map->tileTextures[1] = LoadTexture("assets/grass_selected.png"); map->tileTextures[2] = LoadTexture("assets/tower.png"); map->width = 500; map->height = 500; map->textureWidth = map->tileTextures[0].width; map->textureHeight = map->tileTextures[0].height; map->worldPixelWidth = map->width * map->textureWidth; map->worldPixelWidth = map->height * map->textureHeight; map->layer = layer; // mallocating the twodimensional Tiles Array Tile*** tiles = malloc(map->width*sizeof(Tile*)); int n = 0; for(n=0; n < map->width; n++){ tiles[n] = malloc(map->height*sizeof(Tile*)); } int i = 0; int j = 0; int quarterTextureSize = map->textureWidth / 4; int halfTextureSize = map->textureWidth / 2; for(i=0; i < map->width; i++){ for(j=0; j < map->height; j++){ Tile *tmp = malloc(sizeof(Tile)); // initially all the Tiles are "empty" tmp->textureId = -1; tmp->x = i; tmp->y = j; tmp->z = layer; Vector2 *offset = IsometricMapCalcOffsetForTileAt(i,j, halfTextureSize, quarterTextureSize); // the higher the layer the higher it needs to be drawed offset->y -= layer * quarterTextureSize; tmp->offsetX = offset->x; tmp->offsetY = offset->y; free(offset); tmp->sortable = BucketInit(0, tmp); tiles[i][j] = tmp; } } map->tiles = tiles; return map; } // For Rendering: calculates coordinate offset for a single tile at arrayPosition x y // Only works for tiles with texture width == height (and for 22.5 degree?) Vector2 * IsometricMapCalcOffsetForTileAt(int x, int y, int halfTextureSize, int quarterTextureSize){ Vector2* offset = malloc(sizeof(Vector2)); offset->x = x * halfTextureSize - y * halfTextureSize; offset->y = x * quarterTextureSize + y * quarterTextureSize; return offset; } // Unproject: World Coordinates -> Screen Coordinates writes result in tmp Vector void IsometricMapProject(IsometricMap *isometricMap, Camera2D *camera, float x, float y, Vector2 *tmp){ float tileWidthHalf = isometricMap->textureWidth / 2; float tileHeightQuarter = isometricMap->textureHeight / 4; x += camera->target.x; y += camera->target.y; float xPos = (float) x; float yPos = (float) y; float isoX = 0.5 * ( xPos / tileWidthHalf + yPos / tileHeightQuarter); float isoY = 0.5 * ( -xPos / tileWidthHalf + yPos / tileHeightQuarter); tmp->x = isoX * isometricMap->tileTextures[0].width; tmp->y = isoY * isometricMap->tileTextures[0].height; } // Unproject: World Coordinates -> Screen Coordinates writes result in tmp Vector void IsometricMapUnproject(IsometricMap **isometricMap, Camera2D *camera, int x, int y, float z, Vector2 *tmp){ float xPos = (float) x; float yPos = (float) y; float screenX = (xPos - yPos) / 2; float screenY = (xPos + yPos) / 4; screenX += camera->target.x; screenY += camera->target.y; // z is currently implemented as z=1 equals 1 layer, z=2 would be two layers height (could be smoothed) // hardcoded tile height screenY -= z * 10; tmp->x = screenX; tmp->y = screenY; } // returns Tile * -> tile at coordinates x y z=layer Tile * IsometricMapGetTileFromWorldCoordinates(IsometricMap **isometricMap, float x, float y, float z){ int layer = (int) z; x = (int)(x / isometricMap[layer]->textureWidth); y = (int)(y / isometricMap[layer]->textureHeight); if( x < isometricMap[layer]->width && y < isometricMap[layer]->height && x >= 0 && y >= 0 ){ if(isometricMap[layer]->tiles[(int)x][(int)y]->textureId != -1){ return (isometricMap[layer]->tiles[(int)x][(int)y]); } } Tile *ptr = 0; return ptr; } // Gives the most upper Tile above *tile Tile * IsometricMapGetMostUpperTile(IsometricMap **isometricMap, Tile *tile){ //Tile *ptr = (Tile *) malloc(sizeof(Tile *)); // hardcoded layer amount int n = 9; for(n=9;n>=0;n--){ if( tile->x < isometricMap[n]->width && tile->y < isometricMap[n]->height && tile->x >= 0 && tile->y >= 0 ){ if(isometricMap[n]->tiles[tile->x][tile->y]->textureId != -1){ return isometricMap[n]->tiles[tile->x][tile->y]; } } } return 0; } // changes to Texture ID of tile at x y on maplayer layer void IsometricMapChangeTextureIdOfTile(IsometricMap **map, int x, int y, int layer, int id){ if( x < map[layer]->width && y < map[layer]->height && x >= 0 && y >= 0 ){ (map[layer]->tiles[x][y])->textureId = id; } else{ printf("WARNING: trying to change Texture of Tile which is out of bounds!\n"); } } void IsometricMapDraw(Game *game){ // TODO: Implement as List Bucket *buckets[100000]; int counter = 0; int windowWidth = GetScreenWidth(); int windowHeight = GetScreenHeight(); Vector2 topleft = {0, 0}; IsometricMapProject(game->layers[0], game->camera, topleft.x, topleft.y, &topleft); Vector2 topright = {windowWidth, 0}; IsometricMapProject(game->layers[0], game->camera, topright.x, topright.y, &topright); Vector2 botleft = {0, windowHeight}; IsometricMapProject(game->layers[0], game->camera, botleft.x, botleft.y, &botleft); Vector2 botright = {windowWidth, windowHeight}; IsometricMapProject(game->layers[0], game->camera, botright.x, botright.y, &botright); int extraTiles = 1; int n = 0; int itmp = (int)(topleft.x / game->layers[0]->textureWidth) - extraTiles; int jtmp = (int)(topright.y / game->layers[0]->textureHeight) - extraTiles; int maxI = (int)(botright.x / game->layers[0]->textureWidth) + extraTiles; int maxJ = (int)(botleft.y / game->layers[0]->textureHeight) + extraTiles; if (itmp < 0){ itmp = 0; } if (jtmp < 0){ jtmp = 0; } if (maxI > game->layers[0]->width){ maxI = game->layers[0]->width; } if (maxJ > game->layers[0]->height){ maxJ = game->layers[0]->height; } int i, j = 0; for (n = 0; n < 10; n++){ for (j = jtmp; j < maxJ; j++){ for (i = itmp; i < maxI; i++){ if (game->layers[n]->tiles[i][j]->textureId == -1){ } else{ buckets[counter] = game->layers[n]->tiles[i][j]->sortable; ++counter; } } } } //printf("\n\n\n"); Node *current = game->sprites->head; int extraPixels = 0; // drawing some extra corner pixels // if extraPixels == 0 you can see flickering in the corners itmp = (int)(topleft.x) - extraPixels; jtmp = (int)(topright.y) - extraPixels; maxI = (int)(botright.x) + extraPixels; maxJ = (int)(botleft.y) + extraPixels; while(current != 0){ // Only drawing the Sprites which are within Camera view if( current->data->x > itmp && current->data->y > jtmp && current->data->x < maxI && current->data->y < maxJ){ buckets[counter] = current->data->sortable; ++counter; } current = current->next; } int hmmm = counter; // Merge Sort ist scuffed MergeSort(buckets, hmmm); int k = 0; for(k = 0; k < counter; k++){ if(buckets[k]->type == 1){ DrawTexture( game->layers[0]->tileTextures[buckets[k]->tile->textureId], buckets[k]->tile->offsetX, buckets[k]->tile->offsetY, WHITE); } else if(buckets[k]->type == 0){ DrawSpriteToWorld(buckets[k]->sprite, game->layers, game->camera); } } }