setlinestyle(j,0,3)

本文通过C语言示例代码展示了如何使用graphics.h库初始化绘图环境,并设置不同的线条样式来绘制水平线,以此演示基本的图形输出功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include < graphics.h > 
#include < stdio.h > 
int main() {
    int i,
    j;
    int graphdriver = DETECT;
    int graphmode;
    initgraph( & graphdriver, &graphmode, "");
    cleardevice();
    for (i = 0; i < 4; i++) {
        setlinestyle(i, 0, 1);
        line(0, (i + 1) * 10, getmaxx(), (i + 1) * 10);
    }
    for (j = 0; j < 4; j++) {
        setlinestyle(j, 0, 3);
        line(0, 50 + (j + 1) * 10, getmaxx(), 50 + (j + 1) * 10);
    }
    getch();
    closegraph();
    return (0);
}

#include <graphics.h> #include <conio.h> #include <vector> #include <ctime> #include <string> #include <sstream> #include <windows.h> #include <chrono> // 修复:正确的头文件名 #include <algorithm> #include <atomic> using namespace std; using namespace std::chrono; const int ROW = 8; const int COL = 10; const int BLOCK_SIZE = 80; const int WINDOW_WIDTH = COL * BLOCK_SIZE; const int WINDOW_HEIGHT = ROW * BLOCK_SIZE + 120; const int COLORS[] = {RED, GREEN, BLUE, YELLOW, MAGENTA, CYAN, BROWN, LIGHTBLUE}; const int NUM_COLORS = sizeof(COLORS) / sizeof(COLORS[0]); // Exit button position and state const int EXIT_BTN_WIDTH = 120; const int EXIT_BTN_HEIGHT = 40; const int EXIT_BTN_X = WINDOW_WIDTH - EXIT_BTN_WIDTH - 20; const int EXIT_BTN_Y = WINDOW_HEIGHT - EXIT_BTN_HEIGHT - 15; bool exitBtnHovered = false; bool exitBtnPressed = false; vector<vector<int>> grid(ROW, vector<int>(COL)); atomic<int> score(0); bool gameOver = false; bool quitGame = false; int selectedX = -1, selectedY = -1; steady_clock::time_point lastClickTime = steady_clock::now(); const int MIN_CLICK_INTERVAL = 50; bool isAnimating = false; // High-resolution timer class HighResTimer { public: void start() { startTime = steady_clock::now(); } double elapsed() const { return duration_cast<duration<double>>(steady_clock::now() - start极Time).count(); } private: steady_clock::time_point startTime; }; // Integer to string conversion string intToString(int value) { stringstream ss; ss << value; return ss.str(); } // Draw exit button void drawExitButton() { if (exitBtnHovered) { setfillcolor(LIGHTGRAY); } else { setfillcolor(DARKGRAY); } // Draw button background solidrectangle(EXIT_BTN_X, EXIT_BTN_Y, EXIT_BTN_X + EXIT_BTN_WIDTH, EXIT_BTN_Y + EXIT_BTN_HEIGHT); // Draw button border setlinecolor(WHITE); rectangle(EXIT_BTN_X, EXIT_BTN_Y, EXIT_BTN_X + EXIT_BTN_WIDTH, EXIT_BTN_Y + EXIT_BTN_HEIGHT); // Draw button text settextcolor(exitBtnPressed ? RED : WHITE); settextstyle(24, 0, _T("Arial")); outtextxy(EXIT_BTN_X + 25, EXIT_BTN_Y + 8, "Exit Game"); } // Initialize game grid void initGrid() { srand(static_cast<unsigned>(time(0))); // Generate initial grid without matches bool hasMatches = true; while (hasMatches) { hasMatches = false; for (int i = 0; i < ROW; ++i) { for (int j = 0; j < COL; ++j) { grid[i][j] = rand() % NUM_COLORS; } } // Check horizontal matches for (int i = 0; i < ROW; ++i) { for (int j = 0; j < COL - 2; ++j) { if (grid[i][j] == grid[i][j+1] && grid[i][j] == grid[i][j+2]) { hasMatches = true; break; } } if (hasMatches) break; } // Check vertical matches if (!hasMatches) { for (int j = 0; j < COL; ++j) { for (int i = 0; i < ROW - 2; ++i) { if (grid[i][j] == grid[i+1][j] && grid[i][j] == grid[i+2][j]) { hasMatches = true; break; } } if (hasMatches) break; } } } } // Optimized grid drawing with exit button void drawGridPartial(int highlightX = -1, int highlightY = -1) { // Draw only highlighted block if specified if (highlightX >= 0 && highlightY >= 0) { int x = highlightX, y = highlightY; // Clear original position setfillcolor(BLACK); solidrectangle(x * BLOCK_SIZE, y * BLOCK_SIZE, (x + 1) * BLOCK_SIZE, (y + 1) * BLOCK_SIZE); // Draw new block if (grid[y][x] != -1) { setfillcolor(COLORS[grid[y][x]]); solidrectangle(x * BLOCK_SIZE, y * BLOCK_SIZE, (x + 1) * BLOCK_SIZE, (y + 1) * BLOCK_SIZE); setlinecolor(BLACK); rectangle(x * BLOCK_SIZE, y * BLOCK_SIZE, (x + 1) * BLOCK_SIZE, (y + 1) * BLOCK_SIZE); } // Highlight selected block if (x == selectedX && y == selectedY) { setlinecolor(WHITE); setlinestyle(PS_SOLID, 3); rectangle(x * BLOCK_SIZE + 2, y * BLOCK_SIZE + 2, (x + 1) * BLOCK_SIZE - 2, (y + 1) * BLOCK_SIZE - 2); setlinestyle(PS_SOLID, 1); } return; } // Full screen redraw cleardevice(); settextstyle(24, 0, _T("Arial")); // Draw blocks for (极int i = 0; i < ROW; ++i) { for (int j = 0; j < COL; ++j) { if (grid[i][j] != -1) { setfillcolor(COLORS[grid[i][j]]); solidrectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j + 1) * BLOCK_SIZE, (i + 1) * BLOCK_SIZE); setlinecolor(BLACK); rectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j + 1) * BLOCK_SIZE, (i + 1) * BLOCK_SIZE); // Highlight selected block if (i == selectedY && j == selectedX) { setlinecolor(WHITE); setlinestyle(PS_SOLID, 3); rectangle(j * BLOCK_SIZE + 2, i * BLOCK_SIZE + 2, (j + 1) * BLOCK_SIZE - 2, (i + 1) * BLOCK_SIZE - 2); setlinestyle(PS_SOLID, 1); } } else { // Draw empty block (transparent) setfillcolor(BLACK); setlinecolor(DARKGRAY); rectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j + 1) * BLOCK_SIZE, (i + 1) * BLOCK_SIZE); } } } // Draw score panel setfillcolor(DARKGRAY); solidrectangle(0, ROW * BLOCK_SIZE, WINDOW_WIDTH, WINDOW_HEIGHT); settextcolor(WHITE); string scoreStr = "Score: " + intToString(score); outtextxy(20, ROW * BLOCK_SIZE + 20, scoreStr.c_str()); // Draw exit button drawExitButton(); // Game over message if (gameOver) { settextcolor(RED); settextstyle(36, 0, _T("Arial")); outtextxy(WINDOW_WIDTH/2 - 120, WINDOW_HEIGHT/2 - 30, "Game Over!"); settextstyle(24, 0, _T("Arial")); string finalScore = "Final Score: " + intToString(score); outtextxy(WINDOW_WIDTH/2 - 100, WINDOW_HEIGHT/2 + 20, finalScore.c_str()); } } // Check for possible moves bool hasPossibleMoves() { // Horizontal swap check for (int i = 0; i < ROW; ++i) { for (int j = 0; j < COL - 1; ++j) { // Try swapping swap(grid[i][j], grid[i][j+1]); // Check if swap creates a match bool matchFound = false; // Check row matches (optimized area) for (int r = max(0, i-1); r <= min(ROW-1, i+1); ++r) { for (int c = max(0, j-2); c <= min(COL-3, j+2); ++c) { if (c < 0 || c+2 >= COL) continue; if (grid[r][c] != -1 && grid[r][c] == grid[r][c+1] && grid[r][c] == grid[r][c+2]) { matchFound = true; break; } } if (matchFound) break; } // Check column matches if (!matchFound) { for (int c = max(0, j-1); c <= min(COL-1, j+1); ++c) { for (int r = max(0, i-2); r <= min(ROW-3, i+2); ++r) { if (r < 0 || r+2 >= ROW) continue; if (grid[r][c] != -1 && grid[r][c] == grid[r+1][c] && grid[r][c] == grid[r+2][c]) { matchFound = true; break; } } if (matchFound) break; } } // Restore swap swap(grid[i][j], grid[i][j+1]); if (matchFound) return true; } } // Vertical swap check for (int j = 0; j < COL; ++j) { for (int i = 0; i < ROW - 1; ++i) { // Try swapping swap(grid[i][j], grid[i+1][j]); // Check if swap creates a match bool matchFound = false; // Check row matches for (int r = max(0, i-1); r <= min(ROW-1, i+1); ++r) { for (int c = max(0, j-2); c <= min(COL-3, j+2); ++c) { if (c < 0 || c+2 >= COL) continue; if (grid[r][c] != -1 && grid[r][c] == grid[r][c+1] && grid[r][c] == grid[r][c+2]) { matchFound = true; break; } } if (matchFound) break; } // Check column matches if (!matchFound) { for (int c = max(0, j-1); c <= min(COL-1, j+1); ++c) { for (int r = max(0, i-2); r <= min(ROW-3, i+2); ++r) { if (r < 0 || r+2 >= ROW) continue; if (grid[r][c] != -1 && grid[r][c] == grid[r+1][c] && grid[r][c] == grid[r+2][c]) { matchFound = true; break; } } if (matchFound) break; } } // Restore swap swap(grid[i][j], grid[i+1][j]); if (matchFound) return true; } } return false; } // Process matches and update score int processMatches() { vector<vector<bool>> toRemove(ROW, vector<bool>(COL, false)); int matchCount = 0; // Horizontal match check for (int i = 0; i < ROW; ++i) { for (int j = 0; j < COL - 2; ) { if (grid[i][j] != -1 && grid[i][j] == grid[i][j + 1] && grid[i][j] == grid[i][j + 2]) { int k = j + 2; while (k < COL && grid[i][j] == grid[i][k]) { k++; } for (int pos = j; pos < k; ++pos) { toRemove[i][pos] = true; matchCount++; } j = k; // Skip checked positions } else { j++; } } } // Vertical match check for (int j = 0; j < COL; ++j) { for (int i = 0; i < ROW - 2; ) { if (grid[i][j] != -1 && grid[i][j] == grid[i + 1][j] && grid[i][j] == grid[i + 2][j]) { int k = i + 2; while (k < ROW && grid[i][j] == grid[k][j]) { k++; } for (int pos = i; pos < k; ++pos) { toRemove[pos][j] = true; matchCount++; } i = k; // Skip checked positions } else { i++; } } } // Update score if (matchCount > 0) { static int comboCount = 0; comboCount++; int comboBonus = max(0, comboCount - 1) * 5; score += matchCount * 10 + comboBonus; } else { // Reset combo count static int comboCount = 0; comboCount = 0; } // Remove matched blocks for (int i = 0; i < ROW; ++i) { for (int j = 0; j < COL; ++j) { if (toRemove[i][j]) { grid[i][j] = -1; } } } return matchCount; } // Block falling animation void dropBlocksAnimated() { HighResTimer timer; timer.start(); // Track new positions for each column vector<vector<int>> newPositions(COL); vector<vector<int>> temp(COL); // Prepare falling data for (int j = 0; j < COL; ++j) { // Collect non-empty blocks (bottom to top) for (int i = ROW - 1; i >= 0; --i) { if (grid[i][j] != -1) { temp[j].push_back(grid[i][j]); } } // Generate new blocks int newBlocks = ROW - temp[j].size(); for (int i = 0; i < newBlocks; ++i) { temp[j].push_back(rand() % NUM_COLORS); } // Calculate new positions for (int i = 0; i < ROW; ++i) { newPositions[j].push_back(temp[j][ROW - 1 - i]); } } // Animation duration (seconds) const double animationDuration = 0.3; vector<vector<int>> originalGrid = grid; // Save original state while (true) { double elapsed = timer.elapsed(); if (elapsed >= animationDuration) break; double progress = min(1.0, elapsed / animationDuration); // Update animation frame for (int j = 0; j < COL; ++j) { for (int i = 0; i < ROW; ++i) { // If block needs to fall if (originalGrid[i][j] != -1 && newPositions[j][i] != originalGrid[i][j]) { // Calculate falling distance int targetY = i; while (targetY < ROW && grid[targetY][j] != newPositions[j][i]) { targetY++; } if (targetY < ROW) { // Calculate current position double currentY = i + (targetY - i) * progress; // Draw falling block setfillcolor(COLORS[originalGrid[i][j]]); solidrectangle(j * BLOCK_SIZE, static_cast<int>(currentY * BLOCK_SIZE), (j + 1) * BLOCK_SIZE, static_cast<int>((currentY + 1) * BLOCK_SIZE)); setlinecolor(BLACK); rectangle(j * BLOCK_SIZE, static_cast<int>(currentY * BLOCK_SIZE), (j + 1) * BLOCK_SIZE, static_cast<int>((currentY + 1) * BLOCK_SIZE)); } } } } FlushBatchDraw(); Sleep(10); } // Apply final state for (int j = 0; j < COL; ++j) { for (int i = 0; i < ROW; ++i) { grid[i][j] = newPositions[j][i]; } } } // Handle mouse clicks (including exit button) void handleMouseClick() { // Ignore input during animation if (isAnimating) return; if (MouseHit()) { MOUSEMSG msg = GetMouseMsg(); // Check click interval auto now = steady_clock::now(); auto elapsed = duration_cast<milliseconds>(now - lastClickTime).count(); if (elapsed < MIN_CLICK_INTERVAL) { return; } lastClickTime = now; // Check if mouse is over exit button bool prevHovered = exitBtnHovered; exitBtnHovered = (msg.x >= EXIT_BTN_X && msg.x <= EXIT_BTN_X + EXIT_BTN_WIDTH && msg.y >= EXIT_BTN_Y && msg.y <= EXIT_BTN_Y + EXIT_BTN_HEIGHT); // Redraw button if hover state changed if (exitBtnHovered != prevHovered) { drawExitButton(); FlushBatchDraw(); } // Handle exit button click if (msg.uMsg == WM_LBUTTONDOWN && exitBtnHovered) { exitBtnPressed = true; drawExitButton(); FlushBatchDraw(); } else if (msg.uMsg == WM_LBUTTONUP && exitBtnPressed) { exitBtnPressed = false; if (exitBtnHovered) { // Quit game quitGame = true; return; } drawExitButton(); FlushBatchDraw(); } // Handle grid clicks if (msg.uMsg == WM_LBUTTONDOWN) { int x = msg.x / BLOCK_SIZE; int y = msg.y / BLOCK_SIZE; // Ensure click is within grid if (x >= 0 && x < COL && y >= 0 && y < ROW && grid[y][x] != -1) { // First click or change selection if (selectedX == -1) { selectedX = x; selectedY = y; drawGridPartial(x, y); // Partial redraw FlushBatchDraw(); } // Click same block - deselect else if (selectedX == x && selectedY == y) { selectedX = -1; selectedY = -1; drawGridPartial(x, y); // Partial redraw FlushBatchDraw(); } // Second click (swap) else if ((abs(selectedX - x) == 1 && selectedY == y) || (abs(selectedY - y) == 1 && selectedX == x)) { // Set animation state isAnimating = true; // Swap animation int prevX = selectedX, prevY = selectedY; // Draw swap animation HighResTimer swapTimer; swapTimer.start(); const double swapDuration = 0.2; while (true) { double elapsed = swapTimer.elapsed(); if (elapsed >= swapDuration) break; double progress = min(1.0, elapsed / swapDuration); // Calculate intermediate position int offsetX = static_cast<int>((x - prevX) * progress * BLOCK_SIZE); int offsetY = static_cast<int>((y - prevY) * progress * BLOCK_SIZE); // Clear original position setfillcolor(BLACK); solidrectangle(prevX * BLOCK_SIZE, prevY * BLOCK_SIZE, (prevX + 1) * BLOCK_SIZE, (prevY + 1) * BLOCK_SIZE); solidrectangle(x * BLOCK_SIZE, y * BLOCK_SIZE, (极x + 1) * BLOCK_SIZE, (y + 1) * BLOCK_SIZE); // Draw moving blocks setfillcolor(COLORS[grid[prevY][prevX]]); solidrectangle(prevX * BLOCK_SIZE + offsetX, prevY * BLOCK_SIZE + offsetY, (prevX + 1) * BLOCK_SIZE + offsetX, (prevY + 1) * BLOCK_SIZE + offsetY); setfillcolor(COLORS[grid[y][x]]); solidrectangle(x * BLOCK_SIZE - offsetX, y * BLOCK_SIZE - offsetY, (x + 1) * BLOCK_SIZE - offsetX, (y + 1) * BLOCK_SIZE - offsetY); FlushBatchDraw(); Sleep(10); } // Actually swap blocks swap(grid[prevY][prevX], grid[y][x]); // Check if match is formed bool matched = false; if (processMatches() > 0) { matched = true; } if (!matched) { // Revert swap if no match swap(grid[prevY][prevX], grid[y][x]); drawGridPartial(prevX, prevY); drawGridPartial(x, y); FlushBatchDraw(); } else { // Process chain reactions while (true) { // Drop blocks with animation dropBlocksAnimated(); // Check for new matches if (processMatches() == 0) break; } // Check if game is over gameOver = !hasPossibleMoves(); } // Reset selection selectedX = selectedY = -1; // End animation isAnimating = false; } // Click different position, change selection else { // Clear old selection int oldX = selectedX, oldY = selectedY; selectedX = x; selectedY = y; // Partial redraw if (oldX >= 0 && oldY >= 0) { drawGridPartial(oldX, oldY); } drawGridPartial(x, y); FlushBatchDraw(); } } // Click outside grid, reset selection else if (selectedX >= 0 || selectedY >= 0) { int oldX = selectedX, oldY = selectedY; selectedX = selectedY = -1; // Partial redraw if (oldX >= 0 && oldY >= 0) { drawGridPartial(oldX, oldY); } FlushBatchDraw(); } } } } int main() { initgraph(WINDOW_WIDTH, WINDOW_HEIGHT); initGrid(); BeginBatchDraw(); // High-precision timer HighResTimer frameTimer; const double targetFPS = 120.0; const double frameTime = 1.0 / targetFPS; while (!gameOver && !quitGame) { frameTimer.start(); if (!isAnimating) { drawGridPartial(); // Partial redraw mode } handleMouseClick(); FlushBatchDraw(); // Precise frame rate control double elapsed = frameTimer.elapsed(); if (elapsed < frameTime) { int sleepTime = static_cast<int>((frameTime - elapsed) * 1000); if (sleepTime > 0) { Sleep(sleepTime); } } } // Game over state if (!quitGame) { drawGridPartial(); FlushBatchDraw(); // Wait for key press to exit while (!_kbhit() && !quitGame) { Sleep(100); } } EndBatchDraw(); closegraph(); return 0; }
06-18
#include <graphics.h> #include <conio.h> #include <vector> #include <ctime> #include <string> #include <sstream> #include <windows.h> #include <chrono> #include <algorithm> #include <atomic> using namespace std; using namespace std::chrono; const int ROW = 8; const int COL = 10; const int BLOCK_SIZE = 80; const int WINDOW_WIDTH = COL * BLOCK_SIZE; const int WINDOW_HEIGHT = ROW * BLOCK_SIZE + 120; // 增加高度容纳退出按钮 const int COLORS[] = {RED, GREEN, BLUE, YELLOW, MAGENTA, CYAN, BROWN, LIGHTBLUE}; const int NUM_COLORS = sizeof(COLORS) / sizeof(COLORS[0]); // 退出按钮位置和状态 const int EXIT_BTN_WIDTH = 120; const int EXIT_BTN_HEIGHT = 40; const int EXIT_BTN_X = WINDOW_WIDTH - EXIT_BTN_WIDTH - 20; const int EXIT_BTN_Y = WINDOW_HEIGHT - EXIT_BTN_HEIGHT - 15; bool exitBtnHovered = false; bool exitBtnPressed = false; vector<vector<int>> grid(ROW, vector<int>(COL)); atomic<int> score(0); bool gameOver = false; bool quitGame = false; // 新增退出游戏标志 int selectedX = -1, selectedY = -1; steady_clock::time_point lastClickTime = steady_clock::now(); const int MIN_CLICK_INTERVAL = 50; bool isAnimating = false; // 高精度计时器类 class HighResTimer { public: void start() { startTime = steady_clock::now(); } double elapsed() const { return duration_cast<duration<double>>(steady_clock::now() - startTime).count(); } private: steady_clock::time_point startTime; }; // 整数转字符串 string intToString(int value) { stringstream ss; ss << value; return ss.str(); } // 绘制退出按钮 void drawExitButton() { if (exitBtnHovered) { setfillcolor(LIGHTGRAY); } else { setfillcolor(DARKGRAY); } // 绘制按钮背景 solidrectangle(EXIT_BTN_X, EXIT_BTN_Y, EXIT_BTN_X + EXIT_BTN_WIDTH, EXIT_BTN_Y + EXIT_BTN_HEIGHT); // 绘制按钮边框 setlinecolor(WHITE); rectangle(EXIT_BTN_X, EXIT_BTN_Y, EXIT_BTN_X + EXIT_BTN_WIDTH, EXIT_BTN_Y + EXIT_BTN_HEIGHT); // 绘制按钮文字 settextcolor(exitBtnPressed ? RED : WHITE); settextstyle(24, 0, _T("Arial")); outtextxy(EXIT_BTN_X + 25, EXIT_BTN_Y + 8, "退出游戏"); } // 初始化游戏网格 void initGrid() { srand(static_cast<unsigned>(time(0))); // 生成初始网格,确保没有初始匹配 bool hasMatches = true; while (hasMatches) { hasMatches = false; for (int i = 0; i < ROW; ++i) { for (int j = 0; j < COL; ++j) { grid[i][j] = rand() % NUM_COLORS; } } // 检查水平匹配 for (int i = 0; i < ROW; ++i) { for (int j = 0; j < COL - 2; ++j) { if (grid[i][j] == grid[i][j+1] && grid[i][j] == grid[i][j+2]) { hasMatches = true; break; } } if (hasMatches) break; } // 检查垂直匹配 if (!hasMatches) { for (int j = 0; j < COL; ++j) { for (int i = 0; i < ROW - 2; ++i) { if (grid[i][j] == grid[i+1][j] && grid[i][j] == grid[i+2][j]) { hasMatches = true; break; } } if (hasMatches) break; } } } } // 优化绘制:包含退出按钮 void drawGridPartial(int highlightX = -1, int highlightY = -1) { // 如果指定了高亮位置,只重绘该方块 if (highlightX >= 0 && highlightY >= 0) { int x = highlightX, y = highlightY; // 清除原位置 setfillcolor(BLACK); solidrectangle(x * BLOCK_SIZE, y * BLOCK_SIZE, (x + 1) * BLOCK_SIZE, (y + 1) * BLOCK_SIZE); // 绘制新方块 if (grid[y][x] != -1) { setfillcolor(COLORS[grid[y][x]]); solidrectangle(x * BLOCK_SIZE, y * BLOCK_SIZE, (x + 1) * BLOCK_SIZE, (y + 1) * BLOCK_SIZE); setlinecolor(BLACK); rectangle(x * BLOCK_SIZE, y * BLOCK_SIZE, (x + 1) * BLOCK_SIZE, (y + 1) * BLOCK_SIZE); } // 高亮选中的方块 if (x == selectedX && y == selectedY) { setlinecolor(WHITE); setlinestyle(PS_SOLID, 3); rectangle(x * BLOCK_SIZE + 2, y * BLOCK_SIZE + 2, (x + 1) * BLOCK_SIZE - 2, (y + 1) * BLOCK_SIZE - 2); setlinestyle(PS_SOLID, 1); } return; } // 全屏重绘 cleardevice(); settextstyle(24, 0, _T("Arial")); // 绘制方块 for (int i = 0; i < ROW; ++i) { for (int j = 0; j < COL; ++j) { if (grid[i][j] != -1) { setfillcolor(COLORS[grid[i][j]]); solidrectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j + 1) * BLOCK_SIZE, (i + 1) * BLOCK_SIZE); setlinecolor(BLACK); rectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j + 1) * BLOCK_SIZE, (i + 1) * BLOCK_SIZE); // 高亮选中的方块 if (i == selectedY && j == selectedX) { setlinecolor(WHITE); setlinestyle(PS_SOLID, 3); rectangle(j * BLOCK_SIZE + 2, i * BLOCK_SIZE + 2, (j + 1) * BLOCK_SIZE - 2, (i + 1) * BLOCK_SIZE - 2); setlinestyle(PS_SOLID, 1); } } else { // 绘制空方块(透明) setfillcolor(BLACK); setlinecolor(DARKGRAY); rectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j + 1) * BLOCK_SIZE, (i + 1) * BLOCK_SIZE); } } } // 绘制分数板 setfillcolor(DARKGRAY); solidrectangle(0, ROW * BLOCK_SIZE, WINDOW_WIDTH, WINDOW_HEIGHT); settextcolor(WHITE); string scoreStr = "分数: " + intToString(score); outtextxy(20, ROW * BLOCK_SIZE + 20, scoreStr.c_str()); // 绘制退出按钮 drawExitButton(); // 游戏结束提示 if (gameOver) { settextcolor(RED); settextstyle(36, 0, _T("Arial")); outtextxy(WINDOW_WIDTH/2 - 120, WINDOW_HEIGHT/2 - 30, "游戏结束!"); settextstyle(24, 0, _T("Arial")); string finalScore = "最终分数: " + intToString(score); outtextxy(WINDOW_WIDTH/2 - 100, WINDOW_HEIGHT/2 + 20, finalScore.c_str()); } } // 检查是否有可移动的匹配 bool hasPossibleMoves() { // 水平交换检查 for (int i = 0; i < ROW; ++i) { for (int j = 0; j < COL - 1; ++j) { // 尝试交换 swap(grid[i][j], grid[i][j+1]); // 检查交换后是否形成匹配 bool matchFound = false; // 检查行匹配(优化:只检查受影响的区域) for (int r = max(0, i-1); r <= min(ROW-1, i+1); ++r) { for (int c = max(0, j-2); c <= min(COL-3, j+2); ++c) { if (c < 0 || c+2 >= COL) continue; if (grid[r][c] != -1 && grid[r][c] == grid[r][c+1] && grid[r][c] == grid[r][c+2]) { matchFound = true; break; } } if (matchFound) break; } // 检查列匹配 if (!matchFound) { for (int c = max(0, j-1); c <= min(COL-1, j+1); ++c) { for (int r = max(0, i-2); r <= min(ROW-3, i+2); ++r) { if (r < 0 || r+2 >= ROW) continue; if (grid[r][c] != -1 && grid[r][c] == grid[r+1][c] && grid[r][c] == grid[r+2][c]) { matchFound = true; break; } } if (matchFound) break; } } // 恢复交换 swap(grid[i][j], grid[i][j+1]); if (matchFound) return true; } } // 垂直交换检查 for (int j = 0; j < COL; ++j) { for (int i = 0; i < ROW - 1; ++i) { // 尝试交换 swap(grid[i][j], grid[i+1][j]); // 检查交换后是否形成匹配 bool matchFound = false; // 检查行匹配 for (int r = max(0, i-1); r <= min(ROW-1, i+1); ++r) { for (int c = max(0, j-2); c <= min(COL-3, j+2); ++c) { if (c < 0 || c+2 >= COL) continue; if (grid[r][c] != -1 && grid[r][c] == grid[r][c+1] && grid[r][c] == grid[r][c+2]) { matchFound = true; break; } } if (matchFound) break; } // 检查列匹配 if (!matchFound) { for (int c = max(0, j-1); c <= min(COL-1, j+1); ++c) { for (int r = max(0, i-2); r <= min(ROW-3, i+2); ++r) { if (r < 0 || r+2 >= ROW) continue; if (grid[r][c] != -1 && grid[r][c] == grid[r+1][c] && grid[r][c] == grid[r+2][c]) { matchFound = true; break; } } if (matchFound) break; } } // 恢复交换 swap(grid[i][j], grid[i+1][j]); if (matchFound) return true; } } return false; } // 检查并处理匹配 int processMatches() { vector<vector<bool>> toRemove(ROW, vector<bool>(COL, false)); int matchCount = 0; // 水平匹配检查 for (int i = 0; i < ROW; ++i) { for (int j = 0; j < COL - 2; ) { if (grid[i][j] != -1 && grid[i][j] == grid[i][j + 1] && grid[i][j] == grid[i][j + 2]) { int k = j + 2; while (k < COL && grid[i][j] == grid[i][k]) { k++; } for (int pos = j; pos < k; ++pos) { toRemove[i][pos] = true; matchCount++; } j = k; // 跳过已检查的部分 } else { j++; } } } // 垂直匹配检查 for (int j = 0; j < COL; ++j) { for (int i = 0; i < ROW - 2; ) { if (grid[i][j] != -1 && grid[i][j] == grid[i + 1][j] && grid[i][j] == grid[i + 2][j]) { int k = i + 2; while (k < ROW && grid[i][j] == grid[k][j]) { k++; } for (int pos = i; pos < k; ++pos) { toRemove[pos][j] = true; matchCount++; } i = k; // 跳过已检查的部分 } else { i++; } } } // 更新分数 if (matchCount > 0) { static int comboCount = 0; comboCount++; int comboBonus = max(0, comboCount - 1) * 5); score += matchCount * 10 + comboBonus; } else { // 重置连击计数 static int comboCount = 0; comboCount = 0; } // 移除匹配的方块 for (int i = 0; i < ROW; ++i) { for (int j = 0; j < COL; ++j) { if (toRemove[i][j]) { grid[i][j] = -1; } } } return matchCount; } // 方块下落动画 void dropBlocksAnimated() { HighResTimer timer; timer.start(); // 记录每列需要下落的位置 vector<vector<int>> newPositions(COL); vector<vector<int>> temp(COL); // 准备下落数据 for (int j = 0; j < COL; ++j) { // 收集非空方块(从下往上) for (int i = ROW - 1; i >= 0; --i) { if (grid[i][j] != -1) { temp[j].push_back(grid[i][j]); } } // 生成新方块 int newBlocks = ROW - temp[j].size(); for (int i = 0; i < newBlocks; ++i) { temp[j].push_back(rand() % NUM_COLORS); } // 计算新位置 for (int i = 0; i < ROW; ++i) { newPositions[j].push_back(temp[j][ROW - 1 - i]); } } // 动画持续时间(秒) const double animationDuration = 0.3; vector<vector<int>> originalGrid = grid; // 保存原始状态 while (true) { double elapsed = timer.elapsed(); if (elapsed >= animationDuration) break; double progress = min(1.0, elapsed / animationDuration); // 更新动画帧 for (int j = 0; j < COL; ++j) { for (int i = 0; i < ROW; ++i) { // 如果方块需要下落 if (originalGrid[i][j] != -1 && newPositions[j][i] != originalGrid[i][j]) { // 计算下落距离 int targetY = i; while (targetY < ROW && grid[targetY][j] != newPositions[j][i]) { targetY++; } if (targetY < ROW) { // 计算当前位置 double currentY = i + (targetY - i) * progress; // 绘制下落中的方块 setfillcolor(COLORS[originalGrid[i][j]]); solidrectangle(j * BLOCK_SIZE, static_cast<int>(currentY * BLOCK_SIZE), (j + 1) * BLOCK_SIZE, static_cast<int>((currentY + 1) * BLOCK_SIZE)); setlinecolor(BLACK); rectangle(j * BLOCK_SIZE, static_cast<int>(currentY * BLOCK_SIZE), (j + 1) * BLOCK_SIZE, static_cast<int>((currentY + 1) * BLOCK_SIZE)); } } } } FlushBatchDraw(); Sleep(10); } // 应用最终状态 for (int j = 0; j < COL; ++j) { for (int i = 0; i < ROW; ++i) { grid[i][j] = newPositions[j][i]; } } } // 处理鼠标点击(包含退出按钮处理) void handleMouseClick() { // 如果正在动画中,忽略输入 if (isAnimating) return; if (MouseHit()) { MOUSEMSG msg = GetMouseMsg(); // 检查点击间隔 auto now = steady_clock::now(); auto elapsed = duration_cast<milliseconds>(now - lastClickTime).count(); if (elapsed < MIN_CLICK_INTERVAL) { return; } lastClickTime = now; // 检查鼠标是否在退出按钮上 bool prevHovered = exitBtnHovered; exitBtnHovered = (msg.x >= EXIT_BTN_X && msg.x <= EXIT_BTN_X + EXIT_BTN_WIDTH && msg.y >= EXIT_BTN_Y && msg.y <= EXIT_BTN_Y + EXIT_BTN_HEIGHT); // 如果悬停状态改变,重绘按钮 if (exitBtnHovered != prevHovered) { drawExitButton(); FlushBatchDraw(); } // 处理退出按钮点击 if (msg.uMsg == WM_LBUTTONDOWN && exitBtnHovered) { exitBtnPressed = true; drawExitButton(); FlushBatchDraw(); } else if (msg.uMsg == WM_LBUTTONUP && exitBtnPressed) { exitBtnPressed = false; if (exitBtnHovered) { // 退出游戏 quitGame = true; return; } drawExitButton(); FlushBatchDraw(); } // 游戏网格点击处理 if (msg.uMsg == WM_LBUTTONDOWN) { int x = msg.x / BLOCK_SIZE; int y = msg.y / BLOCK_SIZE; // 确保点击在网格内 if (x >= 0 && x < COL && y >= 0 && y < ROW && grid[y][x] != -1) { // 第一次点击或更换选择 if (selectedX == -1) { selectedX = x; selectedY = y; drawGridPartial(x, y); // 部分重绘 FlushBatchDraw(); } // 点击同一方块 - 取消选择 else if (selectedX == x && selectedY == y) { selectedX = -1; selectedY = -1; drawGridPartial(x, y); // 部分重绘 FlushBatchDraw(); } // 第二次点击(交换) else if ((abs(selectedX - x) == 1 && selectedY == y) || (abs(selectedY - y) == 1 && selectedX == x)) { // 设置动画状态 isAnimating = true; // 交换动画 int prevX = selectedX, prevY = selectedY; // 绘制交换动画 HighResTimer swapTimer; swapTimer.start(); const double swapDuration = 0.2; while (true) { double elapsed = swapTimer.elapsed(); if (elapsed >= swapDuration) break; double progress = min(1.0, elapsed / swapDuration); // 计算中间位置 int offsetX = static_cast<int>((x - prevX) * progress * BLOCK_SIZE); int offsetY = static_cast<int>((y - prevY) * progress * BLOCK_SIZE); // 清除原位置 setfillcolor(BLACK); solidrectangle(prevX * BLOCK_SIZE, prevY * BLOCK_SIZE, (prevX + 1) * BLOCK_SIZE, (prevY + 1) * BLOCK_SIZE); solidrectangle(x * BLOCK_SIZE, y * BLOCK_SIZE, (x + 1) * BLOCK_SIZE, (y + 1) * BLOCK_SIZE); // 绘制移动中的方块 setfillcolor(COLORS[grid[prevY][prevX]]); solidrectangle(prevX * BLOCK_SIZE + offsetX, prevY * BLOCK_SIZE + offsetY, (prevX + 1) * BLOCK_SIZE + offsetX, (prevY + 1) * BLOCK_SIZE + offsetY); setfillcolor(COLORS[grid[y][x]]); solidrectangle(x * BLOCK_SIZE - offsetX, y * BLOCK_SIZE - offsetY, (x + 1) * BLOCK_SIZE - offsetX, (y + 1) * BLOCK_SIZE - offsetY); FlushBatchDraw(); Sleep(10); } // 实际交换方块 swap(grid[prevY][prevX], grid[y][x]); // 检查是否形成匹配 bool matched = false; if (processMatches() > 0) { matched = true; } if (!matched) { // 没有匹配则恢复交换 swap(grid[prevY][prevX], grid[y][x]); drawGridPartial(prevX, prevY); drawGridPartial(x, y); FlushBatchDraw(); } else { // 处理连续消除 while (true) { // 下落方块(动画版) dropBlocksAnimated(); // 检查是否有新的匹配 if (processMatches() == 0) break; } // 检查游戏是否结束 gameOver = !hasPossibleMoves(); } // 重置选择 selectedX = selectedY = -1; // 结束动画 isAnimating = false; } // 点击其他位置,重新选择 else { // 先清除旧选择 int oldX = selectedX, oldY = selectedY; selectedX = x; selectedY = y; // 部分重绘 if (oldX >= 0 && oldY >= 0) { drawGridPartial(oldX, oldY); } drawGridPartial(x, y); FlushBatchDraw(); } } // 点击在网格外,重置选择 else if (selectedX >= 0 || selectedY >= 0) { int oldX = selectedX, oldY = selectedY; selectedX = selectedY = -1; // 部分重绘 if (oldX >= 0 && oldY >= 0) { drawGridPartial(oldX, oldY); } FlushBatchDraw(); } } } } int main() { initgraph(WINDOW_WIDTH, WINDOW_HEIGHT); initGrid(); BeginBatchDraw(); // 高精度计时器 HighResTimer frameTimer; const double targetFPS = 120.0; const double frameTime = 1.0 / targetFPS; while (!gameOver && !quitGame) { frameTimer.start(); if (!isAnimating) { drawGridPartial(); // 部分重绘模式 } handleMouseClick(); FlushBatchDraw(); // 精确帧率控制 double elapsed = frameTimer.elapsed(); if (elapsed < frameTime) { int sleepTime = static_cast<int>((frameTime - elapsed) * 1000); if (sleepTime > 0) { Sleep(sleepTime); } } } // 游戏结束状态 if (!quitGame) { drawGridPartial(); FlushBatchDraw(); // 等待按键退出 while (!_kbhit() && !quitGame) { Sleep(100); } } EndBatchDraw(); closegraph(); return 0; }
06-17
#include <graphics.h> #include <conio.h> #include <vector> #include <ctime> #include <string> #include <sstream> #include <windows.h> #include <algorithm> #include <atomic> #include <thread> #include <mmsystem.h> #pragma comment(lib, "winmm.lib") using namespace std; const int ROW = 8; const int COL = 10; const int BLOCK_SIZE = 80; const int WINDOW_WIDTH = COL * BLOCK_SIZE; const int WINDOW_HEIGHT = ROW * BLOCK_SIZE + 150; const int COLORS[] = {RED, GREEN, BLUE, YELLOW, MAGENTA, CYAN, BROWN, LIGHTBLUE}; const int NUM_COLORS = sizeof(COLORS) / sizeof(COLORS[0]); vector<vector<int>> grid(ROW, vector<int>(COL)); atomic<int> score(0); atomic<bool> exitFlag(false); bool gameOver = false; int selectedX = -1, selectedY = -1; long long lastClickTime = 0; const int MIN_CLICK_INTERVAL = 50; bool isAnimating = false; enum GameState { READY, PLAYING, TIME_UP }; GameState gameState = READY; const int GAME_DURATION = 60; int remainingTime = GAME_DURATION; long long gameStartTime = 0; int finalScore = 0; bool isMusicPlaying = false; const char* MUSIC_FILE = "C:\\Users\\27287\\Desktop\\devc\\ma+7\\music.mp3"; // 使用普通字符串路径 class HighResTimer { public: void start() { QueryPerformanceCounter(&startTime); } double elapsed() const { LARGE_INTEGER endTime, frequency; QueryPerformanceCounter(&endTime); QueryPerformanceFrequency(&frequency); return static_cast<double>(endTime.QuadPart - startTime.QuadPart) / frequency.QuadPart; } private: LARGE_INTEGER startTime; }; void playBackgroundMusic() { string openCmd = "open \"" + string(MUSIC_FILE) + "\" type mpegvideo alias bgmusic"; mciSendString(openCmd.c_str(), NULL, 0, NULL); mciSendString("setaudio bgmusic volume to 500", NULL, 0, NULL); mciSendString("play bgmusic repeat", NULL, 0, NULL); isMusicPlaying = true; } void stopBackgroundMusic() { if (isMusicPlaying) { mciSendString("stop bgmusic", NULL, 0, NULL); mciSendString("close bgmusic", NULL, 0, NULL); isMusicPlaying = false; } } string intToString(int value) { stringstream ss; ss << value; return ss.str(); } void initGrid() { srand(static_cast<unsigned>(time(0))); bool hasMatches = true; while (hasMatches) { hasMatches = false; for (int i = 0; i < ROW; ++i) { for (int j = 0; j < COL; ++j) { grid[i][j] = rand() % NUM_COLORS; } } for (int i = 0; i < ROW; ++i) { for (int j = 0; j < COL - 2; ++j) { if (grid[i][j] == grid[i][j+1] && grid[i][j] == grid[i][j+2]) { hasMatches = true; break; } } if (hasMatches) break; } if (!hasMatches) { for (int j = 0; j < COL; ++j) { for (int i = 0; i < ROW - 2; ++i) { if (grid[i][j] == grid[i+1][j] && grid[i][j] == grid[i+2][j]) { hasMatches = true; break; } } if (hasMatches) break; } } } } void resetGame() { score = 0; remainingTime = GAME_DURATION; gameOver = false; selectedX = -1; selectedY = -1; isAnimating = false; gameState = PLAYING; // 使用QueryPerformanceCounter获取高精度时间 LARGE_INTEGER li; QueryPerformanceCounter(&li); gameStartTime = li.QuadPart; initGrid(); if (!isMusicPlaying) { playBackgroundMusic(); } } void drawGridPartial(int highlightX, int highlightY) { if (highlightX >= 0 && highlightY >= 0) { int x = highlightX, y = highlightY; setfillcolor(BLACK); solidrectangle(x * BLOCK_SIZE, y * BLOCK_SIZE, (x + 1) * BLOCK_SIZE, (y + 1) * BLOCK_SIZE); if (grid[y][x] != -1) { setfillcolor(COLORS[grid[y][x]]); solidrectangle(x * BLOCK_SIZE, y * BLOCK_SIZE, (x + 1) * BLOCK_SIZE, (y + 1) * BLOCK_SIZE); setlinecolor(BLACK); rectangle(x * BLOCK_SIZE, y * BLOCK_SIZE, (x + 1) * BLOCK_SIZE, (y + 1) * BLOCK_SIZE); } if (x == selectedX && y == selectedY) { setlinecolor(WHITE); setlinestyle(PS_SOLID, 3); rectangle(x * BLOCK_SIZE + 2, y * BLOCK_SIZE + 2, (x + 1) * BLOCK_SIZE - 2, (y + 1) * BLOCK_SIZE - 2); setlinestyle(PS_SOLID, 1); } return; } cleardevice(); settextstyle(24, 0, "Arial"); if (gameState == READY) { settextcolor(WHITE); settextstyle(36, 0, "Arial"); outtextxy(WINDOW_WIDTH/2 - 150, WINDOW_HEIGHT/2 - 60, "Block Game"); settextstyle(24, 0, "Arial"); outtextxy(WINDOW_WIDTH/2 - 100, WINDOW_HEIGHT/2, "Click to Start"); outtextxy(20, WINDOW_HEIGHT - 80, "Rules:"); outtextxy(20, WINDOW_HEIGHT - 50, "1. Swap adjacent blocks"); outtextxy(20, WINDOW_HEIGHT - 20, "2. Match 3+ to eliminate"); setfillcolor(isMusicPlaying ? GREEN : RED); solidrectangle(WINDOW_WIDTH - 120, 20, WINDOW_WIDTH - 20, 60); setlinecolor(WHITE); rectangle(WINDOW_WIDTH - 120, 20, WINDOW_WIDTH - 20, 60); settextcolor(WHITE); outtextxy(WINDOW_WIDTH - 110, 30, isMusicPlaying ? "Music:ON" : "Music:OFF"); return; } for (int i = 0; i < ROW; ++i) { for (int j = 0; j < COL; ++j) { if(grid[i][j] != -1) { setfillcolor(COLORS[grid[i][j]]); solidrectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j + 1) * BLOCK_SIZE, (i + 1) * BLOCK_SIZE); setlinecolor(BLACK); rectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j + 1) * BLOCK_SIZE, (i + 1) * BLOCK_SIZE); if (i == selectedY && j == selectedX) { setlinecolor(WHITE); setlinestyle(PS_SOLID, 3); rectangle(j * BLOCK_SIZE + 2, i * BLOCK_SIZE + 2, (j + 1) * BLOCK_SIZE - 2, (i + 1) * BLOCK_SIZE - 2); setlinestyle(PS_SOLID, 1); } } else { setfillcolor(BLACK); setlinecolor(DARKGRAY); rectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j + 1) * BLOCK_SIZE, (i + 1) * BLOCK_SIZE); } } } setfillcolor(DARKGRAY); solidrectangle(0, ROW * BLOCK_SIZE, WINDOW_WIDTH, WINDOW_HEIGHT); settextcolor(WHITE); string scoreStr = "Score: " + intToString(score); outtextxy(20, ROW * BLOCK_SIZE + 20, scoreStr.c_str()); string timeStr = "Time: " + intToString(remainingTime) + "s"; outtextxy(WINDOW_WIDTH/2 - 80, ROW * BLOCK_SIZE + 20, timeStr.c_str()); setfillcolor(isMusicPlaying ? GREEN : RED); solidrectangle(20, ROW * BLOCK_SIZE + 10, 120, ROW * BLOCK_SIZE + 40); setlinecolor(WHITE); rectangle(20, ROW * BLOCK_SIZE + 10, 120, ROW * BLOCK_SIZE + 40); settextcolor(WHITE); outtextxy(30, ROW * BLOCK_SIZE + 15, isMusicPlaying ? "Music:ON" : "Music:OFF"); setfillcolor(LIGHTGRAY); solidrectangle(WINDOW_WIDTH - 120, ROW * BLOCK_SIZE + 10, WINDOW_WIDTH - 20, ROW * BLOCK_SIZE + 40); setlinecolor(WHITE); rectangle(WINDOW_WIDTH - 120, ROW * BLOCK_SIZE + 10, WINDOW_WIDTH - 20, ROW * BLOCK_SIZE + 40); settextcolor(BLACK); outtextxy(WINDOW_WIDTH - 110, ROW * BLOCK_SIZE + 15, "Main Menu"); if (gameOver) { settextcolor(RED); settextstyle(36, 0, "Arial"); outtextxy(WINDOW_WIDTH/2 - 120, WINDOW_HEIGHT/2 - 30, "Game Over!"); settextstyle(24, 0, "Arial"); string finalScoreStr = "Final: " + intToString(finalScore); outtextxy(WINDOW_WIDTH/2 - 100, WINDOW_HEIGHT/2 + 20, finalScoreStr.c_str()); } if (gameState == TIME_UP) { setfillcolor(0x7F000000); solidrectangle(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); settextcolor(WHITE); settextstyle(36, 0, "Arial"); outtextxy(WINDOW_WIDTH/2 - 120, WINDOW_HEIGHT/2 - 60, "Time Up!"); settextstyle(24, 0, "Arial"); string finalScoreStr = "Score: " + intToString(finalScore); outtextxy(WINDOW_WIDTH/2 - 80, WINDOW_HEIGHT/2, finalScoreStr.c_str()); setfillcolor(GREEN); solidrectangle(WINDOW_WIDTH/2 - 100, WINDOW_HEIGHT/2 + 50, WINDOW_WIDTH/2 + 100, WINDOW_HEIGHT/2 + 100); setlinecolor(WHITE); rectangle(WINDOW_WIDTH/2 - 100, WINDOW_HEIGHT/2 + 50, WINDOW_WIDTH/2 + 100, WINDOW_HEIGHT/2 + 100); settextcolor(WHITE); outtextxy(WINDOW_WIDTH/2 - 40, WINDOW_HEIGHT/2 + 65, "Restart"); } } bool hasPossibleMoves() { for (int i = 0; i < ROW; ++i) { for (int j = 0; j < COL - 1; ++j) { swap(grid[i][j], grid[i][j+1]); bool matchFound = false; for (int r = max(0, i-1); r <= min(ROW-1, i+1); ++r) { for (int c = max(0, j-2); c <= min(COL-3, j+2); ++c) { if (c < 0 || c+2 >= COL) continue; if (grid[r][c] != -1 && grid[r][c] == grid[r][c+1] && grid[r][c] == grid[r][c+2]) { matchFound = true; break; } } if (matchFound) break; } if (!matchFound) { for (int c = max(0, j-1); c <= min(COL-1, j+1); ++c) { for (int r = max(0, i-2); r <= min(ROW-3, i+2); ++r) { if (r < 0 || r+2 >= ROW) continue; if (grid[r][c] != -1 && grid[r][c] == grid[r+1][c] && grid[r][c] == grid[r+2][c]) { matchFound = true; break; } } if (matchFound) break; } } swap(grid[i][j], grid[i][j+1]); if (matchFound) return true; } } for (int j = 0; j < COL; ++j) { for (int i = 0; i < ROW - 1; ++i) { swap(grid[i][j], grid[i+1][j]); bool matchFound = false; for (int r = max(0, i-1); r <= min(ROW-1, i+1); ++r) { for (int c = max(0, j-2); c <= min(COL-3, j+2); ++c) { if (c < 0 || c+2 >= COL) continue; if (grid[r][c] != -1 && grid[r][c] == grid[r][c+1] && grid[r][c] == grid[r][c+2]) { matchFound = true; break; } } if (matchFound) break; } if (!matchFound) { for (int c = max(0, j-1); c <= min(COL-1, j+1); ++c) { for (int r = max(0, i-2); r <= min(ROW-3, i+2); ++r) { if (r < 0 || r+2 >= ROW) continue; if (grid[r][c] != -1 && grid[r][c] == grid[r+1][c] && grid[r][c] == grid[r+2][c]) { matchFound = true; break; } } if (matchFound) break; } } swap(grid[i][j], grid[i+1][j]); if (matchFound) return true; } } return false; } int processMatches() { vector<vector<bool>> toRemove(ROW, vector<bool>(COL, false)); int matchCount = 0; for (int i = 0; i < ROW; ++i) { for (int j = 0; j < COL - 2; ) { if (grid[i][j] != -1 && grid[i][j] == grid[i][j + 1] && grid[i][j] == grid[i][j + 2]) { int k = j + 2; while (k < COL && grid[i][j] == grid[i][k]) { k++; } for (int pos = j; pos < k; ++pos) { toRemove[i][pos] = true; matchCount++; } j = k; } else { j++; } } } for (int j = 0; j < COL; ++j) { for (int i = 0; i < ROW - 2; ) { if (grid[i][j] != -1 && grid[i][j] == grid[i + 1][j] && grid[i][j] == grid[i + 2][j]) { int k = i + 2; while (k < ROW && grid[i][j] == grid[k][j]) { k++; } for (int pos = i; pos < k; ++pos) { toRemove[pos][j] = true; matchCount++; } i = k; } else { i++; } } } if (matchCount > 0) { static int comboCount = 0; comboCount++; int comboBonus = max(0, comboCount - 1) * 5; score += matchCount * 10 + comboBonus; } else { static int comboCount = 0; comboCount = 0; } for (int i = 0; i < ROW; ++i) { for (int j = 0; j < COL; ++j) { if (toRemove[i][j]) { grid[i][j] = -1; } } } return matchCount; } void dropBlocksAnimated() { HighResTimer timer; timer.start(); vector<vector<int>> newPositions(COL); vector<vector<int>> temp(COL); for (int j = 0; j < COL; ++j) { for (int i = ROW - 1; i >= 0; --i) { if (grid[i][j] != -1) { temp[j].push_back(grid[i][j]); } } int newBlocks = ROW - temp[j].size(); for (int i = 0; i < newBlocks; ++i) { temp[j].push_back(rand() % NUM_COLORS); } for (int i = 0; i < ROW; ++i) { newPositions[j].push_back(temp[j][ROW - 1 - i]); } } const double animationDuration = 0.3; vector<vector<int>> originalGrid = grid; while (true) { double elapsed = timer.elapsed(); if (elapsed >= animationDuration) break; double progress = min(1.0, elapsed / animationDuration); for (int j = 0; j < COL; ++j) { for (int i = 0; i < ROW; ++i) { if (originalGrid[i][j] != -1 && newPositions[j][i] != originalGrid[i][j]) { int targetY = i; while (targetY < ROW && grid[targetY][j] != newPositions[j][i]) { targetY++; } if (targetY < ROW) { double currentY = i + (targetY - i) * progress; setfillcolor(COLORS[originalGrid[i][j]]); solidrectangle(j * BLOCK_SIZE, static_cast<int>(currentY * BLOCK_SIZE), (j + 1) * BLOCK_SIZE, static_cast<int>((currentY + 1) * BLOCK_SIZE)); setlinecolor(BLACK); rectangle(j * BLOCK_SIZE, static_cast<int>(currentY * BLOCK_SIZE), (j + 1) * BLOCK_SIZE, static_cast<int>((currentY + 1) * BLOCK_SIZE)); } } } } FlushBatchDraw(); Sleep(10); } for (int j = 0; j < COL; ++j) { for (int i = 0; i < ROW; ++i) { grid[i][j] = newPositions[j][i]; } } } void handleMouseClick() { if (isAnimating) return; if (MouseHit()) { MOUSEMSG msg = GetMouseMsg(); // 使用GetTickCount()代替chrono long long now = GetTickCount(); if (now - lastClickTime < MIN_CLICK_INTERVAL) { return; } lastClickTime = now; if (gameState == READY && msg.uMsg == WM_LBUTTONDOWN) { resetGame(); return; } if (gameState == TIME_UP && msg.uMsg == WM_LBUTTONDOWN) { int x = msg.x; int y = msg.y; if (x >= WINDOW_WIDTH/2 - 100 && x <= WINDOW_WIDTH/2 + 100 && y >= WINDOW_HEIGHT/2 + 50 && y <= WINDOW_HEIGHT/2 + 100) { resetGame(); return; } } if (msg.uMsg == WM_LBUTTONDOWN) { int x = msg.x; int y = msg.y; if (x >= 20 && x <= 120 && y >= ROW * BLOCK_SIZE + 10 && y <= ROW * BLOCK_SIZE + 40) { if (isMusicPlaying) { stopBackgroundMusic(); } else { playBackgroundMusic(); } drawGridPartial(-1, -1); FlushBatchDraw(); return; } if (x >= WINDOW_WIDTH - 120 && x <= WINDOW_WIDTH - 20 && y >= ROW * BLOCK_SIZE + 10 && y <= ROW * BLOCK_SIZE + 40) { gameState = READY; selectedX = -1; selectedY = -1; gameOver = false; drawGridPartial(-1, -1); FlushBatchDraw(); return; } } if (msg.uMsg == WM_LBUTTONDOWN) { int x = msg.x / BLOCK_SIZE; int y = msg.y / BLOCK_SIZE; if (x >= 0 && x < COL && y >= 0 && y < ROW && grid[y][x] != -1 && gameState == PLAYING) { if (selectedX == -1) { selectedX = x; selectedY = y; drawGridPartial(x, y); FlushBatchDraw(); } else if (selectedX == x && selectedY == y) { selectedX = -1; selectedY = -1; drawGridPartial(x, y); FlushBatchDraw(); } else if ((abs(selectedX - x) == 1 && selectedY == y) || (abs(selectedY - y) == 1 && selectedX == x)) { isAnimating = true; int prevX = selectedX, prevY = selectedY; HighResTimer swapTimer; swapTimer.start(); const double swapDuration = 0.2; while (true) { double elapsed = swapTimer.elapsed(); if (elapsed >= swapDuration) break; double progress = min(1.0, elapsed / swapDuration); int offsetX = static_cast<int>((x - prevX) * progress * BLOCK_SIZE); int offsetY = static_cast<int>((y - prevY) * progress * BLOCK_SIZE); setfillcolor(BLACK); solidrectangle(prevX * BLOCK_SIZE, prevY * BLOCK_SIZE, (prevX + 1) * BLOCK_SIZE, (prevY + 1) * BLOCK_SIZE); solidrectangle(x * BLOCK_SIZE, y * BLOCK_SIZE, (x + 1) * BLOCK_SIZE, (y + 1) * BLOCK_SIZE); setfillcolor(COLORS[grid[prevY][prevX]]); solidrectangle(prevX * BLOCK_SIZE + offsetX, prevY * BLOCK_SIZE + offsetY, (prevX + 1) * BLOCK_SIZE + offsetX, (prevY + 1) * BLOCK_SIZE + offsetY); setfillcolor(COLORS[grid[y][x]]); solidrectangle(x * BLOCK_SIZE - offsetX, y * BLOCK_SIZE - offsetY, (x + 1) * BLOCK_SIZE - offsetX, (y + 1) * BLOCK_SIZE - offsetY); FlushBatchDraw(); Sleep(10); } swap(grid[prevY][prevX], grid[y][x]); bool matched = false; if (processMatches() > 0) { matched = true; } if (!matched) { swap(grid[prevY][prevX], grid[y][x]); drawGridPartial(prevX, prevY); drawGridPartial(x, y); FlushBatchDraw(); } else { while (true) { dropBlocksAnimated(); if (processMatches() == 0) break; } gameOver = !hasPossibleMoves(); } selectedX = selectedY = -1; isAnimating = false; } else { int oldX = selectedX, oldY = selectedY; selectedX = x; selectedY = y; if (oldX >= 0 && oldY >= 0) { drawGridPartial(oldX, oldY); } drawGridPartial(x, y); FlushBatchDraw(); } } else if (selectedX >= 0 || selectedY >= 0) { int oldX = selectedX, oldY = selectedY; selectedX = selectedY = -1; if (oldX >= 0 && oldY >= 0) { drawGridPartial(oldX, oldY); } FlushBatchDraw(); } } } } void keyListenerThread() { while (!exitFlag) { if (_kbhit()) { char ch = _getch(); if (ch == 27) { exitFlag = true; break; } } Sleep(50); } } int main() { initgraph(WINDOW_WIDTH, WINDOW_HEIGHT); initGrid(); playBackgroundMusic(); BeginBatchDraw(); thread keyThread(keyListenerThread); HighResTimer frameTimer; const double targetFPS = 120.0; const double frameTime = 1.0 / targetFPS; while (!exitFlag) { frameTimer.start(); if (gameState == PLAYING) { // 使用QueryPerformanceCounter计算剩余时间 LARGE_INTEGER now, frequency; QueryPerformanceCounter(&now); QueryPerformanceFrequency(&frequency); double elapsedSeconds = static_cast<double>(now.QuadPart - gameStartTime) / frequency.QuadPart; remainingTime = max(0, GAME_DURATION - static_cast<int>(elapsedSeconds)); if (remainingTime == 0) { gameState = TIME_UP; finalScore = score; } if (gameOver) { finalScore = score; } } drawGridPartial(-1, -1); handleMouseClick(); FlushBatchDraw(); double elapsed = frameTimer.elapsed(); if (elapsed < frameTime) { int sleepTime = static_cast<int>((frameTime - elapsed) * 1000); if (sleepTime > 0) { Sleep(sleepTime); } } } exitFlag = true; if (keyThread.joinable()) { keyThread.join(); } stopBackgroundMusic(); EndBatchDraw(); closegraph(); return 0; }把页面所展示的英文转换为中文,便于理解
06-18
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值