2025-12-21 19:33:00 [显示全部楼层]
16浏览
查看: 16|回复: 0

[项目分享] 俄罗斯方块!!!(C++)

[复制链接]
终于制作好了
#include<iostream>
#include<vector>
#include<Windows.h>
#include<graphics.h>
#include<string>
#include<conio.h>
#include<chrono>
//#pragma comment(lib, "libcpmtd.lib")//Debug
#pragma comment(lib, "libcpmt.lib")//Release
#ifdef _WIN32
bool is_WIN32 = true,k=true,pibm=false;
int _width, _height, BLOCK_SIZE;
std::vector<std::vector<int>>game_interface;
const std::vector<std::vector<std::vector<bool>>> BLOCK{
        // 0: ':.
        {
                {1, 1, 0},
                {0, 1, 1}
        },
        // 1: .:'
        {
                {0, 1, 1},
                {1, 1, 0}
        },
        // 2: :
        //    :
        {
                {1},
                {1},
                {1},
                {1}
        },
        // 3: ::
        {
                {1, 1},
                {1, 1}
        },
        // 4: .:.
        {
                {0, 1, 0},
                {1, 1, 1}
        },
        // 5: ..:
        {
                {0, 0, 1},
                {1, 1, 1}
        },
        // 6: :..
        {
                {1, 0, 0},
                {1, 1, 1}
        }
};
const std::vector<COLORREF>block_color{
RGB(255, 0, 0),//红
RGB(255, 255, 0),//黄

RGB(0, 255, 0),//绿
RGB(0, 255, 255),//青

RGB(0, 0, 255),//蓝
RGB(255, 0, 255)//粉
};
int ran, lran, ll;
#elif
bool is_WIN32 = false;
#endif

