一、在控制台中显示画面
使用cout方式显示时刷新速度较慢,不能满足游戏需求。 游戏的显示借助windows函数。
#include<iostream> using namespace std; #include<Windows.h> //定义屏幕宽度、高度 int nScreenWidth = 120; int nScreenHeight = 40; int main() { // Create Screen Buffer 创建屏幕缓冲区 wchar_t *screen = new wchar_t[nScreenWidth*nScreenHeight]; HANDLE hConsole = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); SetConsoleActiveScreenBuffer(hConsole); DWORD dwBytesWritten = 0; //游戏循环 while (1) { // Display Frame 显示 screen[nScreenWidth * nScreenHeight - 1] = '\0'; WriteConsoleOutputCharacter(hConsole, screen, nScreenWidth * nScreenHeight, { 0,0 }, &dwBytesWritten); } }
二、
地图
//地图 int nMapWidth = 16; // World Dimensions int nMapHeight = 16; //玩家位置X、Y、角度 float fPlayerX = 0.0f; // Player Start Position float fPlayerY = 0.0f; float fPlayerA = 0.0f; // Player Start Rotation // 创建地图 Create Map of world space # = wall block, . = space wstring map; map += L"################"; map += L"#..............#"; map += L"#..............#"; map += L"#..............#"; map += L"#..............#"; map += L"#..............#"; map += L"#..............#"; map += L"#..............#"; map += L"#..............#"; map += L"#..............#"; map += L"#..............#"; map += L"#..............#"; map += L"#..............#"; map += L"#..............#"; map += L"#..............#"; map += L"################";
地图与实际的对应
(玩家视角有限)
(玩家视线)
通过视线与墙面的碰撞检测,生成玩家看到的画面。
for (int x = 0; x < nScreenWidth; x++) { // For each column, calculate the projected ray angle into world space float fRayAngle = (fPlayerA - fFOV / 2.0f) + ((float)x / (float)nScreenWidth) * fFOV;//从左半边到右半边 float fDistanceToWall = 0.0f; // bool bHitWall = false; float fEyeX = sinf(fRayAngle); //视线方向对应的单位分量 Unit vector for ray in player space float fEyeY = cosf(fRayAngle); //增量方式 判断视线撞墙 while (!bHitWall && fDistanceToWall<fDepth) { fDistanceToWall += 0.1f; int nTestX = (int)(fPlayerX + fEyeX * fDistanceToWall); int nTestY = (int)(fPlayerY + fEyeY * fDistanceToWall); // 检查视线达到边界 Test if ray is out of bounds if (nTestX < 0 || nTestX >= nMapWidth || nTestY < 0 || nTestY >= nMapHeight) { bHitWall = true; // Just set distance to maximum depth fDistanceToWall = fDepth; } else { //检查视线是否遇到墙体 if (map[nTestY*nMapWidth + nTestX] == '#') { bHitWall = true; } } } //计算到天花板和地板的距离 int nCeiling = (float)(nScreenHeight / 2.0) - nScreenHeight/((float)fDistanceToWall); int nFloor = nScreenHeight - nCeiling; for (int y = 0; y < nScreenHeight; y++) { // Each Row if (y < nCeiling) //天花板 screen[y*nScreenWidth + x] = ' '; else if (y > nCeiling && y <= nFloor) screen[y*nScreenWidth + x] = '#'; else // 地板 Floor { screen[y*nScreenWidth + x] = ' '; } } }
三、左右移动,其中用tp2-tp1来获得一帧花费的时间,使得运动看起来更流畅。
#include<chrono> //时间相关 auto tp1 = chrono::system_clock::now(); auto tp2 = chrono::system_clock::now(); //游戏循环 while (1) { //计算时间 tp2 = chrono::system_clock::now(); chrono::duration<float>elapsedTime = tp2 - tp1; tp1 = tp2; float fElapsedTime = elapsedTime.count(); //一帧的时间 // Handle CCW Rotation if (GetAsyncKeyState((unsigned short)'A') & 0x8000) fPlayerA -= (0.1f)*fElapsedTime; if (GetAsyncKeyState((unsigned short)'D') & 0x8000) fPlayerA += (0.1f)*fElapsedTime;
做到这里(视频的19:06),当我继续往下做的时候发现图像显示的很奇怪,方块都串行显示,看起来像乱码。
但是参考之前的俄罗斯方块中的控制台设置方法,改变控制台之后还是没有改变。
没有找到解决方法,但猜测是和控制台相关的问题(使用作者代码运行也是乱码https://github.com/OneLoneCoder/videos/blob/master/OneLoneCoder_CommandLineFPS.cpp)。