Untitled

 avatar
unknown
plain_text
a year ago
12 kB
16
Indexable
class TileArrayCPP {
private:
    // Constants for magic numbers
    static constexpr int MAP_WIDTH = 100;
    static constexpr int MAP_HEIGHT = 50;
    static constexpr int RENDER_WIDTH = 32;
    static constexpr int RENDER_HEIGHT = 24;
    static constexpr int TILE_SIZE = 10;
    static constexpr int ANIMATION_CYCLE = 10;
    static constexpr int FALL_ANIMATION_THRESHOLD = 15;
    static constexpr int MOVING_BLOCK_THRESHOLD = 10;
    static constexpr int FALLING_BLOCK_THRESHOLD = 10;
    
    // Tile type constants
    enum TileType : char {
        EMPTY = 'X',
        BLOCK = 'B',
        PLAYER = 'P',
        STATIC_BLOCK = 'S',
        KILLER_BLOCK = 'K',
        MOVING_BLOCK = 'M',
        GOAL_BLOCK = 'G',
        FALLING_BLOCK = 'F'
    };
    
    // Level configuration structure
    struct LevelConfig {
        const uint8_t* levelMap;
        int startX;
        int startY;
    };
    
    // Level configurations lookup table
    static constexpr LevelConfig LEVEL_CONFIGS[6] = {
        {level1_map, 46, 50},
        {level2_map, 35, 50},
        {level3_map, 35, 50},
        {level4_map, 50, 50},
        {level5_map, 50, 50},
        {level6_map, 3, 47}
    };

public:
    char map[MAP_WIDTH][MAP_HEIGHT];
    char blocks[MAP_WIDTH][MAP_HEIGHT];
    
    // Moving block state
    int MBCounter;
    int MBPosY;
    int MBPosX;
    
    // Non-static block (falling) state
    int NSBCounter;
    int NSBPosX;
    int NSBPosY;

    void tileArray() {
        // Reset counters
        MBCounter = 0;
        NSBCounter = 0;
        fallCounter = 0;
        counter = 0;
        
        // Use lookup table for level configuration
        if (levelSelection >= 1 && levelSelection <= 6) {
            const LevelConfig& config = LEVEL_CONFIGS[levelSelection - 1];
            tilemap.map = config.levelMap;
            startX = config.startX;
            startY = config.startY;
        }
    }
    
    void readMap() {
        const int totalTiles = MAP_WIDTH * MAP_HEIGHT;
        
        // Single loop optimization - process tiles sequentially
        for (int idx = 0; idx < totalTiles; idx++) {
            const int i = idx % MAP_WIDTH;
            const int j = idx / MAP_WIDTH;
            const uint8_t tileValue = tilemap.map[idx];
            
            // Use switch for better optimization
            switch (tileValue) {
                case 0x00:
                    map[i][j] = EMPTY;
                    blocks[i][j] = EMPTY;
                    break;
                case 0x01:
                    map[i][j] = BLOCK;
                    blocks[i][j] = STATIC_BLOCK;
                    break;
                case 0x03:
                    map[i][j] = BLOCK;
                    blocks[i][j] = KILLER_BLOCK;
                    break;
                case 0x04:
                case 0x06:  // Combine duplicate cases
                    map[i][j] = BLOCK;
                    blocks[i][j] = MOVING_BLOCK;
                    break;
                case 0x05:
                    map[i][j] = BLOCK;
                    blocks[i][j] = GOAL_BLOCK;
                    break;
                default:
                    map[i][j] = EMPTY;
                    blocks[i][j] = EMPTY;
                    break;
            }
        }
        
        // Set player position
        map[startX][startY] = PLAYER;
        playerX = startX;
        playerY = startY;
        lastX = startX - 16;  // Use RENDER_WIDTH/2
        lastY = startY - 12;  // Use RENDER_HEIGHT/2
    }
    
