「C++趣味程序」之开心消消乐

一、引言

消消乐(Match-Three Game)是一种广泛流行的益智游戏。玩家需要通过交换两个相邻的方块,使得三个或以上颜色相同的方块连在一起,然后这些方块就会消失,同时加上相应的分数。在本篇文章中,我们将会介绍如何用C++来实现一个开心消消乐,希望能对初学者有所帮助。

二、准备工作

1. 游戏界面

在开发任何一个游戏之前,我们都需要先设计游戏界面。对于消消乐来说,游戏界面通常由一个二维的矩阵组成,我们可以用C++中的二维数组来实现。游戏界面还需要一些其他的元素,例如得分、计时器、帮助按钮等等。下面是一个简单的游戏界面设计:

+---------------------+

| Score: 0 |

| Time: 00:00 |

| Help |

+-----+-----+-----+---+

| X | X | X | X |

+-----+-----+-----+---+

| X | X | X | X |

+-----+-----+-----+---+

| X | X | X | X |

+-----+-----+-----+---+

2. 方块设计

在消消乐中,方块通常有不同的颜色,我们可以用一个整数来表示不同的颜色。另外,方块还需要一些其他的属性,例如位置、是否被选中等等。

struct Block {

int color; // 颜色

int x, y; // 位置

bool selected; // 是否被选中

};

三、实现游戏逻辑

1. 生成初始界面

在游戏开始时,需要生成一个随机的游戏界面。我们可以使用一个循环来生成随机的方块,并且确保没有连续三个颜色相同的方块。

const int kNumColors = 5; // 颜色数

const int kNumRows = 8; // 行数

const int kNumCols = 8; // 列数

Block board[kNumRows][kNumCols];

void InitGameBoard() {

// 初始化随机数生成器

srand(time(NULL));

// 生成随机的游戏界面

for (int i = 0; i < kNumRows; i++) {

for (int j = 0; j < kNumCols; j++) {

// 随机生成一个颜色

int color = rand() % kNumColors + 1;

// 如果有连续三个相同颜色的方块,则重新生成颜色

while ((i >= 2 && board[i-1][j].color == color && board[i-2][j].color == color) ||

(j >= 2 && board[i][j-1].color == color && board[i][j-2].color == color)) {

color = rand() % kNumColors + 1;

}

// 初始化方块

board[i][j].color = color;

board[i][j].x = j;

board[i][j].y = i;

board[i][j].selected = false;

}

}

}

2. 检查是否有相邻的三个颜色相同的方块

在消除方块之前,需要检查是否有相邻的三个颜色相同的方块。

bool CheckMatch() {

// 检查每一个方块是否有相邻的三个颜色相同的方块

for (int i = 0; i < kNumRows; i++) {

for (int j = 0; j < kNumCols; j++) {

if (i >= 2 && board[i-1][j].color == board[i-2][j].color && board[i-2][j].color == board[i][j].color) {

return true;

}

if (j >= 2 && board[i][j-1].color == board[i][j-2].color && board[i][j-2].color == board[i][j].color) {

return true;

}

}

}

return false;

}

3. 消除相邻的三个颜色相同的方块

如果有相邻的三个颜色相同的方块,则需要将它们消除,并且加上相应的分数。消除的方法是将它们标记为已选中,然后在界面上进行移动和填充。

int score = 0;

void EliminateBlocks() {

// 将被选中的方块消除,并且加上相应的分数

for (int i = 0; i < kNumRows; i++) {

for (int j = 0; j < kNumCols; j++) {

if (board[i][j].selected) {

board[i][j].color = 0;

score += 10;

}

}

}

// 移动剩下的方块

for (int i = kNumRows-1; i >= 0; i--) {

for (int j = 0; j < kNumCols; j++) {

if (board[i][j].color == 0) {

for (int k = i-1; k >= 0; k--) {

if (board[k][j].color != 0) {

board[i][j] = board[k][j];

board[k][j].color = 0;

break;

}

}

}

}

}

// 随机填充空白的方块

for (int i = 0; i < kNumRows; i++) {

for (int j = 0; j < kNumCols; j++) {

if (board[i][j].color == 0) {

int color = rand() % kNumColors + 1;

while ((i >= 2 && board[i-1][j].color == color && board[i-2][j].color == color) ||

(j >= 2 && board[i][j-1].color == color && board[i][j-2].color == color)) {

color = rand() % kNumColors + 1;

}

board[i][j].color = color;

}

}

}

}

4. 交换相邻的方块

当玩家点击了两个相邻的方块时,需要交换这两个方块,并且检查是否有相邻的三个颜色相同的方块。