//TODO:解决BLOCK[5]:..,BLOCK[6]..:的旋转小问题
static void input_width_or_height(int* _input, const bool IS_HEIGHT) {
        while (true) {
                std::string input_str;
                if (IS_HEIGHT) {
                        std::wcout << "\n请输入游戏高度(大于9):";
                }
                else {
                        std::wcout << "\n请输入游戏宽度(大于9):";
                }
                std::cin >> input_str;

                try {
                        int input_val = stoi(input_str);
                        if (input_val < 10) {
                                std::wcout << "\n数值必须大于9!\n";
                                continue;
                        }
                        int max_val = GetSystemMetrics(IS_HEIGHT) - IS_HEIGHT ? 300 : 100;
                        if (input_val > max_val) {
                                std::wcout << "\n数值过大,最大为" << max_val << "!\n";
                                continue;
                        }
                        *_input = input_val;
                        break;
                }
                catch (std::out_of_range) {
                        std::wcout << "\n数值超出范围!\n";
                }
                catch (...) {
                        std::wcout << "\n请输入有效数字!\n";
                }
        }
}
static void print_interface(const int TIMES, const int SCORE, const int LEVEL, const bool IS_RAN = false) {
        cleardevice();
        int x, y;
        if (TIMES > 0) {
                const std::vector<std::vector<bool>>WATING = BLOCK[lran];
                setfillcolor(block_color[(TIMES - IS_RAN) % 6]);
                for (y = 0; y < WATING.size(); y++) {
                        for (x = 0; x < WATING[0].size(); x++) {
                                if (WATING[y][x]) {
                                        fillrectangle(BLOCK_SIZE * _width + 25 + 25 * x, 25 + 25 * y, BLOCK_SIZE * _width + 50 + 25 * x, 50 + 25 * y);
                                }
                        }
                }
                if (IS_RAN) {
                        lran = ran;
                        ran = rand() % 7;
                }
        }
        outtextxy(BLOCK_SIZE * _width + 25, 125, L"分数:");
        outtextxy(BLOCK_SIZE * _width + 85, 125, std::to_wstring(SCORE).c_str());
        outtextxy(BLOCK_SIZE * _width + 25, 150, L"等级:");
        outtextxy(BLOCK_SIZE * _width + 85, 150, std::to_wstring((LEVEL < 0) ? ll : LEVEL).c_str());
        ll = LEVEL;
        setcolor(DARKGRAY);
        for (y = 0; y <= _height; y++) {//画横线
                line(0, y * BLOCK_SIZE, BLOCK_SIZE * _width, y * BLOCK_SIZE);
        }
        for (x = 0; x < _width + 1; x++) {//画竖线
                line(x * BLOCK_SIZE, BLOCK_SIZE * _height, x * BLOCK_SIZE, 0);
        }
        for (y = 0; y < _height; y++) {
                for (x = 0; x < _width; x++) {
                        if (game_interface[y][x] > 0) {
                                setfillcolor(block_color.at((game_interface[y][x] - 1) % 6));
                                setcolor(block_color.at((game_interface[y][x] - 1) % 6));
                                fillrectangle(x * BLOCK_SIZE, y * BLOCK_SIZE, (x + 1) * BLOCK_SIZE, (y + 1) * BLOCK_SIZE);
                                setcolor(WHITE);
                                const unsigned short this_block_value = game_interface[y][x];
                                //描边↓
                                //上
                                if (y == _height - 1) {
                                        line(x * BLOCK_SIZE, (y + 1) * BLOCK_SIZE, (x + 1) * BLOCK_SIZE, (y + 1) * BLOCK_SIZE);
                                }
                                else if (game_interface[y + 1][x] != this_block_value) {
                                        line(x * BLOCK_SIZE, (y + 1) * BLOCK_SIZE, (x + 1) * BLOCK_SIZE, (y + 1) * BLOCK_SIZE);
                                }
                                //下
                                if (y == 0) {
                                        line(x * BLOCK_SIZE, y * BLOCK_SIZE, (x + 1) * BLOCK_SIZE, y * BLOCK_SIZE);
                                }
                                else if (game_interface[y - 1][x] != this_block_value) {
                                        line(x * BLOCK_SIZE, y * BLOCK_SIZE, (x + 1) * BLOCK_SIZE, y * BLOCK_SIZE);
                                }
                                //左
                                if (x == 0) {
                                        line(x * BLOCK_SIZE, (y + 1) * BLOCK_SIZE, x * BLOCK_SIZE, y * BLOCK_SIZE);
                                }
                                else if (game_interface[y][x - 1] != this_block_value) {
                                        line(x * BLOCK_SIZE, (y + 1) * BLOCK_SIZE, x * BLOCK_SIZE, y * BLOCK_SIZE);
                                }
                                //右
                                if (x == _width - 1) {
                                        line((x + 1) * BLOCK_SIZE, (y + 1) * BLOCK_SIZE, (x + 1) * BLOCK_SIZE, y * BLOCK_SIZE);
                                }
                                else if (game_interface[y][x + 1] != this_block_value) {
                                        line((x + 1) * BLOCK_SIZE, (y + 1) * BLOCK_SIZE, (x + 1) * BLOCK_SIZE, y * BLOCK_SIZE);
                                }
                        }
                }
        }
}
static void put_in_block(int* status, const int TIMES) {
        const int x = _width / 2 - (BLOCK[lran][0].size()) / 2;
        const std::vector<std::vector<bool>>WATING = BLOCK[lran];//暂存形状
        pibm = (lran == 6 || lran == 5);
        for (int ty = 0; ty < WATING.size(); ty++) {
                for (int tx = x; tx - x < WATING[0].size(); tx++) {
                        if (WATING[ty][tx - x]) {
                                if (game_interface[ty][tx] == 0) {
                                        game_interface[ty][tx] = TIMES;
                                }
                                else {
                                        *status = -1;
                                        return;
                                }
                        }
                }
        }
        *status = 0;
}
static void block_moves(const int MODE, int* status, int* times, int* score, int* erased_line, bool add_s_s_t = false, const bool FASTLY_DOWN = false ,const bool s = false) {
        std::vector<std::vector<int>>coords{ {},{} };
        int i, x, y;
        //下落 MODE==0
        if (!MODE) {
                //收集//下落判断
                for (y = 0; y < _height; y++) {
                        for (x = 0; x < _width; x++) {
                                if (game_interface[y][x] == *times) {
                                        if (y == _height - 1) {
                                                if (add_s_s_t) {
                                                        *status = 1;
                                                        *times++;
                                                }
                                                return;
                                        }
                                        else {
                                                if ((game_interface[y + 1][x] != 0 &&
                                                        game_interface[y + 1][x] != *times)) {
                                                        if (add_s_s_t) {
                                                                *status = 1;
                                                                *times++;
                                                        }
                                                        return;
                                                }
                                        }
                                        coords[0].push_back(x);
                                        coords[1].push_back(y);
                                }
                        }
                }
                //执行
                for (i = 0; i < coords[0].size(); i++) {
                        game_interface[coords[1][i]][coords[0][i]] = 0;
                }
                for (i = 0; i < coords[0].size(); i++) {
                        game_interface[coords[1][i] + 1][coords[0][i]] = *times;
                }
                if (FASTLY_DOWN) {
                        if (add_s_s_t) {
                                *score += 5;
                        }
                        if (s) {
                                block_moves(0, &*status, &*times, &*score, &*erased_line, add_s_s_t, true, true);
                        }
                }
        }
        //旋转 MODE==2
        else if (MODE == 2) {
                //收集
                for (y = 0; y < _height; y++) {
                        for (x = 0; x < _width; x++) {
                                if (game_interface[y][x] == *times) {
                                        coords[0].push_back(y);
                                        coords[1].push_back(x);
                                }
                                if (coords[0].size() == 4) {
                                        break;
                                }
                        }
                        if (coords[0].size() == 4) {
                                break;
                        }
                }
                //确定质心
                std::vector<int>centroid{ 0,0 };
                for (i = 0; i < 4; i++) {
                        centroid[0] += coords[0][i];
                        centroid[1] += coords[1][i];
                }
                centroid[0] /= 4;
                centroid[1] /= 4;
                const bool x_correct = pibm||((coords[1][3] - coords[1][0]) % 2);
                //判断
                for (i = 0; i < 4; i++) {
                        const int cx = centroid[1] - coords[0][i] + centroid[0] + x_correct+pibm, cy = centroid[0] + coords[1][i] - centroid[1];
                        if (-1 < cx && cx < _width && -1 < cy && cy < _height) {
                                if (game_interface[cy][cx] != 0 && game_interface[cy][cx] != *times) {
                                        *status = 1;
                                        *times++;
                                        return;
                                }
                        }
                        else {
                                return;
                        }
                }
                //执行
                for (i = 0; i < 4; i++) {
                        game_interface[coords[0][i]][coords[1][i]] = 0;
                }
                for (i = 0; i < 4; i++) {
                        game_interface[centroid[0] + coords[1][i] - centroid[1]][centroid[1] - coords[0][i] + centroid[0] + x_correct] = *times;
                }
                block_moves(0, &*status, &*times, &*score, &*erased_line, true);
        }
        //平移 MODE==±1
        else {
                //收集//判断
                for (x = 0; x < _width; x++) {
                        for (y = 0; y < _height; y++) {
                                if (game_interface[y][x] == *times) {
                                        if ((MODE == -1) ? (x == 0) : (x == _width - 1)) {
                                                return;
                                        }
                                        else if (game_interface[y][x + MODE] != *times && game_interface[y][x + MODE] != 0) {
                                                block_moves(0, &*status, &*times, &*score, &*erased_line, true);
                                                return;
                                        }
                                        coords[0].push_back(x);
                                        coords[1].push_back(y);
                                }
                        }
                }
                //执行
                for (i = 0; i < 4; i++) {
                        game_interface[coords[1][i]][coords[0][i]] = 0;

                }
                for (i = 0; i < 4; i++) {
                        game_interface[coords[1][i]][coords[0][i] + MODE] = *times;
                }
                block_moves(0, &*status, &*times, &*score, &*erased_line, true);
        }
}
static void clear_line(int* erased_line, int* score) {
        std::vector<int> erase_list, fall_block;
        erase_list.reserve(4);
        fall_block.reserve(_width);
        int y, x;
        for (y = _height - 1; y >= 0; y--) {
                bool is_full = true;
                for (x = 0; x < _width; x++) {
                        if (game_interface[y][x] == 0) {
                                is_full = false;
                                break;
                        }
                }
                if (is_full) {
                        erase_list.emplace_back(y);
                        for (const int tx : game_interface[y]) {
                                bool _find = false;
                                for (const int i : fall_block) {
                                        _find = (tx == i);
                                        if (_find) {
                                                break;
                                        }
                                }
                                if (!_find) {
                                        fall_block.emplace_back(tx);
                                }
                        }
                        *erased_line++;
                }
        }
        if (!erase_list.empty()) {
                switch (erase_list.size()) {
                case 1:
                        *score += 100;
                        break;
                case 2:
                        *score += 200;
                        break;
                case 3:
                        *score += 400;
                        break;
                default:
                        *score += 800;
                        break;
                }
                for (y = 0; y < erase_list.size(); y++) {
                        for (x = 0; x < _width; x++) {
                                game_interface[erase_list[y]][x] = 0;
                        }
                }
                std::cout << 0;
                print_interface(0, *score, *erased_line / 10);
                for (int y : erase_list) {
                        game_interface.erase(game_interface.begin() + y);
                }
                for (int y : erase_list) {
                        game_interface.insert(game_interface.begin(), std::vector<int>(_width, 0));
                }
                fall_block.pop_back();
                for (int i : fall_block) {
                        block_moves(0, nullptr, &i, nullptr, &*erased_line, false, true);
                }
                Sleep(300);
                print_interface(0, *score, *erased_line / 10);
        }
}
int main() {
        if (is_WIN32) {
                std::wcout << "(游戏结束后按esc退出)\n上键:逆时针旋转方块\n下键:加速游戏\n\n左键:方块左移\n右键:方块右移\ns:方块直接下落        (英文输入法!!!)\n";
                input_width_or_height(&_height, true);
                input_width_or_height(&_width, false);
                //判断方块尺寸用
                if ((GetSystemMetrics(SM_CYSCREEN) - 100) > _height * 30 && (GetSystemMetrics(SM_CXSCREEN) - 100) > _width * 30) {
                        BLOCK_SIZE = 30;
                }
                else if ((GetSystemMetrics(SM_CYSCREEN) - 100) / _height > (GetSystemMetrics(SM_CXSCREEN) - 100) / _width) {
                        BLOCK_SIZE = (GetSystemMetrics(SM_CXSCREEN) - 100) / _width;
                }
                else {
                        BLOCK_SIZE = (GetSystemMetrics(SM_CYSCREEN) - 100) / _height;
                }
                initgraph(BLOCK_SIZE * _width + 200, BLOCK_SIZE * _height);
                game_interface.resize(_height);
                for (int y = 0; y < _height; ++y) {
                        game_interface[y].resize(_width, 0);
                }
                int times = 0, score = 0, erased_line = 0;
                int status = 1;//1:允许 0:不允许【(已有方块下落中)不得同时出现两个方块】 -1:添加失败(游戏结束)
                bool speed_up = false, lks = false;
                srand(time(0));
                ran = rand() % 7;
                print_interface(times, score, erased_line / 10, true);
                setfont(20, 10, L"黑体");
                //主循环
                while (true) {
                        bool ks = false;
                        int key = 0;
                        if (_kbhit()) {
                                ks = true;
                                key = _getch();
                                if (key == 's') {
                                        block_moves(0, &status, &times, &score, &erased_line, true, true, true);
                                }
                                if (key == 0 || key == 0xE0) {
                                        key = _getch();
                                }
                        }
                        if (!lks && ks) {
                                switch (key) {
                                case 0x48:  // 上键
                                        block_moves(2, &status, &times, &score, &erased_line);
                                        speed_up = false;
                                        break;
                                case 0x50:  // 下键
                                        speed_up = true;
                                        break;
                                case 0x4B:  // 左键
                                        block_moves(-1, &status, &times, &score, &erased_line);
                                        speed_up = false;
                                        break;
                                case 0x4D:  // 右键
                                        block_moves(1, &status, &times, &score, &erased_line);
                                        speed_up = false;
                                        break;
                                default:    // 其他按键
                                        speed_up = false;
                                        break;
                                }
                        }
                        if (lks && !ks) {
                                speed_up = false;
                        }
                        lks = ks;
                        if (status == 1) {
                                clear_line(&erased_line, &score);
                                times++;
                                put_in_block(&status, times);
                                print_interface(times, score, erased_line / 10, true);
                        }
                        else if (status == 0) {
                                block_moves(0, &status, &times, &score, &erased_line, true);
                                print_interface(times, score, erased_line / 10);
                        }
                        else {
                                std::wstring result = L"你最终放置了";
                                result += std::to_wstring(times - 1);
                                result += L"个方块,清除了";
                                result += std::to_wstring(erased_line);
                                result += L"行,已暂停游戏(esc退出)";
                                outtext(result.c_str());
                                while (true) {
                                        if (_kbhit()) {
                                                if (_getch() == 27) {
                                                        return 0;
                                                }
                                        }
                                        Sleep(50);
                                }
                        }
                        auto start = std::chrono::high_resolution_clock::now();
                        while (true) {
                                if (_kbhit()|| std::chrono::high_resolution_clock::now()-start> std::chrono::duration<double>(speed_up ? 0.1 : 0.3)) {
                                        break;
                                }
                        }
                }
        }
        else {
                std::wcout << "无法进行游戏,因为此设备的系统非Windows\n";
                Sleep(3000);
        }
}



俄罗斯方块.zip

39.84 KB, 下载次数: 1

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4 备案 沪公网安备31011502402448

© 2013-2025 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail