0
\$\begingroup\$

I'm using Raylib, and I'm attempting to place tiles on a level, and the algorithm for placing the tiles is working.Player displays behind left walls

The problem is that the player will display over the walls on the bottom right hand side of the isometric grid. Player is drawn on top of the wall

Displays player over wall on all bottom right tiles

What am I doing wrong, and does this involve the painter's algorithm?

Here is the code:

#include "raylib.h"
#include <stdint.h>

//Defines
#define COLUMNS 10
#define ROWS 10

//Player
typedef struct Player
{
    int dirX; 
    int dirY;
    Texture2D playerTexture;
    Vector2 position;
    struct Player* player;
}Player;

//Change from 2D to Isometric
Vector2 twoDtoIso(Vector2 tilePosition);

void movePlayer(Player* player, int8_t newX, int8_t newY);

int main()
{
    // Initialization
    //-------------------------------------------------------------------------

    const uint8_t TILE_WIDTH    =     32;
    const uint8_t TILE_HEIGHT   =     32;
    const uint8_t PLAYER_OFFSET =     32;
    const float SCREEN_WIDTH    = 640.0f;
    const float SCREEN_HEIGHT   = 352.0f;
    const float SCREEN_CENTER_X = 288.0f; 
    const float SCREEN_CENTER_Y =   0.0f;

    InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Isometric Tile placement");

    //These images are loaded from a folder named "images" with 
    //isometric cubes that are 64 pixels by 64 pixels
    Texture2D wallTexture   = LoadTexture("images/wallTile.png");
    Texture2D groundTexture = LoadTexture("images/groundTile.png");

    Player player = {0, 0,LoadTexture("images/player.png"),(Vector2){ SCREEN_CENTER_X, PLAYER_OFFSET }};

    uint8_t levelData[COLUMNS][ROWS] = 
    {
        {1,1,1,1,1,1,1,1,1,1},
        {1,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,0,1},
        {1,0,0,0,0,0,0,0,2,1}, //<-----The player is designated as 2, ground as 0, and wall tiles as 1
        {1,1,1,1,1,1,1,1,1,1}
    };

    static uint8_t tileType;  
    const uint8_t  NUM_COLUMNS = 10;
    const uint8_t  NUM_ROWS    = 10;
    const int8_t   newX        = 32;
    const int8_t   newY        = 16;

    Vector2 coords;
    Vector2 tilePosition;

    SetTargetFPS(30);              
    //------------------------End Initialization-------------------------------

    // Main game loop
    while (!WindowShouldClose())    
    {
        // Update
        //---------------------------------------------------------------------

        //Player input/movement 

        movePlayer(&player, newX, newY); 

        //--------------------------End Update---------------------------------

        // Draw
        //---------------------------------------------------------------------
        BeginDrawing();

            ClearBackground(BLACK);

            //place tiles
            for (uint8_t i = 0; i < NUM_ROWS; i++)
            {   
                for (uint8_t j = 0; j < NUM_COLUMNS ; j++)
                {
                    tilePosition = (Vector2){(float)j * TILE_WIDTH, (float)i * TILE_HEIGHT};
                    tileType = levelData[i][j];
                    coords = twoDtoIso(tilePosition);

                    if(tileType == 0) //place ground tile
                    {
                         DrawTexture(groundTexture, coords.x + SCREEN_CENTER_X, coords.y + SCREEN_CENTER_Y, WHITE);
                    }
                    else if(tileType == 1) //place wall tile                
                    {
                        DrawTexture(wallTexture, coords.x + SCREEN_CENTER_X, coords.y + SCREEN_CENTER_Y, WHITE);
                    }
                    else //otherwise place the player 
                    {
                        DrawTexture(player.playerTexture, player.position.x, player.position.y, WHITE);
                    }
                }
            }//end for loop     

        EndDrawing();
        //---------------------------------------------------------------------
    }

    // De-Initialization
    //-------------------------------------------------------------------------
    UnloadTexture(groundTexture);    
    UnloadTexture(wallTexture);
    UnloadTexture(player.playerTexture);

    CloseWindow();                // Close window and OpenGL context
    //-------------------------------------------------------------------------

    return 0;
}

Vector2 twoDtoIso(Vector2 tilePosition)
{
    Vector2 tempPoint;
    tempPoint.x =  tilePosition.x - tilePosition.y;
    tempPoint.y = (tilePosition.x + tilePosition.y)/ 2;
    return(tempPoint);
}

