完整代码##define UNICODE #define _UNICODE #include windows.h #include cmath #include cstdio #include chrono #include thread #include algorithm #include vector #include string #include random #include fstream struct vec2 { float x,y; vec2(float v):x(v),y(v){} vec2(float a,float b):x(a),y(b){} vec2 operator(vec2 o)const{return {xo.x,yo.y};} vec2 operator-(vec2 o)const{return {x-o.x,y-o.y};} vec2 operator*(vec2 o)const{return {x*o.x,y*o.y};} }; struct vec3 { float x,y,z; vec3():x(0),y(0),z(0){} vec3(float v):x(v),y(v),z(v){} vec3(float a,float b,float c):x(a),y(b),z(c){} vec3(float a,vec2 v):x(a),y(v.x),z(v.y){} vec3 operator(vec3 o)const{return {xo.x,yo.y,zo.z};} vec3 operator-(vec3 o)const{return {x-o.x,y-o.y,z-o.z};} vec3 operator*(vec3 o)const{return {x*o.x,y*o.y,z*o.z};} vec3 operator/(vec3 o)const{return {x/o.x,y/o.y,z/o.z};} vec3 operator-()const{return {-x,-y,-z};} vec3 operator*(float s) const { return {x*s, y*s, z*s}; } friend vec3 operator*(float s, const vec3 v) { return v * s; } }; inline float clamp(float v,float a,float b){ return fmaxf(fminf(v,b),a); } inline float sign(float a){ return (0a)-(a0); } inline float length(vec3 v){ return sqrtf(v.x*v.xv.y*v.yv.z*v.z); } inline vec3 norm(vec3 v){ float len length(v); if(len 1e-8f) return {0,1,0}; return v/len; } inline float dot(vec3 a,vec3 b){ return a.x*b.xa.y*b.ya.z*b.z; } inline vec3 cross(vec3 a,vec3 b){ return {a.y*b.z-a.z*b.y, a.z*b.x-a.x*b.z, a.x*b.y-a.y*b.x}; } vec2 box(vec3 ro,vec3 rd,vec3 halfSize,vec3 n){ vec3 invvec3(1.0f)/rd; vec3 t1(-ro-halfSize)*inv, t2(-rohalfSize)*inv; vec3 tMin{fminf(t1.x,t2.x),fminf(t1.y,t2.y),fminf(t1.z,t2.z)}; vec3 tMax{fmaxf(t1.x,t2.x),fmaxf(t1.y,t2.y),fmaxf(t1.z,t2.z)}; float tnfmaxf(fmaxf(tMin.x,tMin.y),tMin.z); float tffminf(fminf(tMax.x,tMax.y),tMax.z); if(tntf||tf0.0f)return vec2(-1.0f); if(tMin.xtMin.ytMin.xtMin.z)nvec3(-sign(rd.x),0,0); else if(tMin.ytMin.xtMin.ytMin.z)nvec3(0,-sign(rd.y),0); else nvec3(0,0,-sign(rd.z)); return vec2(tn,tf); } void HideCursor(){ HANDLE HGetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_CURSOR_INFO ci; GetConsoleCursorInfo(H,ci); ci.bVisibleFALSE; SetConsoleCursorInfo(H,ci); } POINT GetConsoleCenter(){ HWND hGetConsoleWindow(); if(!h){POINT c;c.xGetSystemMetrics(SM_CXSCREEN)/2;c.yGetSystemMetrics(SM_CYSCREEN)/2;return c;} RECT wa;SystemParametersInfo(SPI_GETWORKAREA,0,wa,0); int ww(wa.right-wa.left)*0.7, wh(wa.bottom-wa.top)*0.7; MoveWindow(h,(wa.leftwa.right-ww)/2,(wa.topwa.bottom-wh)/2,ww,wh,TRUE); RECT wr;GetWindowRect(h,wr); return {(wr.leftwr.right)/2,(wr.topwr.bottom)/2}; } void GetConsoleSize(HANDLE H, int w, int h){ CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(H, csbi); w csbi.srWindow.Right - csbi.srWindow.Left 1; h csbi.srWindow.Bottom - csbi.srWindow.Top 1; } void FitBufferToWindow(HANDLE H, int w, int h){ COORD bufSize { (SHORT)w, (SHORT)h }; SetConsoleScreenBufferSize(H, bufSize); SMALL_RECT windowRect { 0, 0, (SHORT)(w-1), (SHORT)(h-1) }; SetConsoleWindowInfo(H, TRUE, windowRect); } struct BoxCol{ vec3 c; vec3 hs; }; const float PR0.4f; const int CI8; std::vectorBoxCol ground, walls; std::mt19937 rng(std::random_device{}()); float nextZ0; float lastWallZ -1e9f; float lastNeoZ -100.0f; int neoCooldown 0; bool neoActive false; const float GRAVITY -18.0f; const float JUMP_VEL 9.5f; const float GROUND_ACC 18.0f; const float AIR_ACC 0.5f; const float MAX_SPEED 8.0f; const float GROUND_FRICT 12.0f; const float AIR_FRICT 0.5f; const float WALL_BOUNCE 0.2f; const float WALL_BRAKE 1.00f; const float MIN_WALL_GAP 3.0f; const size_t MAX_OBJECTS 300; void resolveSphereBox(vec3 p, vec3 vel, float r, const BoxCol b, float bounce0.0f, bool isWallfalse){ vec3 cl; cl.xclamp(p.x, b.c.x-b.hs.x, b.c.xb.hs.x); cl.yclamp(p.y, b.c.y-b.hs.y, b.c.yb.hs.y); cl.zclamp(p.z, b.c.z-b.hs.z, b.c.zb.hs.z); vec3 d p-cl; float l length(d); if(l r){ vec3 n; if(l 0.001f){ vec3 tc p - b.c; float ax fabsf(tc.x), ay fabsf(tc.y), az fabsf(tc.z); if(ax ay ax az) n vec3(sign(tc.x), 0, 0); else if(ay ax ay az) n vec3(0, sign(tc.y), 0); else n vec3(0, 0, sign(tc.z)); if(length(n) 0.5f) n vec3(0,1,0); n norm(n); } else { n d / l; } p cl n * r; float vdotn dot(vel, n); if(vdotn 0){ vel vel - (1.0fbounce)*vdotn * n; if(isWall fabs(n.y) 0.1f){ vel.x * WALL_BRAKE; vel.z * WALL_BRAKE; } } } } void resolveAll(vec3 p, vec3 vel){ for(int i0;iCI;i){ for(autog:ground) resolveSphereBox(p,vel,PR,g,0.0f, false); for(autow:walls) resolveSphereBox(p,vel,PR,w,WALL_BOUNCE, true); } } bool onGround(const vec3 p, const vec3 vel){ vec3 tp; t.y - PR0.05f; for(autog:ground){ vec3 c;c.xclamp(t.x,g.c.x-g.hs.x,g.c.xg.hs.x); c.yclamp(t.y,g.c.y-g.hs.y,g.c.yg.hs.y); c.zclamp(t.z,g.c.z-g.hs.z,g.c.zg.hs.z); if(length(t-c)PR) return true; } return false; } void clearScene(){ ground.clear(); walls.clear(); nextZ0; lastWallZ -1e9f; lastNeoZ -100.0f; neoCooldown 0; neoActive false; } void genUntil(float targetZ){ std::uniform_real_distributionfloat gap(0,1), wallCh(0,1), wallH(0.8f,2.5f), wallT(0.25f,0.45f); while(nextZ targetZ ground.size() walls.size() MAX_OBJECTS){ if (neoCooldown 0 gap(rng) 0.05f nextZ - lastNeoZ 15.0f) { neoActive true; lastNeoZ nextZ; } if (neoActive) { float frontZ nextZ - 1.0f; bool hasFront false; for (auto g : ground) { if (g.c.z frontZ g.c.z frontZ 1.0f) { hasFront true; break; } } if (!hasFront) { ground.push_back({ vec3(0, -0.5f, frontZ 0.5f), {1.5f, 0.5f, 0.5f} }); } for (int i 0; i 1; i) { float wallZ nextZ 0.5f i; float h 10.0f; float t 0.1f; walls.push_back({vec3(0, h*0.5f, wallZ), {1.45f, h*0.5f, t*0.5f}}); lastWallZ wallZ; ground.push_back({vec3(0, -0.5f, wallZ), {1.5f, 0.5f, 0.5f}}); } float backZ nextZ 1.0f; bool hasBack false; for (auto g : ground) { if (g.c.z backZ g.c.z backZ 1.0f) { hasBack true; break; } } if (!hasBack) { ground.push_back({ vec3(0, -0.5f, backZ 0.5f), {1.5f, 0.5f, 0.5f} }); } nextZ 3; neoActive false; neoCooldown 20; continue; } if (neoCooldown 0) neoCooldown--; if(gap(rng) 0.22f){ nextZ 1.0f; continue; } ground.push_back({vec3(0, -0.5f, nextZ0.5f), {1.5f, 0.5f, 0.5f}}); if(wallCh(rng) 0.32f){ float newWallZ nextZ0.5f; if(newWallZ - lastWallZ MIN_WALL_GAP){ float h wallH(rng); float t wallT(rng); walls.push_back({vec3(0, h*0.5f, newWallZ), {1.45f, h*0.5f, t*0.5f}}); lastWallZ newWallZ; } } nextZ 1.0f; } } void updateScene(const vec3 pp){ if(!std::isfinite(pp.x) || !std::isfinite(pp.y) || !std::isfinite(pp.z)){ clearScene(); return; } float cl pp.z - 45.0f; ground.erase(std::remove_if(ground.begin(), ground.end(), [cl](BoxCol g){ return g.c.z cl; }), ground.end()); walls.erase(std::remove_if(walls.begin(), walls.end(), [cl](BoxCol w){ return w.c.z cl; }), walls.end()); genUntil(pp.z 18.0f); } float g_bestDist 0.0f; const char* HIGHSCORE_FILE highscore.dat; void loadHighScore() { std::ifstream ifs(HIGHSCORE_FILE); if (ifs.is_open()) { ifs g_bestDist; ifs.close(); } } void saveHighScore(float newDist) { if (newDist g_bestDist) { g_bestDist newDist; std::ofstream ofs(HIGHSCORE_FILE); if (ofs.is_open()) { ofs g_bestDist; ofs.close(); } } } void writeHUD(wchar_t* buffer, int screenW, float dist, float bestDist, bool dead, float sprintTimer, float sprintCooldown) { wchar_t line[240]; const wchar_t* stateStr L; if (sprintTimer 0.0f) stateStr L[SPRINT!]; else if (sprintCooldown 0.0f) { swprintf(line, 240, L[COOL:%.1f], sprintCooldown); stateStr line; } else stateStr L[READY]; int len swprintf(line, 240, L Distance: %.0f m Best: %.0f m %s %s, dist, bestDist, dead ? LDEAD : L, stateStr); for (int i 0; i screenW; i) { if (i len) buffer[i] line[i]; else buffer[i] L ; } } int main(){ HideCursor(); HANDLE HCreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE,0,NULL,CONSOLE_TEXTMODE_BUFFER,NULL); SetConsoleActiveScreenBuffer(H); int w, h; Sleep(100); GetConsoleSize(H, w, h); if (w 0 || h 0) { w 240; h 60; } FitBufferToWindow(H, w, h); float asp(float)w/h; float pa 0.4583f; char grad[] .:!/r(l1Z4H9W8$; int gssizeof(grad)-2; wchar_t* scrnew wchar_t[w*h]; DWORD dw0; POINT cGetConsoleCenter(); SetCursorPos(c.x,c.y); ground.reserve(256); walls.reserve(128); loadHighScore(); vec3 pos(0, 1.5f, -8); vec3 vel(0,0,0); float yaw0.0f, pitch0, ms0.0025f; bool grounded false; enum{PLAYING,LOST} stPLAYING; bool runtrue; auto ltstd::chrono::steady_clock::now(); vec3 ldnorm(vec3(-0.5f, 0.8f, -1.0f)); clearScene(); nextZ pos.z; lastWallZ -1e9f; genUntil(pos.z18.f); float sprintTimer 0.0f; float sprintCooldown 0.0f; int frameCounter 0; while(run){ auto ntstd::chrono::steady_clock::now(); float dtstd::chrono::durationfloat(nt-lt).count(); ltnt; if(dt0.033f) dt0.033f; if(GetAsyncKeyState(VK_ESCAPE)0x8000) runfalse; if(GetAsyncKeyState(R)0x8000){ float curDist pos.z 8.0f; if (curDist g_bestDist) saveHighScore(curDist); posvec3(0,1.5f,-8); velvec3(0,0,0); yaw0.0f; pitch0; stPLAYING; clearScene(); nextZpos.z; lastWallZ -1e9f; genUntil(pos.z18.f); sprintTimer 0.0f; sprintCooldown 0.0f; } POINT mp; GetCursorPos(mp); int dxmp.x-c.x, dymp.y-c.y; if(dx||dy){ if(stPLAYING){ yaw - dx*ms; pitch - dy*ms; pitchclamp(pitch,-1.4f,1.4f); } SetCursorPos(c.x,c.y); } vec3 fwd(cosf(pitch)*sinf(yaw), sinf(pitch), cosf(pitch)*cosf(yaw)); vec3 rgtnorm(cross(fwd,vec3(0,1,0))); vec3 upcross(rgt,fwd); updateScene(pos); if(stPLAYING){ vec3 moveDir(0,0,0); if(GetAsyncKeyState(W)0x8000) moveDir moveDir vec3(fwd.x,0,fwd.z); if(GetAsyncKeyState(S)0x8000) moveDir moveDir - vec3(fwd.x,0,fwd.z); if(GetAsyncKeyState(A)0x8000) moveDir moveDir - rgt; if(GetAsyncKeyState(D)0x8000) moveDir moveDir rgt; float lenM length(moveDir); if(lenM0.001f) moveDir moveDir/lenM; else moveDirvec3(0,0,0); grounded onGround(pos, vel); if (sprintTimer 0) { sprintTimer - dt; if (sprintTimer 0) sprintTimer 0.0f; } if (sprintCooldown 0) { sprintCooldown - dt; if (sprintCooldown 0) sprintCooldown 0.0f; } if ((GetAsyncKeyState(VK_LSHIFT) 0x8000) || (GetAsyncKeyState(VK_RSHIFT) 0x8000)) { if (sprintTimer 0.0f sprintCooldown 0.0f grounded) { sprintTimer 0.6f; sprintCooldown 1.2f; } } float currentMaxSpeed MAX_SPEED; float currentGroundAcc GROUND_ACC; if (sprintTimer 0.0f) { currentMaxSpeed MAX_SPEED * 2.0f; currentGroundAcc GROUND_ACC * 1.5f; } float accScale grounded ? currentGroundAcc : AIR_ACC; vec3 acc moveDir * accScale; acc.y GRAVITY; vel vel acc * dt; if(!grounded){ vel.x * (1.0f - AIR_FRICT*dt); vel.z * (1.0f - AIR_FRICT*dt); }else{ float spdHor sqrtf(vel.x*vel.x vel.z*vel.z); if(spdHor 0.01f){ float newSpd fmaxf(0.0f, spdHor - GROUND_FRICT*dt); vel.x * newSpd/spdHor; vel.z * newSpd/spdHor; }else vel.xvel.z0; } float horSpeed sqrtf(vel.x*vel.x vel.z*vel.z); if(horSpeed currentMaxSpeed){ vel.x * currentMaxSpeed/horSpeed; vel.z * currentMaxSpeed/horSpeed; } if(GetAsyncKeyState(VK_SPACE)0x8000 grounded){ vel.y JUMP_VEL; grounded false; } vec3 newPos pos vel * dt; resolveAll(newPos, vel); pos newPos; grounded onGround(pos, vel); if(grounded vel.y 0) vel.y 0; if(pos.y -5.0f) { st LOST; float curDist pos.z 8.0f; if (curDist g_bestDist) saveHighScore(curDist); } if(!std::isfinite(pos.x) || !std::isfinite(pos.y) || !std::isfinite(pos.z)){ posvec3(0,1.5f,-8); velvec3(0,0,0); yaw0.0f; pitch0; stPLAYING; clearScene(); nextZpos.z; lastWallZ-1e9f; genUntil(pos.z18.f); sprintTimer sprintCooldown 0.0f; } } float dist pos.z 8.0f; if(dist 0) dist 0; if(frameCounter % 10 0){ std::string titlestPLAYING ? 无尽跑酷 | NEO挑战 | 距离:std::to_string((int)dist)m | R重置 : 坠落! 距离:std::to_string((int)dist)m | R重新开始; SetConsoleTitleA(title.c_str()); } CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(H, csbi); int visW csbi.srWindow.Right - csbi.srWindow.Left 1; int visH csbi.srWindow.Bottom - csbi.srWindow.Top 1; int left csbi.srWindow.Left; int top csbi.srWindow.Top; if (visW ! w || visH ! h) { w visW; h visH; FitBufferToWindow(H, w, h); delete[] scr; scr new wchar_t[w * h]; asp (float)w / h; } float viewZ pos.z; for(int i0;iw;i){ for(int j0;jh;j){ vec2 uv((float)i/w,(float)j/h); uvuv*2.f-1.f; uv.x*asp*pa; uv.y*-1; vec3 rdnorm(fwd rgt*uv.x up*uv.y); float tmin1e9f; vec3 n; float alb1; bool hitfalse; for(autog:ground){ if(g.c.z viewZ - 1.5f) continue; vec3 bn; vec2 tbox(pos-g.c, rd, g.hs, bn); if(t.x0 t.xtmin){ tmint.x; nbn; alb0.75f; hittrue; } } for(autow:walls){ if(w.c.z viewZ - 1.5f) continue; vec3 bn; vec2 tbox(pos-w.c, rd, w.hs, bn); if(t.x0 t.xtmin){ tmint.x; nbn; alb1.0f; hittrue; } } float diff0; if(hit){ float amb0.2f, ndlfmaxf(0.f,dot(n,ld)); diff(ambndl)*alb; diffclamp(diff,0.f,1.f); } int idx(int)(diff*gs); idx(int)clamp((float)idx,0.0f,(float)gs); scr[ij*w]grad[idx]; } } writeHUD(scr, w, dist, g_bestDist, st LOST, sprintTimer, sprintCooldown); for (int j 0; j h; j) { COORD pos { (SHORT)left, (SHORT)(top j) }; DWORD written; WriteConsoleOutputCharacterW(H, scr j * w, w, pos, written); int bufW csbi.dwSize.X; if (bufW left w) { int clearLen bufW - (left w); std::wstring spaces(clearLen, L ); COORD fillPos { (SHORT)(left w), (SHORT)(top j) }; WriteConsoleOutputCharacterW(H, spaces.c_str(), clearLen, fillPos, written); } } } saveHighScore(pos.z 8.0f); delete[]scr; CloseHandle(H); return 0; }编译时加入命令-stdc11 -lpthread -O3 -fopenmp