专栏文章
迷宫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 条评论,欢迎与作者交流。
正在加载评论...