注意需要先把自动排列图标和将图标与网格对齐关闭,运行后可能会打乱图标排列。 空格控制开始与游戏中的跳跃。 ESC键结束程序。
首先需要了解一下桌面图标的一些api,例如获取屏幕长宽,设置图标坐标这些,代码里有注释
鸟: 给他一个速度量和重力加速度量,初始速度为0,始终受到重力加速度影响,每当按下跳跃,将速度重设为一个跳跃速度量。 墙: 在墙的图标个数中随机取一个数,多于这个数的图标的y轴值加上图标大小*3(3指空三格),即可做到随机生成裂口。然后每次刷新让墙的所有图标的x轴值减少,即可做到墙的移动。 碰撞检测: 当鸟的坐标加一个身位会与墙发生重叠时,说明发生了碰撞,具体看代码。 因为比较懒,坠落检测之类的就没做了。需要完善的话可以自己加下。 如果需要隐藏控制台,把Init函数中的第一行注释掉的代码打开即可。
BirdGame.h:
#pragma once
#include<vector>
struct Bird {
int idx; //对应图标下标
int x, y; //坐标
int hSpeed = 0; //纵向速度
int lastRefreshTime;
const double JUMP_ADD_SPEED;
static const double G; //重力加速度
Bird(int _idx, int _x, int _y, const double _JUMP_ADD_SPEED);
Bird() = default;
void Jump(); //跳跃
void Print(); //打印
void Refresh(); //刷新信息
void SetLocation(int x, int y); //设置坐标
};
struct WallBlock {
int idx;
int x, y;
};
struct Wall {
static const int SPACE_NUM; //中间空几格
std::vector<WallBlock> wallBlocks;
int lastRefreshTime;
int upRand;
Wall(int beginIdx);
bool Refresh(); //返回是否走到终点
void Print();
bool IsOverlap(int x, int y); //返回传入坐标是否与墙发生overlap
};
void StartGame_Bird();
//暂停游戏,按空格继续
void StopGame();
//初始化游戏
void Init();
BirdGame.cpp:
#include "BirdGame.h"
#include <Windows.h>
#include <ShlObj.h>
#include <ctime>
#include<iostream>
using namespace std;
HWND desktop; //桌面句柄
int iconCount; //图标个数
int screenX; //获取屏幕的分辨率(宽)
int screenY; //获取屏幕的分辨率(高)
const int ICON_SIZE{ 80 }; //图标间隔
const double MAP_SPEED{700};
void Init() {
//属性初始化
//ShowWindow(GetConsoleWindow(), SW_HIDE); //隐藏控制台
srand(unsigned int(time(NULL)));
HWND grandpa = FindWindowA("Progman", "Program Manager");
HWND father = FindWindowExA(grandpa, NULL, "SHELLDLL_DefView", NULL);
desktop = FindWindowExA(father, 0, "SysListView32", "FolderView");
iconCount = SendMessage(desktop, LVM_GETITEMCOUNT, 0, 0); //获取句柄中控件的个数
screenX = GetSystemMetrics(SM_CXSCREEN); //获取屏幕的分辨率(宽)
screenY = GetSystemMetrics(SM_CYSCREEN); //获取屏幕的分辨率(高)
//隐藏图标
for (int i = 0; i < iconCount; i++)
SendMessageA(desktop, LVM_SETITEMPOSITION, i, (screenY << 16) + screenX);
}
Bird::Bird(int _idx, int _x, int _y, const double _JUMP_ADD_SPEED = 700)
: idx{ _idx }, x{ _x }, y{ _y }, lastRefreshTime{ clock() }, JUMP_ADD_SPEED(_JUMP_ADD_SPEED) {}
const double Bird::G{ 2400 };
void Bird::Jump() {
hSpeed = JUMP_ADD_SPEED;
}
void Bird::Print() {
//cout << this->x << " " << this->y << endl;
SendMessageA(desktop, LVM_SETITEMPOSITION, this->idx, (screenY - this->y << 16) + this->x);
}
void Bird::SetLocation(int x, int y) {
this->x = x; this->y = y;
}
void Bird::Refresh() {
double curTime = clock();
double rateTime = (curTime - lastRefreshTime) / CLOCKS_PER_SEC;
lastRefreshTime = curTime;
y += hSpeed * rateTime - 0.5 * G * rateTime * rateTime;
hSpeed -= G * rateTime;
Print();
}
const int Wall::SPACE_NUM{ 5 };
Wall::Wall(int beginIdx) : lastRefreshTime{clock()} {
int wallNum = (screenY + ICON_SIZE) / ICON_SIZE - SPACE_NUM;
cout << "wallNum = " << wallNum << endl;
upRand = rand() % (wallNum) + 1; //1~wallNum-1
for (int i = 0; i < wallNum; i++) {
wallBlocks.push_back({ beginIdx + i, (screenX + ICON_SIZE) - (screenX + ICON_SIZE) % ICON_SIZE, i * ICON_SIZE + (i < upRand ? 0 : SPACE_NUM * ICON_SIZE) });
}
}
//返回是否已经走到终点
bool Wall::Refresh() {
double curTime = clock();
double rateTime = (curTime - lastRefreshTime) / CLOCKS_PER_SEC;
lastRefreshTime = curTime;
if (wallBlocks[0].x - rateTime * MAP_SPEED < 0) {
return true;
}
for (WallBlock &wallBlock : wallBlocks) {
wallBlock.x -= rateTime * MAP_SPEED;
}
Print();
return false;
}
void Wall::Print() {
for (int i = 0; i < wallBlocks.size(); i++) {
SendMessageA(desktop, LVM_SETITEMPOSITION, wallBlocks[i].idx, (wallBlocks[i].y << 16) + wallBlocks[i].x);
}
}
bool Wall::IsOverlap(int x, int y) {
if (y < -ICON_SIZE or y > screenY + ICON_SIZE) //越界
return false;
if (x > wallBlocks[0].x + ICON_SIZE or x + ICON_SIZE < wallBlocks[0].x) //x方向没碰到墙
return false;
if (y < upRand * ICON_SIZE or y + ICON_SIZE >(upRand + SPACE_NUM) * ICON_SIZE)
return true;
return false;
}
void StartGame_Bird() {
int startTime = clock();
Init();
Bird bird(0, screenX / 3, screenY / 2);
bird.Print();
Wall *wall = new Wall(1);
StopGame();
bird.lastRefreshTime = clock();
wall->lastRefreshTime = clock();
while (true) {
if (GetAsyncKeyState(VK_ESCAPE) or (clock() - startTime) / CLOCKS_PER_SEC > 2000)
exit(0);
bird.Refresh();
if (wall->IsOverlap(bird.x, screenY - bird.y)) {
MessageBox(desktop, TEXT("你死了,游戏结束!"), TEXT(""), MB_OK | MB_ICONEXCLAMATION);
exit(0);
}
if (GetAsyncKeyState(VK_SPACE))
bird.Jump();
bool isOver = wall->Refresh();
if (isOver) {
delete wall;
wall = new Wall(1);
}
Sleep(20);
}
}
//暂停游戏,按空格继续
void StopGame() {
while (true) {
if (GetAsyncKeyState(VK_SPACE))break;
Sleep(300);
}
}
int main() {
StartGame_Bird();
return 0;
}