Untitled
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