#include <iostream> #include <vector> #include <cmath> #include <windows.h> #include <conio.h> #include <fstream> #include <cstring> #include <cstdlib> #include <ctime> using namespace std; const int WORLD_SIZE = 32; const int WORLD_HEIGHT = 16; char world[WORLD_SIZE][WORLD_SIZE][WORLD_HEIGHT]; struct Player { float x, y, z; float pitch, yaw; float v_y; int hp; bool onGround; }p; //多种怪物类型 struct Monster { float x, z; int hp; int maxHp; float speed; char sym; bool alive; }; struct DropItem { float x, z; char blockType; bool exist; }; struct Bullet { float x, y, z; float dx, dy, dz; bool alive; }; //粒子 struct Particle { float x,y,z; float vx,vy,vz; int life; char ch; }; vector<Monster> monsters; vector<DropItem> drops; vector<Bullet> bullets; vector<Particle> particles; //物品栏 const int INV_SIZE = 6; char inventory[INV_SIZE] = {'#', '&', '@', '~', '◇', '◆'}; //草、泥土、石头、沙子、铁矿、钻石 int selectedSlot = 0; float dayTime = 0; //合成配方 //合成:石头@+铁矿◇ = 子弹弹药 bool TryCraft() { bool hasStone=false, hasIron=false; for(int i=0;i<INV_SIZE;i++) { if(inventory[i]=='@') hasStone=true; if(inventory[i]=='◇') hasIron=true; } if(hasStone && hasIron) { //消耗材料 for(int i=0;i<INV_SIZE;i++) { if(inventory[i]=='@') {inventory[i]=0;break;} } for(int i=0;i<INV_SIZE;i++) { if(inventory[i]=='◇') {inventory[i]=0;break;} } //添加钻石弹药 int slot = -1; for(int i=0;i<INV_SIZE;i++) if(inventory[i]==0) {slot=i;break;} if(slot!=-1) inventory[slot]='◆'; return true; } return false; } //生成粒子 void SpawnParticles(float x,float y,float z,char c,int count) { for(int i=0;i<count;i++) { Particle pt; pt.x=x;pt.y=y;pt.z=z; pt.vx=(rand()%100-50)/100.0f; pt.vy=(rand()%100-50)/100.0f; pt.vz=(rand()%100-50)/100.0f; pt.life=20+rand()%20; pt.ch=c; particles.push_back(pt); } } // 初始化世界地形,添加矿石 void InitWorld() { memset(world, 0, sizeof(world)); for(int x=0;x<WORLD_SIZE;x++){ for(int z=0;z<WORLD_SIZE;z++){ int h = (int)(sin(x*0.2f)*cos(z*0.2f)*3 + 4); for(int y=0;y<=h;y++){ if(y == h) world[x][z][y] = '#'; //草 else world[x][z][y] = '&'; //泥土 } //水域 if(x>5 && x<10 && z>5 && z<10){ for(int y=0;y<=2;y++) world[x][z][y] = '='; } //埋矿石 for(int y=0;y<4;y++) { int r = rand()%100; if(r<5) world[x][z][y] = '◇'; //铁矿 else if(r<8) world[x][z][y] = '◆'; //钻石 } } } world[10][10][5] = 'O'; world[10][11][5] = 'O'; srand((unsigned int)time(NULL)); } bool IsSolid(int x,int z,int y){ if(x<0||x>=WORLD_SIZE||z<0||z>=WORLD_SIZE||y<0||y>=WORLD_HEIGHT) return true; if(world[x][z][y] == '=') return false; return world[x][z][y] != 0; } bool IsWater(int x,int z,int y) { if(x<0||x>=WORLD_SIZE||z<0||z>=WORLD_SIZE||y<0||y>=WORLD_HEIGHT) return false; return world[x][z][y] == '='; } void BlockEdit(bool place){ float rayX = p.x, rayY = p.y, rayZ = p.z; float dx = sin(p.yaw)*cos(p.pitch); float dy = sin(p.pitch); float dz = cos(p.yaw)*cos(p.pitch); for(int i=0;i<10;i++){ int bx = (int)rayX; int by = (int)rayY; int bz = (int)rayZ; if(IsSolid(bx,bz,by)){ if(!place) { //挖方块产生粒子 SpawnParticles(bx,by,bz,'.',8); world[bx][bz][by] = 0; } else{ if(by>0) world[bx][bz][by-1] = inventory[selectedSlot]; } break; } rayX += dx*0.5f; rayY += dy*0.5f; rayZ += dz*0.5f; } } int FindEmptyInvSlot() { for(int i=0;i<INV_SIZE;i++) { if(inventory[i]==0) return i; } return -1; } void SpawnDrop(float x, float z, char c) { DropItem d; d.x = x; d.z = z; d.blockType = c; d.exist = true; drops.push_back(d); } void PickupItems() { for(auto &item : drops) { if(!item.exist) continue; float dx = p.x - item.x; float dz = p.z - item.z; float dist = sqrt(dx*dx + dz*dz); if(dist < 1.2f) { int slot = FindEmptyInvSlot(); if(slot != -1) { inventory[slot] = item.blockType; item.exist = false; SpawnParticles(item.x, p.y, item.z, '+',5); } } } } void ShootBullet() { Bullet b; b.x = p.x; b.y = p.y; b.z = p.z; b.dx = sin(p.yaw)*cos(p.pitch); b.dy = sin(p.pitch); b.dz = cos(p.yaw)*cos(p.pitch); b.alive = true; bullets.push_back(b); SpawnParticles(p.x,p.y,p.z,'*',3); } //生成不同类型怪物 void SpawnMonster(int type) { Monster m; m.x = rand()%24 + 4; m.z = rand()%24 + 4; if(type == 0) { m.hp=3; m.maxHp=3; m.speed=0.03f; m.sym='M'; }else if(type ==1) { m.hp=5; m.maxHp=5; m.speed=0.045f; m.sym='X'; }else { m.hp=8; m.maxHp=8; m.speed=0.02f; m.sym='B'; } m.alive = true; monsters.push_back(m); } //保存 void SaveWorld() { ofstream f("world.dat", ios::binary); if(!f) { cout << "存档失败!" << endl; return; } f.write((char*)world, sizeof(world)); f.write((char*)&p, sizeof(p)); int mCnt = monsters.size(); f.write((char*)&mCnt, sizeof(int)); for(auto &m : monsters) { f.write((char*)&m, sizeof(m)); } int dropCnt = drops.size(); f.write((char*)&dropCnt, sizeof(int)); for(auto &d : drops) { f.write((char*)&d, sizeof(d)); } int bulletCnt = bullets.size(); f.write((char*)&bulletCnt, sizeof(int)); for(auto &b : bullets) { f.write((char*)&b, sizeof(b)); } int ptCnt = particles.size(); f.write((char*)&ptCnt, sizeof(int)); for(auto &pt : particles) { f.write((char*)&pt, sizeof(pt)); } f.write((char*)inventory, sizeof(inventory)); f.write((char*)&selectedSlot, sizeof(selectedSlot)); f.write((char*)&dayTime, sizeof(dayTime)); f.close(); cout << "✅ 存档保存成功" << endl; } //读取 void LoadWorld() { ifstream f("world.dat", ios::binary); if(!f) { cout << "❌ 存档不存在!" << endl; return; } f.read((char*)world, sizeof(world)); f.read((char*)&p, sizeof(p)); int mCnt; f.read((char*)&mCnt, sizeof(int)); monsters.clear(); for(int i=0;i<mCnt;i++) { Monster tmp; f.read((char*)&tmp, sizeof(tmp)); monsters.push_back(tmp); } int dropCnt; f.read((char*)&dropCnt, sizeof(int)); drops.clear(); for(int i=0;i<dropCnt;i++) { DropItem tmp; f.read((char*)&tmp, sizeof(tmp)); drops.push_back(tmp); } int bulletCnt; f.read((char*)&bulletCnt, sizeof(int)); bullets.clear(); for(int i=0;i<bulletCnt;i++) { Bullet tmp; f.read((char*)&tmp, sizeof(tmp)); bullets.push_back(tmp); } int ptCnt; f.read((char*)&ptCnt, sizeof(int)); particles.clear(); for(int i=0;i<ptCnt;i++) { Particle tmp; f.read((char*)&tmp, sizeof(tmp)); particles.push_back(tmp); } f.read((char*)inventory, sizeof(inventory)); f.read((char*)&selectedSlot, sizeof(selectedSlot)); f.read((char*)&dayTime, sizeof(dayTime)); f.close(); cout << "✅ 存档读取成功" << endl; } void Render() { system("cls"); const int SCREEN_W = 80; const int SCREEN_H = 24; char screen[SCREEN_H][SCREEN_W]; memset(screen, ' ', sizeof(screen)); float light = (sin(dayTime)+1)/2; for(int w=0;w<SCREEN_W;w++){ float angle = p.yaw - 0.35f + (w/(float)SCREEN_W)*0.7f; for(int d=1;d<20;d+=1){ float rx = p.x + sin(angle)*d; float rz = p.z + cos(angle)*d; int bx = (int)rx; int bz = (int)rz; int h = 0; while(h<WORLD_HEIGHT && IsSolid(bx,bz,h)) h++; float wallH = (h - p.y)/d; int lineH = (int)(wallH * SCREEN_H); int top = SCREEN_H/2 - lineH/2 + (int)(p.pitch*20); if(top<0) top=0; if(top+lineH >= SCREEN_H) lineH = SCREEN_H-top; char ch = world[bx][bz][h-1]; if(light <0.3) ch = ' '; else if(light <0.6) ch = (ch == '=') ? '~' : '.'; for(int y=top;y<top+lineH && y<SCREEN_H;y++){ if(ch!=0) screen[y][w] = ch; } } } //怪物渲染 for(auto &m : monsters){ if(!m.alive) continue; float dx = m.x - p.x; float dz = m.z - p.z; float dist = sqrt(dx*dx+dz*dz); float ang = atan2(dx,dz); float diff = ang - p.yaw; while(diff > 3.14159) diff -= 2*3.14159; while(diff < -3.14159) diff += 2*3.14159; if(fabs(diff)<0.35 && dist<15){ int sx = SCREEN_W/2 + diff*100; int sy = SCREEN_H/2; if(sx>=0 && sx<SCREEN_W) screen[sy][sx] = m.sym; } } //掉落物 for(auto &item : drops){ if(!item.exist) continue; float dx = item.x - p.x; float dz = item.z - p.z; float dist = sqrt(dx*dx+dz*dz); float ang = atan2(dx,dz); float diff = ang - p.yaw; while(diff > 3.14159) diff -= 2*3.14159; while(diff < -3.14159) diff += 2*3.14159; if(fabs(diff)<0.35 && dist<15){ int sx = SCREEN_W/2 + diff*100; int sy = SCREEN_H/2 + 2; if(sx>=0 && sx<SCREEN_W) screen[sy][sx] = item.blockType; } } //子弹 for(auto &b : bullets) { if(!b.alive) continue; float dx = b.x - p.x; float dz = b.z - p.z; float dist = sqrt(dx*dx+dz*dz); float ang = atan2(dx,dz); float diff = ang - p.yaw; while(diff > 3.14159) diff -= 2*3.14159; while(diff < -3.14159) diff += 2*3.14159; if(fabs(diff)<0.35 && dist<15){ int sx = SCREEN_W/2 + diff*100; int sy = SCREEN_H/2 -1; if(sx>=0 && sx<SCREEN_W) screen[sy][sx] = '*'; } } //粒子渲染 for(auto &pt : particles) { if(pt.life <=0) continue; float dx = pt.x - p.x; float dz = pt.z - p.z; float dist = sqrt(dx*dx+dz*dz); float ang = atan2(dx,dz); float diff = ang - p.yaw; while(diff > 3.14159) diff -= 2*3.14159; while(diff < -3.14159) diff += 2*3.14159; if(fabs(diff)<0.35 && dist<15){ int sx = SCREEN_W/2 + diff*100; int sy = SCREEN_H/2; if(sx>=0 && sx<SCREEN_W) screen[sy][sx] = pt.ch; } } //输出画面 for(int y=0;y<SCREEN_H;y++){ for(int x=0;x<SCREEN_W;x++) cout << screen[y][x]; cout << endl; } cout << "HP:" << p.hp << " | 昼夜:" << (sin(dayTime)>0?"白天":"夜晚") << " | X:"<<p.x<<" Z:"<<p.z<<" | "; cout << "物品栏["; for(int i=0;i<INV_SIZE;i++){ if(i == selectedSlot) cout << "[" << inventory[i] << "]"; else cout << " " << inventory[i] << " "; } cout << "]" << endl; cout << "1** 2放置 | S保存 L读取 | WASD空格 ↑↓视角 | 0~5切换物品 | J射击 | K刷普通怪 U刷快速怪 I刷厚血怪 | C合成" << endl; } void Update() { dayTime += 0.008f; if(dayTime > 2*3.14159f) dayTime = 0; float speed = 0.08f; if(_kbhit()){ char key = _getch(); switch(key){ case 'w': p.x += sin(p.yaw)*speed; p.z += cos(p.yaw)*speed; break; case 's': p.x -= sin(p.yaw)*speed; p.z -= cos(p.yaw)*speed; break; case 'a': p.yaw -= 0.06f; break; case 'd': p.yaw += 0.06f; break; case ' ': if(IsWater((int)p.x,(int)p.z,(int)p.y)){ p.v_y = 0.1f; SpawnParticles(p.x,p.y,p.z,'~',4); }else if(p.onGround) {p.v_y = 0.22f; p.onGround=false;} break; case 72: p.pitch +=0.04f; break; case 80: p.pitch -=0.04f; break; case '1': BlockEdit(false); break; case '2': BlockEdit(true); break; case 's': SaveWorld(); break; case 'l': LoadWorld(); break; case '0': selectedSlot=0; break; case '1': selectedSlot=1; break; case '2': selectedSlot=2; break; case '3': selectedSlot=3; break; case '4': selectedSlot=4; break; case '5': selectedSlot=5; break; case 'j': ShootBullet(); break; case 'k': SpawnMonster(0); break; case 'u': SpawnMonster(1); break; case 'i': SpawnMonster(2); break; case 'c': TryCraft(); break; } } //重力浮力 if(IsWater((int)p.x,(int)p.z,(int)p.y)) p.v_y -= 0.004f; else p.v_y -= 0.012f; p.y += p.v_y; p.onGround = false; if(IsSolid((int)p.x,(int)p.z,(int)p.y)){ p.y -= p.v_y; p.v_y = 0; p.onGround = true; } PickupItems(); //更新粒子 for(auto &pt : particles) { pt.x += pt.vx; pt.y += pt.vy; pt.z += pt.vz; pt.life--; } //清理**亡粒子 vector<Particle> newPt; for(auto &pt : particles) if(pt.life>0) newPt.push_back(pt); particles.swap(newPt); //更新子弹 for(auto &b : bullets) { if(!b.alive) continue; b.x += b.dx*0.3f; b.y += b.dy*0.3f; b.z += b.dz*0.3f; int bx=(int)b.x,by=(int)b.y,bz=(int)b.z; if(IsSolid(bx,bz,by)){ b.alive = false; SpawnParticles(b.x,b.y,b.z,'*',6); continue; } for(auto &m : monsters) { if(!m.alive) continue; float dx = b.x - m.x; float dz = b.z - m.z; float dist = sqrt(dx*dx+dz*dz); if(dist < 0.8f) { m.hp--; b.alive = false; SpawnParticles(m.x,p.y,m.z,'!',8); if(m.hp <= 0) { m.alive = false; SpawnDrop(m.x,m.z,'@'); } } } } //清理**亡子弹 vector<Bullet> newBul; for(auto &b : bullets) if(b.alive) newBul.push_back(b); bullets.swap(newBul); //怪物AI for(auto &m : monsters){ if(!m.alive) continue; float dx = p.x - m.x; float dz = p.z - m.z; float dist = sqrt(dx*dx+dz*dz); if(dist>1.5f){ m.x += dx/dist * m.speed; m.z += dz/dist * m.speed; }else{ p.hp--; if(p.hp <=0){ cout << "游戏结束!" << endl; system("pause"); exit(0); } } } } int main() { InitWorld(); p = {16, 8, 16, 0,0,0,10,true}; monsters.push_back({20,16,3,3,0.03f,'M',true}); monsters.push_back({12,18,5,5,0.045f,'X',true}); while(true){ Render(); Update(); Sleep(40); } return 0; }