    void render() {
        gfx_SetPalette(global_palette, sizeof_global_palette, 0);
        zx7_Decompress(gfx_vram, background2_compressed);
        
        // Calculate camera position with bounds checking
        updateCamera();
        
        // Render visible tiles only
        for (int i = 0; i < RENDER_WIDTH; i++) {
            for (int j = 0; j < RENDER_HEIGHT; j++) {
                const int worldX = lastX + i;
                const int worldY = lastY + j;
                
                // Bounds check
                if (worldX >= MAP_WIDTH || worldY >= MAP_HEIGHT) continue;
                
                const int screenX = i * TILE_SIZE;
                const int screenY = j * TILE_SIZE;
                
                // Render player
                if (map[worldX][worldY] == PLAYER) {
                    renderPlayer(screenX, screenY);
                } else {
                    // Render blocks
                    renderBlock(blocks[worldX][worldY], screenX, screenY);
                }
            }
        }
    }
    
private:
    void updateCamera() {
        const int halfRenderWidth = RENDER_WIDTH / 2;
        const int halfRenderHeight = RENDER_HEIGHT / 2;
        
        int topLeftX = playerX - halfRenderWidth;
        int topLeftY = playerY - halfRenderHeight;
        
        // Clamp camera bounds
        topLeftX = clamp(topLeftX, 0, MAP_WIDTH - RENDER_WIDTH);
        topLeftY = clamp(topLeftY, 0, MAP_HEIGHT - RENDER_HEIGHT);
        
        lastX = topLeftX;
        lastY = topLeftY;
    }
    
    int clamp(int value, int min, int max) const {
        if (value < min) return min;
        if (value > max) return max;
        return value;
    }
    
    void renderPlayer(int screenX, int screenY) {
        gfx_sprite_t* sprite = getPlayerSprite();
        gfx_TransparentSprite(sprite, screenX, screenY);
    }
    
    gfx_sprite_t* getPlayerSprite() {
        // Falling animation
        if (fallCounter >= 1) {
            if (fallCounter < 5) {
                return texture == 0 ? MDJump : SJJump;
            } else if (fallCounter < 10) {
                return texture == 0 ? MDFalling1 : SJFalling1;
            } else {
                return texture == 0 ? MDFalling2 : SJFalling2;
            }
        }
        
        // Walking animation
        if (counter >= 1 && counter < 5) {
            return texture == 0 ? MDAnimation1 : SJAnimation1;
        } else if (counter >= 5 && counter < 10) {
            return texture == 0 ? MDAnimation2 : SJAnimation2;
        } else {
            return texture == 0 ? MDStatic : SJStatic;
        }
    }
    
    void renderBlock(char blockType, int screenX, int screenY) {
        gfx_sprite_t* sprite = nullptr;
        
        switch (blockType) {
            case STATIC_BLOCK:
                sprite = staticBlock;
                break;
            case KILLER_BLOCK:
                sprite = killerBlock;
                break;
            case FALLING_BLOCK:
                sprite = fallingBlock;
                break;
            case GOAL_BLOCK:
                sprite = goalBlock;
                break;
            case MOVING_BLOCK:
                sprite = movingBlock;
                break;
            default:
                return; // Don't render empty tiles
        }
        
        if (sprite) {
            gfx_TransparentSprite(sprite, screenX, screenY);
        }
    }

public:
    void gravity() {
        map[playerX][playerY] = EMPTY;
        playerY--;
        map[playerX][playerY] = PLAYER;
        
        fallCounter += 2;
        if (fallCounter >= FALL_ANIMATION_THRESHOLD) {
            fallCounter = 5;
        }
    }
    
    bool tryMove(int deltaX, int deltaY) {
        const int newX = playerX + deltaX;
        const int newY = playerY + deltaY;
        
        // Bounds checking
        if (newX < 0 || newX >= MAP_WIDTH || newY < 0 || newY >= MAP_HEIGHT) {
            return false;
        }
        
        if (map[newX][newY] == BLOCK) {
            return false;
        }
        
        // Move player
        map[playerX][playerY] = EMPTY;
        playerX = newX;
        playerY = newY;
        map[playerX][playerY] = PLAYER;
        
        return true;
    }
    
