前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >用桌面图标模拟FlappyBird游戏

用桌面图标模拟FlappyBird游戏

作者头像
六月丶
发布2022-12-26 18:15:45
8670
发布2022-12-26 18:15:45
举报
文章被收录于专栏:六月-游戏开发

实现效果

操作说明

注意需要先把自动排列图标和将图标与网格对齐关闭运行后可能会打乱图标排列。 空格控制开始与游戏中的跳跃。 ESC键结束程序。

实现逻辑

首先需要了解一下桌面图标的一些api,例如获取屏幕长宽,设置图标坐标这些,代码里有注释

游戏逻辑:

: 给他一个速度量和重力加速度量,初始速度为0,始终受到重力加速度影响,每当按下跳跃,将速度重设为一个跳跃速度量。 : 在墙的图标个数中随机取一个数,多于这个数的图标的y轴值加上图标大小*3(3指空三格),即可做到随机生成裂口。然后每次刷新让墙的所有图标的x轴值减少,即可做到墙的移动。 碰撞检测: 当鸟的坐标加一个身位会与墙发生重叠时,说明发生了碰撞,具体看代码。 因为比较懒,坠落检测之类的就没做了。需要完善的话可以自己加下。 如果需要隐藏控制台,把Init函数中的第一行注释掉的代码打开即可。

代码

BirdGame.h:

代码语言:javascript
复制
#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:

代码语言:javascript
复制
#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;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021 年 10 月,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 实现效果
  • 操作说明
  • 实现逻辑
    • 游戏逻辑:
    • 代码
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档