本项目需要EasyX图形库,若没有可在www.easyx.cn网上下载哦 !
可以选择一个游戏音乐哦!
- mciSendString函数
Parameters
lpszCommand
指向一个以空结束的字符串的指针,该字符串指定一个MCI命令字符串。有关列表,请参见多媒体命令字符串。
lpszReturnString
指向接收返回信息的缓冲区的指针。如果不需要返回信息,该参数可以为NULL。
cchReturn
由lpszReturnString参数指定的返回缓冲区的大小(以字符为单位)。
hwndCallback
如果在命令字符串中指定了"notify"标志,则回调窗口的句柄。
#include <Windows.h>
#pragma comment(lib,"winmm.lib")
编译器:Visual Studio Professional 2019
源码:
#include <easyx.h>
#include <string.h>
#include <map>
#include <sstream>
#include <time.h>
#include <conio.h>
#pragma comment( lib, "MSIMG32.LIB")
// 方块的状态
enum State
{
EXIST, // 存在
DESTORY // 销毁
};
// 二维向量,用于表示位置或者大小
struct Vector2
{
float x;
float y;
};
// 符号函数
int sgn(float d)
{
if (d < 0) return -1;
if (d > 0) return 1;
return 0;
}
class Block
{
private:
State currentState; // 当前的状态
State targetState; // 移动后的状态
Vector2 size;
Vector2 currentPos; // 当前位置
Vector2 targetPos; // 目标位置
IMAGE *img;
IMAGE *newImg;
float deltaPos; // 每秒移动多少位置
float deltaSize; // 每秒变大多少
float animationSpeed; // 动画速度
public:
Block(const Vector2 &pos, IMAGE *img)
{
currentPos = targetPos = pos;
currentState = targetState = EXIST;
size = {
50,50 };
this->img = this->newImg = img;
deltaPos = 100;
deltaSize = 40;
animationSpeed = 20.0f;
}
void update(float deltaTime)
{
// 改变方块大小(图片刚生成时的由小到大的动画)
if (size.x < img->getwidth())
{
size.x = size.y = size.x + deltaSize * deltaTime * animationSpeed / 2;
if (size.x > img->getwidth())
{
size.x = size.y = (float)img->getwidth();
}
}
// 更新方块位置
if (currentPos.x != targetPos.x || currentPos.y != targetPos.y)
{
int directionX = sgn(targetPos.x - currentPos.x);
int directionY = sgn(targetPos.y - currentPos.y);
currentPos.x += deltaPos * directionX * deltaTime * animationSpeed;
// 相距小于 5 视为在同一位置
if (fabs(currentPos.x - targetPos.x) < 5)
{
currentPos.x = targetPos.x;
}
currentPos.y += deltaPos * directionY * deltaTime * animationSpeed;
if (fabs(currentPos.y - targetPos.y) < 5)
{
currentPos.y = targetPos.y;
}
}
if (currentPos.x == targetPos.x &¤tPos.y == targetPos.y)
{
currentState = targetState;
img = newImg;
}
}
void draw()
{
TransparentBlt(GetImageHDC(NULL), int(currentPos.x + (90 - size.x) / 2), int(currentPos.y + (90 - size.y) / 2),
(int)size.x, (int)size.y, GetImageHDC(img), 0, 0, img->getwidth(), img->getheight(), BLACK);
}
// 把方块从当前位置移动到目标位置,移动后改变状态
void MoveTo(const Vector2 &pos, IMAGE *newImg, State state = EXIST)
{
targetPos = pos;
targetState = state;
this->newImg = newImg;
}
State getState()
{
return currentState;
}
};
int map[4][4]; // 4 * 4 地图
Block *blockMap[4][4]; // 方块索引
int score; // 得分
int maxScore; // 最高得分
int currentMaxBlock; // 当前最大方块
int maxBlock; // 历史最大方块
int gameLoop; // 游戏循环
float keyTime = 0; // 按键间隔
std::map<int, IMAGE> image; // 存储所有数字图像
bool gameOver = false; // 游戏是否结束
float overTime; // 游戏结束后不会立刻退出循环,而是等待 0.5s 更新动画
// 判断是否有可移动的方式,有返回 1 ,没有返回 0
// 检测思路:如果碰到为 0 的格子,或者两个相邻的格子数字相等,则返回 1
int Judge()
{
// 横向检测
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 3; j++)
{
if (map[i][j] == 0 || map[i][j] == map[i][j + 1] || map[i][j + 1] == 0)
return 1;
}
}
// 纵向检测
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 3; j++)
{
if (map[j][i] == 0 || map[j][i] == map[j + 1][i] || map[j + 1][i] == 0)
return 1;
}
}
return 0;
}
// 上移
void Up()
{
int moveFlag = 0; // 记录是否进行过移动
int mergeFlag = 0; // 记录是否合并过
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 3; j++)
{
int k, z;
// 找到一个不为 0 的方块向上移动,并判断是否可以和下边的方块合并
for (k = j; k < 4; k++)
if (map[k][i] != 0)
break;
// 寻找右边不为 0 的方块
for (z = k + 1; z < 4; z++)
if (map[z][i] != 0)
break;
// 当前行有非 0 方块
if (k < 4)
{
if (z < 4 && map[k][i] == map[z][i])
{
// 可以合并
int value = map[k][i] + map[z][i];
map[k][i] = map[z][i] = 0;
map[j][i] = value;
// 开启动画
Block *temp = blockMap[k][i];
blockMap[k][i] = NULL;
blockMap[j][i] = temp;
blockMap[j][i]->MoveTo({
25.0f + 100 * i,225.0f + 100 * j }, &image[map[j][i]]);
blockMap[z][i]->MoveTo({
25.0f + 100 * i,225.0f + 100 * (j + 1) }, &image[map[z]