专栏文章

迷宫0

个人记录参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miors3oh
此快照首次捕获于
2025/12/03 00:05
3 个月前
此快照最后确认于
2025/12/03 00:05
3 个月前
查看原文
CPP
#include<iostream>
#include<vector>
#include<cmath>
#include<windows.h>
static int SCREEN_WIDTH;
static int SCREEN_HEIGHT;
static CHAR_INFO* screen = nullptr;
static HANDLE hConsole;
static SMALL_RECT writeRegion;
static COORD bufCoord = {0,0};
const double PI = 3.141592653589793;
const double MOVE_SPEED = 0.1,TURN_SPEED = 0.05;
const int MAP_WIDTH = 10,MAP_HEIGHT = 10;
static int worldMap[MAP_HEIGHT][MAP_WIDTH] = {
    {1,1,1,1,1,1,1,1,1,1},
    {1,0,0,0,0,0,0,0,0,1},
    {1,0,1,1,1,1,1,0,1,1},
    {1,0,1,0,0,0,1,0,0,1},
    {1,0,1,0,1,0,1,1,0,1},
    {1,0,1,0,1,0,0,0,0,1},
    {1,0,1,0,1,1,1,1,0,1},
    {1,0,0,0,0,0,0,0,0,1},
    {1,1,1,1,1,1,1,1,1,1},
    {1,1,1,1,1,1,1,1,1,1},
};
struct Player {
    double x = 1.5, y = 1.5; // Start position
    double angle = 0;       // Horizontal viewing angle (yaw)
    double cosA, sinA;      // Precomputed sin/cos of angle
    inline void updateTrig(){ cosA=cos(angle); sinA=sin(angle); }
} player;
enum ConsoleColor {
    BLACK = 0,
    DARK_BLUE = 1, DARK_GREEN = 2, DARK_CYAN = 3, DARK_RED = 4, DARK_MAGENTA = 5, DARK_YELLOW = 6,
    GREY = 7, DARK_GREY = 8, BLUE = 9, GREEN = 10, CYAN = 11, RED = 12, MAGENTA = 13, YELLOW = 14,
    WHITE = 15
};
int getWorldAt(int x, int y) {
    if (x < 0 || x >= MAP_WIDTH || y < 0 || y >= MAP_HEIGHT) return 1;
    return worldMap[y][x];
}
inline bool key(int vk){ return (GetAsyncKeyState(vk) & 0x8000) != 0; }
inline void draw(int x,int y,char c,WORD col){
    if(y>=0&&y<SCREEN_HEIGHT&&x>=0&&x<SCREEN_WIDTH) {
        CHAR_INFO cell_info;
        cell_info.Char.AsciiChar = c; 
        cell_info.Attributes = col;    
        screen[y*SCREEN_WIDTH + x] = cell_info; 
    }
}
void initConsole(){
    hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    std::cout << "Enter console width height (e.g., 120 40): "; 
    std::cin >> SCREEN_WIDTH >> SCREEN_HEIGHT;
    COORD bufSize = {(SHORT)SCREEN_WIDTH,(SHORT)SCREEN_HEIGHT};
    SetConsoleScreenBufferSize(hConsole,bufSize);
    SMALL_RECT win={0,0,(SHORT)(SCREEN_WIDTH-1),(SHORT)(SCREEN_HEIGHT-1)};
    SetConsoleWindowInfo(hConsole,TRUE,&win);
    writeRegion=win;
    screen = (CHAR_INFO*)malloc(sizeof(CHAR_INFO)*SCREEN_WIDTH*SCREEN_HEIGHT);
    CONSOLE_CURSOR_INFO cci; GetConsoleCursorInfo(hConsole,&cci); cci.bVisible=false; SetConsoleCursorInfo(hConsole,&cci);
}
void renderFrame(){
    player.updateTrig();
    const double FOV = PI / 3.0; // Fixed FOV
    const double invW = 1.0 / SCREEN_WIDTH;
    const int halfH = SCREEN_HEIGHT / 2;
    for(int y = 0; y < SCREEN_HEIGHT; ++y){
        for(int x = 0; x < SCREEN_WIDTH; ++x){
            if (y < halfH) { // Sky
                screen[y*SCREEN_WIDTH+x]={{' '},BLUE};
            } else { // Floor
                screen[y*SCREEN_WIDTH+x]={{'.'},DARK_GREEN};
            }
        }
    }
    for(int x=0; x<SCREEN_WIDTH; ++x){
        double camX = 2 * x * invW - 1; 
        double rayDirX = player.cosA - player.sinA * camX;
        double rayDirY = player.sinA + player.cosA * camX;
        int mapX = int(player.x);
        int mapY = int(player.y);
        double deltaDistX = fabs(1 / rayDirX);
        double deltaDistY = fabs(1 / rayDirY);
        double sideDistX;
        double sideDistY;
        int stepX;
        int stepY;
        if (rayDirX < 0) {
            stepX = -1;
            sideDistX = (player.x - mapX) * deltaDistX;
        } else {
            stepX = 1;
            sideDistX = (mapX + 1.0 - player.x) * deltaDistX;
        }
        if (rayDirY < 0) {
            stepY = -1;
            sideDistY = (player.y - mapY) * deltaDistY;
        } else {
            stepY = 1;
            sideDistY = (mapY + 1.0 - player.y) * deltaDistY;
        }
        int hit = 0; // Was a wall hit?
        int side;    // Was it an X or Y side? (0 for X, 1 for Y)
        while(hit == 0){
            if(sideDistX < sideDistY){
                sideDistX += deltaDistX;
                mapX += stepX;
                side = 0;
            } else {
                sideDistY += deltaDistY;
                mapY += stepY;
                side = 1;
            }
            if(getWorldAt(mapX,mapY) == 1) hit = 1; // Hit a wall
        }
        double perpWallDist;
        if(side == 0) perpWallDist = (mapX - player.x + (1 - stepX) / 2) / rayDirX;
        else          perpWallDist = (mapY - player.y + (1 - stepY) / 2) / rayDirY;
        if (perpWallDist < 0.05) perpWallDist = 0.05;
        int lineHeight = int(SCREEN_HEIGHT / perpWallDist);
        int drawStart = -lineHeight / 2 + halfH;
        int drawEnd = lineHeight / 2 + halfH;
        drawStart = std::max(0, drawStart);
        drawEnd = std::min(SCREEN_HEIGHT, drawEnd);
        WORD wallCol = (side ? DARK_GREY : GREY); 
        char wallChar = (perpWallDist < 2.5 ? '#' : (perpWallDist < 5 ? '%' : (perpWallDist < 7.5 ? '*' : '.')));
        for(int y=drawStart; y<drawEnd; ++y){
            draw(x,y,wallChar,wallCol);
        }
    }
    draw(SCREEN_WIDTH/2, halfH, '+', WHITE); 
    WriteConsoleOutputA(hConsole, screen, {SHORT(SCREEN_WIDTH), SHORT(SCREEN_HEIGHT)}, bufCoord, &writeRegion);
}
int main(){
    initConsole();
    std::cout << "\n\n  按下 ENTER 开始...";
    std::cin.ignore();
    std::cin.get();
    bool gameOver=0;
    while(!gameOver){
        double player_old_x = player.x;
        double player_old_y = player.y;
        if(key('W')){
            player.x+=player.cosA * MOVE_SPEED; 
            player.y+=player.sinA * MOVE_SPEED; 
        }
        if(key('S')){
            player.x -= player.cosA * MOVE_SPEED; 
            player.y -= player.sinA * MOVE_SPEED; 
        }
        if(key('A')){
            player.x += player.sinA * MOVE_SPEED; 
            player.y -= player.cosA * MOVE_SPEED; 
        }
        if(key('D')){
            player.x -= player.sinA * MOVE_SPEED; 
            player.y += player.cosA * MOVE_SPEED; 
        }
        if(key(VK_LEFT)) player.angle -= TURN_SPEED; 
        if(key(VK_RIGHT)) player.angle += TURN_SPEED; 
        const double COLLISION_RADIUS = 0.2; 
        if(getWorldAt(int(player.x + (player.x > player_old_x ? COLLISION_RADIUS : -COLLISION_RADIUS)), int(player.y)) == 1) {
            player.x = player_old_x;
        }
        if(getWorldAt(int(player.x), int(player.y + (player.y > player_old_y ? COLLISION_RADIUS : -COLLISION_RADIUS))) == 1) {
            player.y = player_old_y;
        }
        renderFrame();
        if(key(VK_ESCAPE)) {
            gameOver = true;
        }
        Sleep(16);
    }
    free(screen);
    system("cls");
    std::cout << "\n\n  Thanks for playing!\n";
    Sleep(1000);
    return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...