    void translateLeft() {
        if (tryMove(-1, 0)) {
            updateAnimationCounter();
        }
    }
    
    void translateRight() {
        if (tryMove(1, 0)) {
            updateAnimationCounter();
        }
    }
    
    void jump() {
        // Try different jump heights based on available space
        for (int jumpHeight = 3; jumpHeight >= 1; jumpHeight--) {
            if (tryMove(0, jumpHeight)) {
                break;
            }
        }
    }
    
    bool isTouchingGround() {
        if (playerY == 0) {
            gameOver = true;
            return true;
        }
        
        const char groundTile = map[playerX][playerY - 1];
        const char groundBlock = blocks[playerX][playerY - 1];
        
        if (groundTile == BLOCK) {
            fallCounter = 0;
            handleSpecialBlocks(groundBlock);
            return true;
        }
        
        return false;
    }
    
private:
    void updateAnimationCounter() {
        counter++;
        if (counter >= ANIMATION_CYCLE) {
            counter = 1;
        }
    }
    
    void handleSpecialBlocks(char blockType) {
        switch (blockType) {
            case KILLER_BLOCK:
                gameOver = true;
                break;
            case GOAL_BLOCK:
                handleLevelClear();
                break;
            case FALLING_BLOCK:
                handleFallingBlock();
                break;
            case MOVING_BLOCK:
                handleMovingBlock();
                break;
        }
    }
    
    void handleLevelClear() {
        levelCleared = true;
        
        // Use lookup table or switch for unlocking
        switch (levelSelection) {
            case 1: L2Unlocked = 1; break;
            case 2: L3Unlocked = 1; break;
            case 3: L4Unlocked = 1; break;
            case 4: L5Unlocked = 1; break;
            case 5: L6Unlocked = 1; break;
            case 6: SJUnlocked = 1; break;
        }
    }
    
    void handleFallingBlock() {
        NSBCounter++;
        NSBPosX = playerX;
        NSBPosY = playerY - 1;
        
        if (NSBCounter >= FALLING_BLOCK_THRESHOLD) {
            moveFallingBlock();
        }
    }
    
    void handleMovingBlock() {
        MBCounter++;
        MBPosX = playerX;
        MBPosY = playerY - 1;
        
        if (MBCounter >= MOVING_BLOCK_THRESHOLD) {
            moveMovingBlock();
        }
    }
    
    void moveFallingBlock() {
        // Clear current position
        blocks[NSBPosX][NSBPosY] = EMPTY;
        map[NSBPosX][NSBPosY] = EMPTY;
        
        // Move down
        NSBPosY--;
        
        const char targetBlock = blocks[NSBPosX][NSBPosY];
        if (targetBlock == KILLER_BLOCK || targetBlock == BLOCK || targetBlock == GOAL_BLOCK) {
            // Block is destroyed
            blocks[NSBPosX][NSBPosY] = EMPTY;
            map[NSBPosX][NSBPosY] = EMPTY;
        } else {
            // Place falling block in new position
            blocks[NSBPosX][NSBPosY] = FALLING_BLOCK;
            map[NSBPosX][NSBPosY] = BLOCK;
        }
    }
    
    void moveMovingBlock() {
        // Clear current position
        blocks[MBPosX][MBPosY] = EMPTY;
        map[MBPosX][MBPosY] = EMPTY;
        
        // Move left
        MBPosX--;
        
        // Place in new position
        blocks[MBPosX][MBPosY] = MOVING_BLOCK;
        map[MBPosX][MBPosY] = BLOCK;
    }

public:
    void resetWalk() {
        counter = 0;
    }
};
Editor is loading...
Leave a Comment