做了很多注释,不懂的话就评论问我吧,会尽量回答的 这是一个控制window桌面图标,化作贪吃蛇和食物的游戏。学会了就发给女朋友玩吧。 b站视频 https://www.bilibili.com/vi
做了很多注释,不懂的话就评论问我吧,会尽量回答的
这是一个控制window桌面图标,化作贪吃蛇和食物的游戏。学会了就发给女朋友玩吧。
b站视频
https://www.bilibili.com/video/BV1h64y1f7Hy
.用桌面图标玩贪吃蛇【C++】【想要源码的找我吧】
.核心代码
1.开启独立线程, 获取桌面宽高,隐藏界面
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow){ hInst = hInstance; // 将实例句柄存储在全局变量中 HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0,200,200, nullptr, nullptr, hInstance, nullptr); if (!hWnd) { return FALSE; } //ShowWindow(hWnd, nCmdShow);//不显示界面 就注释 //UpdateWindow(hWnd); //不显示界面 就注释 //随机值种子 srand(time(0)); //桌面宽高 nScreenWith = GetSystemMetrics(SM_CXSCREEN); nScreenHeight = GetSystemMetrics(SM_CYSCREEN); thread gameLogicThread(OnGameLogicRun); gameLogicThread.detach(); return TRUE;}
二。
游戏核心逻辑
注意:每次移动和判断是否吃到食物都是以网格为基础的,宽高由nStep指定。
int nCurDir = 1; //当前方向 右1 下2 左3 上4int nTargetDir = 1; //目标方向int runInterval = 250; //移动间隔 毫秒int nScore = 0; //得分int nIconScore = 10; //图标得分int nStep = 50; //每次移动的距离 int nFirstPosX = 10 * nStep; //蛇的初始位置xint nFirstPosY = 10 * nStep; //蛇的初始位置y int nFoodPosX = -1; //目标食物的位置xint nFoodPosY = -1; //目标食物的位置y int nScreenWith; //桌面宽int nScreenHeight; //桌面高 enum eDir{ DIR_RIGHT = 1, DIR_DOWN, DIR_LEFT, DIR_UP,}; //标记蛇节点的索引int nSnakeNodeIndex = 0;//蛇的每一个节点class CSnakeNode{public: CSnakeNode(); void SetPos(int x, int y) { m_posX = x; m_posY = y; } void GetPos(int& x, int& y) { x = m_posX; y = m_posY; } int m_index;private: int m_posX; int m_posY; };CSnakeNode::CSnakeNode(){ ++nSnakeNodeIndex; m_index = nSnakeNodeIndex;} //链表存整个蛇的身体list<CSnakeNode> SnakeNodeList; bool CreateFood(HWND handle){ if (SnakeNodeList.size() >= ListView_GetItemCount(handle)) { //桌面图标被吃完了 return false; } //TODO 随机创建食物,窗口范围内且不能在蛇的身体上 int randNumX = rand() % 10000; int randNumY = rand() % 10000; randNumX = (int)((double)nScreenWith* (randNumX / 10000.0)); randNumY = (int)((double)nScreenHeight * (randNumY / 10000.0)); int gridX = ((double)randNumX / nStep); //处于第几个格子上 int gridY = ((double)randNumY / nStep); //处于第几个格子上 nFoodPosX = gridX * nStep; //格子的位置 nFoodPosY = gridY * nStep; //格子的位置 int foodIndex = SnakeNodeList.size(); ::SendMessage(handle, LVM_SETITEMPOSITION, foodIndex, MAKELPARAM(nFoodPosX, nFoodPosY)); return true;} //更新蛇的位置//param nFirstPosX nFirstPosY:蛇头的位置//蛇身跟随蛇头,以此类推,后面的节点跟前面的走void UpdateSnakePos(HWND handle,int nHeadPosX,int nHeadPosY){ if (SnakeNodeList.begin() == SnakeNodeList.end()) return; int nLastPosX = 0; int nLastPosY = 0; CSnakeNode* head = &SnakeNodeList.front(); //记录蛇头上一个位置 head->GetPos(nLastPosX, nLastPosY); //更新蛇头的位置 head->SetPos(nHeadPosX, nHeadPosY); ::SendMessage(handle, LVM_SETITEMPOSITION, 0, MAKELPARAM(nHeadPosX, nHeadPosY)); int index = 0; for (auto iter = SnakeNodeList.begin(); iter != SnakeNodeList.end(); ++iter) { if (index == 0) { ++index; continue;//蛇头前面已经更新了 } int nRecordX = 0, nRecordY = 0; iter->GetPos(nRecordX, nRecordY); iter->SetPos(nLastPosX, nLastPosY); //记录节点的上一个位置 nLastPosX = nRecordX; nLastPosY = nRecordY; ::SendMessage(handle, LVM_SETITEMPOSITION, index ++ , MAKELPARAM(nLastPosX, nLastPosY)); }} void OnGameLogicRun(){ HWND hwndParent = ::FindWindow(_T("Progman"), _T("Program Manager")); HWND hwndSHELLDLL_DefView = ::FindWindowEx(hwndParent, NULL, _T("SHELLDLL_DefView"), NULL); HWND hwndSysListView32 = ::FindWindowEx(hwndSHELLDLL_DefView, NULL, _T("SysListView32"), _T("FolderView")); /*某些系统可能获取不到句柄,需要用spy++再确定,有需要可以评论问我*/ //这里会将所有桌面图标放到0 0的位置,后面可以右键桌面设置对齐网格还原图标位置 int iconCount = ListView_GetItemCount(hwndSysListView32); for (size_t i = 0; i < iconCount; i++) { ::SendMessage(hwndSysListView32, LVM_SETITEMPOSITION, i, MAKELPARAM(-100, -100)); } ListView_RedrawItems(hwndSysListView32, 0, iconCount - 1); ::UpdateWindow(hwndSysListView32); //创建蛇头 CSnakeNode nSnakeHead; nSnakeHead.SetPos(nFirstPosX, nFirstPosY); SnakeNodeList.push_front(nSnakeHead);//蛇头加入列表 //加一个节点的蛇身 CSnakeNode nNewNode; SnakeNodeList.push_back(nNewNode); //创建第一个目标食物 CreateFood(hwndSysListView32); DWORD nLastRunTick = 0; int i = 0; while (1) { //按esc退出游戏 if (GetKeyState(VK_ESCAPE) < 0) { DestroyWindow(hwndSysListView32); break; } else if (GetKeyState(VK_RIGHT) < 0) { if(nCurDir != DIR_LEFT)//不能选择反方向 nTargetDir = DIR_RIGHT; } else if (GetKeyState(VK_DOWN) < 0) { if (nCurDir != DIR_UP) nTargetDir = DIR_DOWN; } else if (GetKeyState(VK_LEFT) < 0) { if (nCurDir != DIR_RIGHT) nTargetDir = DIR_LEFT; } else if (GetKeyState(VK_UP) < 0) { if (nCurDir != DIR_DOWN) nTargetDir = DIR_UP; } if(GetTickCount() - nLastRunTick < runInterval) continue; nLastRunTick = GetTickCount(); //根据选择的方向,修改坐标 if (nTargetDir == DIR_RIGHT) { nCurDir = DIR_RIGHT; nFirstPosX += nStep; if (nFirstPosX > nScreenWith) nFirstPosX = nStep; } else if (nTargetDir == DIR_DOWN) { nFirstPosY += nStep; nCurDir = DIR_DOWN; if (nFirstPosY > nScreenHeight) nFirstPosY = nStep; } else if (nTargetDir == DIR_LEFT) { nFirstPosX -= nStep; nCurDir = DIR_LEFT; if (nFirstPosX < 0) nFirstPosX = (int)((double)nScreenWith / nStep) * nStep; } else if (nTargetDir == DIR_UP) { nCurDir = DIR_UP; nFirstPosY -= nStep; if (nFirstPosY < 0) nFirstPosY = (int)((double)nScreenHeight / nStep) * nStep; } UpdateSnakePos(hwndSysListView32, nFirstPosX, nFirstPosY); if (nFoodPosX == nFirstPosX && nFoodPosY == nFirstPosY) { //吃的食物 CSnakeNode nNewNode; SnakeNodeList.push_back(nNewNode); //吃一个给一个新的 CreateFood(hwndSysListView32); //提高游戏难度 runInterval -= 50; if (runInterval < 200) runInterval = 200; } //刷新蛇身的图标位置 ListView_RedrawItems(hwndSysListView32, 0, SnakeNodeList.size() -1 ); ::UpdateWindow(hwndSysListView32); } }
最后记得去掉桌面的这2个勾选:自动排列图标、将图标与网格对齐。
注意:游戏开始的时候会将所有图标挪到看不见的地方,游戏结束了再手动设置对齐网格就行了。
当然如果你的图标太少就玩不了。
收藏比赞多,证明写的东西还算有点用,顺手点个赞呗,赠人玫瑰手留余香,先行谢过!
有需要的话,下面是完整的工程压缩包,用vs打开。需要花点小钱(1.9元),毕竟要恰饭。
https://download.csdn.net/download/Yang9325/13634138