bool SwapBlocks(Block &a, Block &b) {

if ((a.x == b.x && abs(a.y-b.y) == 1) || (a.y == b.y && abs(a.x-b.x) == 1)) {

// 交换两个相邻方块的位置

swap(a.color, b.color);

return true;

}

return false;

}

void SelectBlock(int x, int y) {

static Block *selected = NULL;

if (selected == NULL) { // 如果没有已选中的方块,则将当前方块标记为已选中

selected = &board[y][x];

selected->selected = true;

} else { // 如果有已选中的方块,则尝试交换它们,并且检查是否有相邻的三个颜色相同的方块

if (SwapBlocks(*selected, board[y][x])) {

if (CheckMatch()) {

EliminateBlocks();

} else {

SwapBlocks(*selected, board[y][x]);

}

}

selected->selected = false;

selected = NULL;

}

}

四、完整代码

以下是完整的代码:

#include <iostream>

#include <ctime>

#include <cstdlib>

using namespace std;

const int kNumColors = 5; // 颜色数

const int kNumRows = 8; // 行数

const int kNumCols = 8; // 列数

struct Block {

int color; // 颜色

int x, y; // 位置

bool selected; // 是否被选中

};

Block board[kNumRows][kNumCols];

void InitGameBoard() {

// 初始化随机数生成器

srand(time(NULL));

// 生成随机的游戏界面

for (int i = 0; i < kNumRows; i++) {

for (int j = 0; j < kNumCols; j++) {

// 随机生成一个颜色

int color = rand() % kNumColors + 1;

// 如果有连续三个相同颜色的方块,则重新生成颜色

while ((i >= 2 && board[i-1][j].color == color && board[i-2][j].color == color) ||

(j >= 2 && board[i][j-1].color == color && board[i][j-2].color == color)) {

color = rand() % kNumColors + 1;

}

// 初始化方块

board[i][j].color = color;

board[i][j].x = j;

board[i][j].y = i;

board[i][j].selected = false;

}

}

}

bool CheckMatch() {

// 检查每一个方块是否有相邻的三个颜色相同的方块

for (int i = 0; i < kNumRows; i++) {

for (int j = 0; j < kNumCols; j++) {

if (i >= 2 && board[i-1][j].color == board[i-2][j].color && board[i-2][j].color == board[i][j].color) {

return true;

}

if (j >= 2 && board[i][j-1].color == board[i][j-2].color && board[i][j-2].color == board[i][j].color) {

return true;

}

}

}

return false;

}

void EliminateBlocks() {

// 将被选中的方块消除,并且加上相应的分数

for (int i = 0; i < kNumRows; i++) {

for (int j = 0; j < kNumCols; j++) {

if (board[i][j].selected) {

board[i][j].color = 0;

score += 10;

}

}

}

// 移动剩下的方块

for (int i = kNumRows-1; i >= 0; i--) {

for (int j = 0; j < kNumCols; j++) {

if (board[i][j].color == 0) {

for (int k = i-1; k >= 0; k--) {

if (board[k][j].color != 0) {

board[i][j] = board[k][j];

board[k][j].color = 0;

break;

}

}

}

}

}

// 随机填充空白的方块

for (int i = 0; i < kNumRows; i++) {

for (int j = 0; j < kNumCols; j++) {

if (board[i][j].color == 0) {

int color = rand() % kNumColors + 1;

while ((i >= 2 && board[i-1][j].color == color && board[i-2][j].color == color) ||

(j >= 2 && board[i][j-1].color == color && board[i][j-2].color == color)) {

color = rand() % kNumColors + 1;

}

board[i][j].color = color;

}

}

}

}

bool SwapBlocks(Block &a, Block &b) {

if ((a.x == b.x && abs(a.y-b.y) == 1) || (a.y == b.y && abs(a.x-b.x) == 1)) {

// 交换两个相邻方块的位置

swap(a.color, b.color);

return true;

}

return false;

}

void SelectBlock(int x, int y) {

static Block *selected = NULL;

if (selected == NULL) { // 如果没有已选中的方块,则将当前方块标记为已选中

selected = &board[y][x];

selected->selected = true;

} else { // 如果有已选中的方块,则尝试交换它们,并且检查是否有相邻的三个颜色相同的方块

if (SwapBlocks(*selected, board[y][x])) {

if (CheckMatch()) {

EliminateBlocks();

} else {

SwapBlocks(*selected, board[y][x]);

}

}

selected->selected = false;

selected = NULL;

}

}

int main() {

InitGameBoard();

// TODO: 添加游戏界面和用户交互的代码

return 0;

}

五、总结

通过本文的介绍,我们学习了如何用C++来实现一个简单的消消乐游戏。消消乐游戏涉及到了很多常见的问题,例如随机数生成、二维数组、结构体等等,这些知识点对于C++的学习和应用都有很大的帮助。

后端开发标签