关注 码龄 粉丝数 原力等级 -- 被采纳 被点赞 采纳率 hello_world34 2024-05-31 21:29
采纳率: 0%
浏览 0 首页/
微软技术
/ 画面消失,但功能还在正常实现,窗口绘制出了问题 windowsc++ Windows编程做一个小游戏,但是运行到一半,画面突然消失。但是!但是游戏还在运行,键盘鼠标还能操控,只是画面看不见了(加了一个控制台打印输出)
跑着跑着就变这样了,在左边的控制台可以看到程序还在跑,并没有卡,猜测应该是窗口绘制出了问题,但也不知道为什么,具体哪里的问题
下面是跟绘制有关的代码
//游戏界面
void Mypaint(HDC hdc, RECT rect) {
if (mdc0 == NULL){
mdc0 = CreateCompatibleDC(hdc);
fullmap0 = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);
oldmap0 = (HBITMAP)SelectObject(mdc0, fullmap0);
}
hb = CreateSolidBrush(RGB(32, 33, 37));
FillRect(mdc0, &rect, hb);
//地图
gridmap.draw_map(mdc0, gridmap.l, gridmap.l.size());
/////////////////////////////////////////////////////////////////////////////////////
//视线
draw_view(mdc0, gridmap.l, gridmap.l.size());
//人物
draw_direction(mdc0);
if (a.isatk)
a.attack(mdc0);
//最后贴mdc到hdc上
BitBlt(hdc, 0, 0, rect.right, rect.bottom, mdc0, 0, 0, SRCCOPY);
_cprintf("g");
//记录时间
tPre = GetTickCount64();
}
//创造模式绘制
void Mypaint1(HDC hdc, RECT rect) {
if (mdc == NULL) {
mdc = CreateCompatibleDC(hdc);
fullmap = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);
oldmap = (HBITMAP)SelectObject(mdc, fullmap);
}
//背景
hb = CreateSolidBrush(RGB(32, 33, 37));
FillRect(mdc, &rect, hb);
//可动区域
hb = CreateSolidBrush(RGB(56, 58, 70));
SelectObject(mdc, hb);
Rectangle(mdc, drawRect.left, drawRect.top, drawRect.right, drawRect.bottom);
//按钮区域
hb = CreateSolidBrush(RGB(255, 255, 255));
SelectObject(mdc, hb);
Rectangle(mdc, revokeRect.left, revokeRect.top, revokeRect.right, revokeRect.bottom);
Rectangle(mdc, saveRect.left, saveRect.top, saveRect.right, saveRect.bottom);
DrawText(mdc, "撤销", strlen("撤销"), &revokeRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
DrawText(mdc, "保存", strlen("保存"), &saveRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
//绘制
hb = CreateSolidBrush(RGB(32, 33, 37));
SelectObject(mdc, hb);
hp = CreatePen(PS_SOLID, 3, RGB(78, 87, 100));
SelectObject(mdc, hp);
for (int i = 0; i < l.size(); i++) {
if (l[i].isline) {//线段
MoveToEx(mdc, l[i].st.x, l[i].st.y, NULL);
LineTo(mdc, l[i].ed.x, l[i].ed.y);
}
else//矩形块
Rectangle(mdc, l[i].st.x, l[i].st.y, l[i].ed.x, l[i].ed.y);
}
if (draw_l) {
MoveToEx(mdc, l_start.x, l_start.y, NULL);
LineTo(mdc, l_end.x, l_end.y);
}
if (draw_r) {
Rectangle(mdc, l_start.x, l_start.y, l_end.x, l_end.y);
}
//最后贴mdc到hdc上
BitBlt(hdc, 0, 0, rect.right, rect.bottom, mdc, 0, 0, SRCCOPY);
_cprintf("c");
//记录时间
tPre = GetTickCount64();
}
//主界面绘制
void Mypaint2(HDC hdc, RECT rect) {
if (mdc2 == NULL) {
mdc2 = CreateCompatibleDC(hdc);
fullmap2 = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);
oldmap2 = (HBITMAP)SelectObject(mdc2, fullmap2);
}
//背景
hb = CreateSolidBrush(RGB(32, 33, 37));
FillRect(mdc2, &rect, hb);
//按钮区域
hb = CreateSolidBrush(RGB(255, 255, 255));
SelectObject(mdc2, hb);
Rectangle(mdc2, titleRect.left, titleRect.top, titleRect.right, titleRect.bottom);
Rectangle(mdc2, gameRect.left, gameRect.top, gameRect.right, gameRect.bottom);
Rectangle(mdc2, createRect.left, createRect.top, createRect.right, createRect.bottom);
Rectangle(mdc2, quitRect.left, quitRect.top, quitRect.right, quitRect.bottom);
DrawText(mdc2, "标题", strlen("标题"), &titleRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
DrawText(mdc2, "进入游戏", strlen("进入游戏"), &gameRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
DrawText(mdc2, "创造地图", strlen("创造地图"), &createRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
DrawText(mdc2, "退出游戏", strlen("退出游戏"), &quitRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
BitBlt(hdc, 0, 0, rect.right, rect.bottom, mdc2, 0, 0, SRCCOPY);
_cprintf("m");
//记录时间
tPre = GetTickCount64();
}
然后是窗口处理函数
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lparam) {
PAINTSTRUCT ps;
RECT rect;
GetClientRect(hwnd, &rect);
bool flag;
POINT1 oldp;
POINT1 exp;
xNow = LOWORD(lparam);
yNow = HIWORD(lparam);
switch (message) {
case WM_LBUTTONDOWN:
if (isgame) {
a.isatk = true;
InvalidateRect(hwnd, NULL, false);
}
else if (isdraw) {
if (PtInRect(&drawRect, { xNow,yNow })) {//在可动区域,进行画图
draw_l = true;
l_start = { xNow,yNow };
}
}
break;
case WM_LBUTTONUP:
if (isgame) {//在游戏界面
a.isatk = false;
}
else if (ismain) {//在主界面
if (PtInRect(&gameRect, { xNow,yNow })) {
ismain = false;
isgame = true;
isdraw = false;
/////////////////////////////////////////////////////////////////
//进入游戏,加载地图
/////////////////////////////////////////////////////////////////
}
else if (PtInRect(&createRect, { xNow,yNow })) {
isdraw = true;
ismain = false;
isgame = false;
draw_l = false;
}
else if (PtInRect(&quitRect, { xNow,yNow })) {
PostMessage(hwnd, WM_QUIT, 0, 0);
}
InvalidateRect(hwnd, NULL, false);
}
else if (isdraw) {//在创造界面
if (PtInRect(&drawRect, { xNow,yNow })) {
draw_l = false;
l.push_back({ l_start,l_end,true });
}
else if (PtInRect(&revokeRect, { xNow,yNow })) {//在撤销区域,删除元素
if(!l.empty())
l.pop_back();//删除元素
InvalidateRect(hwnd, NULL, false);
}
else if (PtInRect(&saveRect, { xNow,yNow })) {//在保存(区域),进入游戏
isdraw = false;
isgame = true;
ismain = false;
/////////////////////////////////////////////////////////////////
//保存到文件
gridmap.setMap(l);
_cprintf("\n-------------------\n");
for (int i = 0; i < gridmap.l.size(); i++) {
_cprintf("(%d,%d)->(%d,%d)\n", gridmap.l[i].st.x, gridmap.l[i].st.y, gridmap.l[i].ed.x, gridmap.l[i].ed.y);
}
_cprintf("\n-------------------\n");
/////////////////////////////////////////////////////////////////
InvalidateRect(hwnd, NULL, false);
}
}
break;
case WM_RBUTTONDOWN:
if (isdraw) {
if (PtInRect(&drawRect, { xNow,yNow })) {//在可动区域,进行画图
draw_r = true;
l_start = { xNow,yNow };
}
}
InvalidateRect(hwnd, NULL, false);
break;
case WM_RBUTTONUP:
if (isdraw) {//在创造界面
if (PtInRect(&drawRect, { xNow,yNow })) {
draw_r = false;
l.push_back({ l_start,l_end,false });
}
}
break;
case WM_MOUSEMOVE:
l_end = { xNow,yNow };
if (isgame) {
//鼠标代表人物朝向
//获取鼠标和人物连线和水平向右的角度
//这就是人物朝向
face = -atan2(yNow - psrc.y, xNow - psrc.x);/////////返回弧度制
face = face * 180.0 / 3.14159;
}
InvalidateRect(hwnd, NULL, false);
UpdateWindow(hwnd);
break;
case WM_KEYDOWN://人物移动时,更新人物(定点)坐标
if(isgame){
oldp = psrc;
change_x = 0;
change_y = 0;
if (GetAsyncKeyState(VK_ESCAPE)) {//按下esc键,回到主界面
isgame = false;
ismain = true;
InvalidateRect(hwnd, NULL, false);
}
else if (GetAsyncKeyState(VK_RIGHT) && GetAsyncKeyState(VK_UP)) {
change_x = -1;
change_y = 1;
}
else if (GetAsyncKeyState(VK_RIGHT) && GetAsyncKeyState(VK_DOWN)) {
change_x = -1;
change_y = -1;
}
else if (GetAsyncKeyState(VK_LEFT) && GetAsyncKeyState(VK_UP)) {
change_x = 1;
change_y = 1;
}
else if (GetAsyncKeyState(VK_LEFT) && GetAsyncKeyState(VK_DOWN)) {
change_x = 1;
change_y = -1;
}
//四向
else if (GetAsyncKeyState(VK_UP)) {
change_x = 0;
change_y = 1;
}
else if (GetAsyncKeyState(VK_DOWN)) {
change_x = 0;
change_y = -1;
}
else if (GetAsyncKeyState(VK_LEFT)) {
change_x = 1;
change_y = 0;
}
else if (GetAsyncKeyState(VK_RIGHT)) {
change_x = -1;
change_y = 0;
}
//预期点
exp = psrc;
exp.x -= change_x * step_distance;
exp.y -= change_y * step_distance;
//碰撞检测
flag = false;
for (int i = 0; i < gridmap.l.size(); i++)
if (judge_cross(oldp, exp, gridmap.l[i])) {
//有碰撞,更新人物在交点上
flag = true;
exp = cal_p(oldp, exp, gridmap.l[i].st, gridmap.l[i].ed);
}
if (!flag)
psrc = exp;
//最终更新
a.updatePos(psrc);
InvalidateRect(hwnd, NULL, false);
}
break;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
//绘制
if (ismain)
Mypaint2(hdc, rect);
else if (isgame)
Mypaint(hdc, rect);
else if (isdraw)
Mypaint1(hdc, rect);
EndPaint(hwnd, &ps);
break;
case WM_DESTROY:
FreeConsole();
l.clear();
DeleteObject(mdc0);
DeleteObject(mdc);
DeleteObject(mdc2);
ReleaseDC(hwnd, hdc);
DeleteObject(hp);
DeleteObject(hb);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lparam);
}
展开全部
收起
写回答
好问题
0 提建议
追加酬金
关注问题
微信扫一扫 点击复制链接 分享 邀请回答
编辑 收藏 删除 结题 收藏 举报 追加酬金 (90%的用户在追加酬金后获得了解决方案) 当前问题酬金 ¥ 0
(可追加 ¥500)
¥ 15¥ 20¥ 50¥ 100¥ 200 支付方式 扫码支付
二维码出错
点击刷新
支付金额
15 元
提供问题酬金的用户不参与问题酬金结算和分配
支付即为同意
《付费问题酬金结算规则》 结题 再想想 删除 再等等
3条回答 默认 最新
关注
关注 以下内容由CHATGPT及阿里嘎多学长共同生成、有用望采纳:
根据你提供的信息和代码,画面消失但功能正常的问题可能与以下几个方面有关:
-
双缓冲问题:如果画面闪烁或消失,可能是由于没有正确实现双缓冲。双缓冲是一种技术,用于减少或消除屏幕撕裂和闪烁现象。在你的代码中,你创建了兼容的DC(Device Context)和位图,但没有明确实现双缓冲的代码。
-
资源释放问题:如果资源(如位图、画笔等)没有正确释放,可能会导致资源泄漏,从而影响窗口的正常绘制。在你的代码中,DeleteObject 应该在 WM_DESTROY 消息处理中被调用,以确保所有资源都被正确释放。
-
绘图代码逻辑:检查你的绘图逻辑,确保在绘制过程中没有覆盖或错误地清除了画面上的内容。
-
窗口重绘问题:InvalidateRect 用于指示指定的矩形区域需要重绘。如果调用了 InvalidateRect 但没有正确处理 WM_PAINT 消息,或者 BeginPaint 和 EndPaint 没有正确配对使用,可能会导致绘制问题。
-
线程问题:如果你的游戏逻辑和绘制在不同的线程中运行,需要确保线程间的同步和通信正确无误,否则可能会导致画面更新不及时或不一致。
为了解决这个问题,你可以尝试以下步骤:
- 实现双缓冲:确保你的绘图逻辑使用了双缓冲技术,这样可以减少画面闪烁和消失的问题。
- 检查资源释放:确保所有创建的资源(如位图、画笔等)在不再需要时被正确释放。
- 审查绘制逻辑:仔细检查你的绘制逻辑,确保没有逻辑错误导致画面被错误地清除或覆盖。
- 正确处理
WM_PAINT 消息:确保 WM_PAINT 消息被正确处理,BeginPaint 和 EndPaint 正确配对使用。 - 线程同步:如果使用了多线程,确保线程间的同步机制正确,避免竞态条件。
如果你需要具体的代码实现,我可以提供一个简单的双缓冲实现示例。但请注意,这只是一个示例,你可能需要根据自己的具体需求进行调整。
// 在 WM_CREATE 消息中初始化双缓冲
case WM_CREATE:
{
PIXELFORMATDESCRIPTOR pfd;
int iPixelFormatIndex;
// 获取当前窗口的设备上下文
HDC hdc = GetDC(hwnd);
// 零出PIXELFORMATDESCRIPTOR结构体
ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
// 设置结构体参数
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_WGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.iLayerType = PFD_MAIN_PLANE;
// 设置像素格式
iPixelFormatIndex = ChoosePixelFormat(hdc, &pfd);
SetPixelFormat(hdc, iPixelFormatIndex, &pfd);
// 创建渲染上下文
hglrc = wglCreateContext(hdc);
wglMakeCurrent(hdc, hglrc);
}
break;
// 在 WM_PAINT 消息中进行双缓冲绘图
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
HDC hdcMem = CreateCompatibleDC(hdc);
HBITMAP hbmMem = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);
HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hbmMem);
// 在内存DC上进行绘图
// ... 你的绘图代码 ...
// 将内存DC的内容复制到窗口DC
BitBlt(hdc, 0, 0, rect.right, rect.bottom, hdcMem, 0, 0, SRCCOPY);
// 清理资源
SelectObject(hdcMem, hbmOld);
DeleteObject(hbmMem);
DeleteDC(hdcMem);
EndPaint(hwnd, &ps);
}
break;
// 在 WM_DESTROY 消息中清理资源
case WM_DESTROY:
{
wglMakeCurrent(NULL, NULL);
wglDeleteContext(hglrc);
ReleaseDC(hwnd, GetDC(hwnd));
PostQuitMessage(0);
}
break;
请注意,这个示例使用了OpenGL的上下文,如果你的项目中没有使用OpenGL,你可能需要调整这部分代码以适应你的项目。
至于参考资料,你可以查看微软的官方文档,特别是关于双缓冲和窗口绘制的部分。这些文档提供了详细的信息和示例,可以帮助你更好地理解和实现窗口绘制。
本回答被题主选为最佳回答 , 对您是否有帮助呢? 本回答被专家选为最佳回答 , 对您是否有帮助呢? 本回答被题主和专家选为最佳回答 , 对您是否有帮助呢?
解决
无用
评论
打赏
微信扫一扫 点击复制链接
分享 举报
编辑记录
-
引自免费微信小程序:皆我百晓生
根据您提供的代码和描述,问题可能出在窗口重绘部分。当游戏界面中的画面消失后,控制台依然可以接收到输入并执行相应的操作,这表明程序逻辑仍在继续运行,只是窗口上的图形渲染出现了问题。
首先,检查一下几个关键点:
- 窗口是否正确初始化?确保你在创建窗口时指定了正确的窗口类。
- 你是否有正确设置窗口过程(
WndProc)? - 在
WM_CREATE消息处理中,你是否创建了必要的设备上下文(Device Context, DC)和位图(Bitmap)?
从代码上看,你在WM_PAINT处理函数中为不同状态的游戏、创造模式和主界面分别创建了不同的DC和位图。然而,如果窗口大小发生变化,这些资源可能需要重新创建。因此,你需要在WM_SIZE消息处理中添加相应的清理和创建操作。
以下是针对WM_SIZE消息处理的建议:
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
...
case WM_SIZE:
// 清理旧的DC和位图
if (mdc0) {
DeleteObject(mdc0);
DeleteObject(fullmap0);
mdc0 = NULL;
fullmap0 = NULL;
}
if (mdc) {
DeleteObject(mdc);
DeleteObject(fullmap);
mdc = NULL;
fullmap = NULL;
}
if (mdc2) {
DeleteObject(mdc2);
DeleteObject(fullmap2);
mdc2 = NULL;
fullmap2 = NULL;
}
// 依据新的窗口大小重新创建DC和位图
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rect;
GetClientRect(hwnd, &rect);
// 创建游戏界面的DC和位图
if (ismain || isgame)
Mypaint(hdc, rect);
// 创建创造模式的DC和位图
else if (isdraw)
Mypaint1(hdc, rect);
// 创建主界面的DC和位图
else
Mypaint2(hdc, rect);
EndPaint(hwnd, &ps);
break;
...
}
这个修改将确保在窗口大小改变时,相关的DC和位图会被正确地清理和重建。这样应该能解决画面消失的问题。不过,为了完全确定问题所在,你也可以考虑在代码的关键位置加入一些调试信息,比如在WM_SIZE、WM_PAINT等消息处理函数开始时打印一些日志,以便更好地了解窗口和DC的状态变化。
另外,考虑到代码的复杂性,建议对内存管理进行优化,确保每次创建的新对象都被正确释放,以防止内存泄漏。例如,在窗口关闭时,确保所有创建的对象都被释放。
如果你仍然遇到问题,可以尝试使用调试工具(如Visual Studio的调试器)来逐步执行代码,查看是否有未捕获的异常或错误。同时,确保所有的GDI对象(如DC、位图、刷子和笔)在不再需要时被正确地释放。
本回答被题主选为最佳回答 , 对您是否有帮助呢? 本回答被专家选为最佳回答 , 对您是否有帮助呢? 本回答被题主和专家选为最佳回答 , 对您是否有帮助呢?
解决
无用
评论
打赏
微信扫一扫 点击复制链接
分享 举报
编辑记录