1、按空格鍵來切換模式(挖掘模式和放置模式),一律用鼠標右鍵來操作!!!?2、按數字1和2鍵來切換放置的方塊(1是草,2是木),樹葉不能放置!!! 3、樹木生成時可能有點BUG。 4、在操作時位置會有點偏移,請見諒。 5、地圖默認大小為20*20,可以自己修改。(第15行和第16行) 6、本程序應該會持續更新
更新日志:
4月25日: 1、更新了新方塊“石”,按數字3鍵切換(沒錯,樹葉依然不可以放置) 2、石頭會生成在草方塊下面,會生成5層。 3、更改了地圖的大小,為25*18。 4、操作偏移的bug依然存在(改了好幾次,結果改的更離譜了)
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
#include <ctime>
#include <windows.h>// 定義方塊類型
typedef int BlockType;// 定義方塊名稱
const std::string BLOCK_NAMES[] = { "", "草", "木", "葉", "石" };// 定義世界的大小
const int WORLD_WIDTH = 25;
const int WORLD_HEIGHT = 18;// 定義世界地圖
class World {
private:std::vector<std::vector<BlockType> > blocks;public:World() {blocks.resize(WORLD_HEIGHT);for (int y = 0; y < WORLD_HEIGHT; ++y) {blocks[y].resize(WORLD_WIDTH, 0);}generateTerrain();generateTrees();}// 生成簡單地形void generateTerrain() {srand(static_cast<unsigned int>(time(NULL)));for (int x = 0; x < WORLD_WIDTH; ++x) {int height = rand() % 3 + 1;// 生成石頭for (int y = WORLD_HEIGHT - 1; y >= WORLD_HEIGHT - 5; --y) {blocks[y][x] = 4;}// 生成草for (int y = WORLD_HEIGHT - 6; y >= WORLD_HEIGHT - 6 - height + 1; --y) {blocks[y][x] = 1;}}}// 生成樹木void generateTrees() {for (int x = 0; x < WORLD_WIDTH; x += 5) { // 每隔 5 個方塊嘗試生成樹木if (rand() % 2 == 0) { // 50% 的概率生成樹木int baseY = WORLD_HEIGHT - 7; // 從可能的最上層草方塊開始找while (baseY >= 0 && blocks[baseY][x] != 1) baseY--; // 找到最上層的草方塊if (baseY > 0) {int treeHeight = rand() % 3 + 3; // 樹高 3 - 5// 生成樹干for (int i = 0; i < treeHeight; ++i) {if (baseY - i >= 0) {blocks[baseY - i][x] = 2;}}// 生成樹葉int leafTop = baseY - treeHeight;for (int dy = -1; dy <= 1; ++dy) {for (int dx = -1; dx <= 1; ++dx) {if (leafTop + dy >= 0 && x + dx >= 0 && x + dx < WORLD_WIDTH) {blocks[leafTop + dy][x + dx] = 3;}}}}}}}// 放置方塊void placeBlock(int x, int y, BlockType block) {if (x >= 0 && x < WORLD_WIDTH && y >= 0 && y < WORLD_HEIGHT) {blocks[y][x] = block;}}// 挖掘方塊void digBlock(int x, int y) {if (x >= 0 && x < WORLD_WIDTH && y >= 0 && y < WORLD_HEIGHT) {blocks[y][x] = 0;}}// 查看方塊BlockType getBlock(int x, int y) {if (x >= 0 && x < WORLD_WIDTH && y >= 0 && y < WORLD_HEIGHT) {return blocks[y][x];}return 0;}// 顯示世界void display(HANDLE hOut) {COORD coord = { 0, 0 };SetConsoleCursorPosition(hOut, coord);for (int y = 0; y < WORLD_HEIGHT; ++y) {for (int x = 0; x < WORLD_WIDTH; ++x) {std::string blockName = BLOCK_NAMES[blocks[y][x]];if (blockName.empty()) {std::cout << " ";} else {std::cout << blockName;if (blockName.length() == 1) {std::cout << " ";}}std::cout << " "; // 方塊之間添加一個空格}std::cout << std::endl;}}
};// 獲取鼠標點擊的坐標并轉換為地圖坐標
void getMouseCoordinates(int& x, int& y) {POINT cursorPos;GetCursorPos(&cursorPos);HWND consoleWindow = GetConsoleWindow();RECT consoleRect;GetWindowRect(consoleWindow, &consoleRect);// 修正鼠標坐標轉換,確保準確對應方塊x = (cursorPos.x - consoleRect.left) / 25;y = (cursorPos.y - consoleRect.top) / 20;if (x < 0) x = 0;if (x >= WORLD_WIDTH) x = WORLD_WIDTH - 1;if (y < 0) y = 0;if (y >= WORLD_HEIGHT) y = WORLD_HEIGHT - 1;
}int main() {World world;BlockType currentBlock = 1; // 初始方塊類型為草bool rightButtonDown = false;bool key1Down = false;bool key2Down = false;bool key3Down = false;bool spaceDown = false;bool isDigging = false; // 初始為放置模式HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);while (true) {// 雙緩沖技術:先移動光標到屏幕左上角world.display(hOut);std::cout << "當前選擇的方塊:" << BLOCK_NAMES[currentBlock] << std::endl;std::cout << "當前模式:" << (isDigging ? "挖掘" : "放置") << std::endl;// 檢測空格鍵切換模式if ((GetAsyncKeyState(VK_SPACE) & 0x8000) && !spaceDown) {isDigging = !isDigging;spaceDown = true;} else if (!(GetAsyncKeyState(VK_SPACE) & 0x8000)) {spaceDown = false;}// 檢測鼠標右鍵if ((GetAsyncKeyState(VK_RBUTTON) & 0x8000) && !rightButtonDown) {int x, y;getMouseCoordinates(x, y);if (isDigging) {world.digBlock(x, y);} else {world.placeBlock(x, y, currentBlock);}rightButtonDown = true;} else if (!(GetAsyncKeyState(VK_RBUTTON) & 0x8000)) {rightButtonDown = false;}// 檢測數字 1 鍵if ((GetAsyncKeyState(0x31) & 0x8000) && !key1Down) {currentBlock = 1;key1Down = true;} else if (!(GetAsyncKeyState(0x31) & 0x8000)) {key1Down = false;}// 檢測數字 2 鍵if ((GetAsyncKeyState(0x32) & 0x8000) && !key2Down) {currentBlock = 2;key2Down = true;} else if (!(GetAsyncKeyState(0x32) & 0x8000)) {key2Down = false;}// 檢測數字 3 鍵if ((GetAsyncKeyState(0x33) & 0x8000) && !key3Down) {currentBlock = 4;key3Down = true;} else if (!(GetAsyncKeyState(0x33) & 0x8000)) {key3Down = false;}if (GetAsyncKeyState(VK_ESCAPE) & 0x8000) { // 按下 ESC 鍵退出break;}Sleep(50);}return 0;
}