void movePlayer(Player* player, int8_t newX, int8_t newY)
{
    if (IsKeyPressed(KEY_LEFT))
    { 
        player->position = (Vector2){ player->position.x - newX, player->position.y + newY };
    }
    if (IsKeyPressed(KEY_RIGHT))
    { 
        player->position = (Vector2){ player->position.x + newX, player->position.y - newY };
    }
    if (IsKeyPressed(KEY_UP))
    { 
        player->position = (Vector2){ player->position.x - newX, player->position.y - newY };
    }
    if (IsKeyPressed(KEY_DOWN))
    { 
        player->position = (Vector2){ player->position.x + newX, player->position.y + newY };
    }
}


```
\$\endgroup\$
2

2 Answers 2

2
\$\begingroup\$

You are painting your tiles in the wrong order. Yes, you would use the painters algorithm, which just means, that you draw from back to forward. In your image (I can't really see, where you 0,0 is in the image. 0,0 should be in the top middle of the screen and then like so:

enter image description here

if you "rotate" to change the direction you are viewing you need another draw order. It's normally solved by just inverting a loop from 0->n to n->0 or something (depends on where you 0,0 is on the image)

\$\endgroup\$
1
  • \$\begingroup\$ Thank you so much. I will start working on this now. \$\endgroup\$ Commented Dec 1, 2019 at 17:41
0
\$\begingroup\$

Here's how I got it working. The player tile can be moved with WASD, and some tiles allow the player to move to tiles that are a height of less than 2. The player can collide with tiles that are designated as collision tiles. Make sure you have a folder named "images" with your tiles, where the .c file is located. Using raylib v4.6-dev:

#include <raylib.h>
#include <raymath.h>

#define GRID_WIDTH 8
#define GRID_HEIGHT 8
#define TILE_SIZE 64
#define PLAYER_SPEED 1
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480

// Define tile types (add more as needed)
enum TileType {
    TILE_FLOOR = 0,
    TILE_WALL,
    TILE_TREE,
    TILE_WATER,
    TILE_ELEVATION, // New tile type for elevation
    TILE_GRASS,
};

int playerX = 0;
int playerY = 0;

// 3D array representing the isometric grid with tile types and elevation
int grid[GRID_WIDTH][GRID_HEIGHT][2] = {0}; // Initialize with all floor tiles at elevation 0

// Function to convert grid coordinates to screen coordinates
Vector2 GridToScreen(int x, int y, int elevation) {
    Vector2 screenPos;
    screenPos.x = (x - y) * (TILE_SIZE / 2);
    screenPos.y = (x + y) * (TILE_SIZE / 4) - elevation * (TILE_SIZE / 2);
    return screenPos;
}

// Function to check if the player can move to the specified grid position
bool CanMoveTo(int x, int y) {
    if (x < 0 || x >= GRID_WIDTH || y < 0 || y >= GRID_HEIGHT) {
        // Out of bounds
        return false;
    }

    // Check the tile type and elevation at the specified grid position
    int tileType = grid[x][y][0];
    int elevation = grid[x][y][1];

    // Check if the target tile has an elevation of 1 or is flat ground (elevation 0)
    if (elevation == 1 || elevation == 0) {
        // If the tile is a wall or tree, return false
        if (tileType == TILE_WALL || tileType == TILE_TREE) {
            return false;
        }

        return true; // Otherwise, the player can move to this tile
    }

    // Check if the player is moving from elevation 1 to elevation 2 or vice versa
    int currentElevation = grid[playerX][playerY][1];
    if ((currentElevation == 1 && elevation == 2) || (currentElevation == 2 && elevation == 1)){
        return true;
    }

    return false; // Elevation is 2 or higher, and it's not a valid move from elevation 0
}

int main() {
    InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Isometric Grid with Raylib");
    SetTargetFPS(60);

    // Place wall tiles at specific locations with elevation 1 (you can change these as needed)
    grid[2][5][0] = TILE_WALL;
    grid[3][1][0] = TILE_WALL;
    grid[4][3][0] = TILE_WALL;
    grid[2][4][0] = TILE_WALL;
    grid[3][3][0] = TILE_WALL;

    // Add other tile types (e.g., tree, water, grass) at specific locations and elevations
    grid[1][3][0] = TILE_TREE;
    grid[6][4][0] = TILE_TREE;
    grid[4][1][0] = TILE_WATER;
    grid[0][7][0] = TILE_ELEVATION; // Elevation at (0, 7) represented by the rock tile
    grid[7][0][0] = TILE_GRASS;

    // Set the elevation value for the tile representing the rock elevation
    grid[0][7][1] = 1; // Elevation level of 1 for the rock tile
    grid[1][7][1] = 2; // Elevation level of 1 for the rock tile

    // Load textures
    Texture2D floorTexture     = LoadTexture("images/floorTile.png");
    Texture2D wallTexture      = LoadTexture("images/wallTile.png");
    Texture2D playerTexture    = LoadTexture("images/playerTile.png");
    Texture2D treeTexture      = LoadTexture("images/treeTile.png");
    Texture2D waterTexture     = LoadTexture("images/waterTile.png");
    Texture2D elevationTexture = LoadTexture("images/rockTile.png"); // Texture for elevation (rock tile)
    Texture2D grassTexture     = LoadTexture("images/grassTile.png");

    while (!WindowShouldClose()) {
        // Handle player movement
        if (IsKeyPressed(KEY_W) && CanMoveTo(playerX, playerY - 1)) {
            playerY -= PLAYER_SPEED;
        }
        if (IsKeyPressed(KEY_A) && CanMoveTo(playerX - 1, playerY)) {
            playerX -= PLAYER_SPEED;
        }
        if (IsKeyPressed(KEY_S) && CanMoveTo(playerX, playerY + 1)) {
            playerY += PLAYER_SPEED;
        }
        if (IsKeyPressed(KEY_D) && CanMoveTo(playerX + 1, playerY)) {
            playerX += PLAYER_SPEED;
        }

        // Ensure the player stays within the grid boundaries
        playerX = Clamp(playerX, 0, GRID_WIDTH - 1);
        playerY = Clamp(playerY, 0, GRID_HEIGHT - 1);

        BeginDrawing();
        ClearBackground(BLACK);

        // Render tiles from back to front (lower y-axis first)
        for (int y = 0; y < GRID_HEIGHT; y++) {
            for (int x = 0; x < GRID_WIDTH; x++) {
                Vector2 screenPos = GridToScreen(x, y, grid[x][y][1]); // Use the elevation value

                // Render the tile at grid[x][y] at (screenPos.x, screenPos.y)
                switch (grid[x][y][0]) {
                    case TILE_WALL:
                        DrawTexture(wallTexture, screenPos.x + SCREEN_WIDTH / 2, screenPos.y, WHITE);
                        break;
                    case TILE_TREE:
                        DrawTexture(treeTexture, screenPos.x + SCREEN_WIDTH / 2, screenPos.y, WHITE);
                        break;
                    case TILE_WATER:
                        DrawTexture(waterTexture, screenPos.x + SCREEN_WIDTH / 2, screenPos.y, WHITE);
                        break;
                    case TILE_ELEVATION:
                        DrawTexture(elevationTexture, screenPos.x + SCREEN_WIDTH / 2, screenPos.y, WHITE);
                        break;
                    case TILE_GRASS:
                        DrawTexture(grassTexture, screenPos.x + SCREEN_WIDTH / 2, screenPos.y, WHITE);
                        break;
                    default:
                        DrawTexture(floorTexture, screenPos.x + SCREEN_WIDTH / 2, screenPos.y, WHITE);
                        break;
                }

                // Render the player
                if (x == playerX && y == playerY) {
                    DrawTexture(playerTexture, screenPos.x + SCREEN_WIDTH / 2, screenPos.y, WHITE);
                }
            }
        }

        EndDrawing();
    }

    // Unload textures
    UnloadTexture(floorTexture);
    UnloadTexture(wallTexture);
    UnloadTexture(playerTexture);
    UnloadTexture(treeTexture);
    UnloadTexture(waterTexture);
    UnloadTexture(elevationTexture);
    UnloadTexture(grassTexture);

    CloseWindow();

    return 0;
}
```
\$\endgroup\$
1
  • \$\begingroup\$ Remember to click the checkmark icon at the top-left of an answer to mark it as "Accepted" if it successfully solved your problem. \$\endgroup\$
    – DMGregory
    Commented Jul 29, 2023 at 12:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .