图像不会绘制到屏幕 C++

Posted

技术标签:

【中文标题】图像不会绘制到屏幕 C++【英文标题】:Image wont draw to screen C++ 【发布时间】:2010-02-22 21:23:09 【问题描述】:

我正在学习教程。我正在尝试将 .bmp 文件绘制到屏幕上。它构建没有错误,但没有出现图像。根据这本书,我应该看到图像在随机位置弹出。下面是我的代码。作者不推荐这种技术来绘制对象,他只是为了演示。万一你想知道。

图片是一个 25x25 的红色正方形。

#include <windows.h>
#include <iostream>
#include <time.h>

using namespace std;

const string APPTITLE = "Game Loop";
HWND window;
HDC device;
bool gameover = false;


void DrawBitmap(char *filename, int x, int y)

 //load the bitmap image
 HBITMAP image = (HBITMAP)LoadImage(0,"c.bmp", IMAGE_BITMAP,0,0, LR_LOADFROMFILE);

 BITMAP bm;
 GetObject(image, sizeof(BITMAP), &bm);

 HDC hdcImage = CreateCompatibleDC(device);
 SelectObject(hdcImage,image);

 BitBlt(
  device,
  x,y,
  bm.bmWidth, bm.bmHeight,
  hdcImage,
  0,0,
  SRCCOPY);

 //deletec the device context and bitmap
 DeleteDC(hdcImage);
 DeleteObject((HBITMAP)image);


bool Game_Init()

 srand(time(NULL));
 return 1;


void Game_Run()

 if(gameover == true) return;

 RECT rect;
 GetClientRect(window, &rect);

 //draw bitmap at random location
 int x = rand() % (rect.right - rect.left);
 int y = rand() % (rect.bottom - rect.top);

 DrawBitmap("c.bmp",x,y);


void Game_End()

 //free the device
 ReleaseDC(window,device);


LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM WParam, LPARAM lparam)

 switch(message)
 
  case WM_DESTROY:
   gameover = true;
   PostQuitMessage(0);
  break;
 

 return DefWindowProc(hWnd, message, WParam, lparam);


ATOM MyRegisterClass(HINSTANCE hInstance)

 //set the new windows properties

 WNDCLASSEX wc;

 wc.cbSize  = sizeof(WNDCLASSEX);
 wc.style  = CS_HREDRAW | CS_VREDRAW;
 wc.lpfnWndProc = (WNDPROC) WinProc;
 wc.cbClsExtra = 0;
 wc.cbWndExtra = 0;
 wc.hInstance = hInstance;
 wc.hIcon  = NULL;
 wc.hCursor  = LoadCursor(NULL, IDC_ARROW);
 wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
 wc.lpszMenuName = NULL;
 wc.lpszClassName= APPTITLE.c_str();
 wc.hIconSm  = NULL;

 return RegisterClassEx(&wc);


bool InitInstance(HINSTANCE hInstance, int nCmdShow)

 //create a  new window
 window = CreateWindow(
  APPTITLE.c_str(),
  APPTITLE.c_str(),
  WS_OVERLAPPEDWINDOW,
  CW_USEDEFAULT, CW_USEDEFAULT,
  640,480,
  NULL,
  NULL,
  hInstance,
  NULL);

 //was there an error creating the window ?
 if(window == 0) return 0;

 //display the window 
 ShowWindow(window, nCmdShow);
 UpdateWindow(window);
 device = GetDC(window);

 return 1;


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
      LPSTR lpCmdLine, int nCmdShow)

 //declare variables
 MSG msg;

 //register the class
 MyRegisterClass(hInstance);

 //initialize application
 if(!InitInstance(hInstance, nCmdShow)) return 0;

 //initilize the game
 if(!Game_Init()) return 0;

 //main message loop
 while(!gameover)
 
  if(PeekMessage(&msg,NULL, 0, 0,PM_REMOVE))
  
   TranslateMessage(&msg);
   DispatchMessage(&msg);
  
  Game_Run();
 

 Game_End();

 return msg.wParam;

我不确定是不是因为我把图片放在了错误的位置。但如果是这样的话。我认为它会引发错误。我将图像放在源文件夹的根目录下。

[编辑]

另外,当我重建时,我收到一个警告,这可能是一个原因,但这里是警告

1>------ Rebuild All started: Project: Begin, Configuration: Debug Win32 ------
1>Deleting intermediate and output files for project 'Begin', configuration 'Debug|Win32'
1>Compiling...
1>main.cpp
1>c:\users\numerical25\documents\visual studio 2008\projects\begin\begin\main.cpp(39) : warning C4244: 'argument' : conversion from 'time_t' to 'unsigned int', possible loss of data
1>Compiling manifest to resources...
1>Microsoft (R) Windows (R) Resource Compiler Version 6.1.6723.1
1>Copyright (C) Microsoft Corporation.  All rights reserved.
1>Linking...
1>LINK : C:\Users\numerical25\Documents\Visual Studio 2008\Projects\Begin\Debug\Begin.exe not found or not built by the last incremental link; performing full link
1>Embedding manifest...
1>Microsoft (R) Windows (R) Resource Compiler Version 6.1.6723.1
1>Copyright (C) Microsoft Corporation.  All rights reserved.
1>Build log was saved at "file://c:\Users\numerical25\Documents\Visual Studio 2008\Projects\Begin\Begin\Debug\BuildLog.htm"
1>Begin - 0 error(s), 1 warning(s)
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

【问题讨论】:

您需要检查 Win32 函数调用的结果。其中任何一个都可能失败,没有人会知道。 只是好奇,你如何在 C++ 中跟踪?也许这可能会帮助我弄清楚功能是否失败。因为如果它这样做了,函数不会停止吗?? 不,如果一个函数失败,它不会停止,它只是返回一个错误指示,你可以得到一个错误代码。查看每个 Windows 调用的文档以获取详细信息。 Visual Studio 将单步执行程序,如果您想检查单个点,则在一行上停止。 【参考方案1】:

代码确实有效,您只是忘记将c.bmp 放在正确的位置。如果您从资源管理器启动程序,则将其放入项目输出文件夹(即 bin/Debug);如果您从 Visual Studio 启动程序,则将其放入项目文件夹。

【讨论】:

成功了。我不确定图像相对于应用程序的运行位置。但相对于 .exe 文件运行是有道理的。谢谢 我数不清那天我写了多少简单的小游戏,我会花几个小时挠头,直到我意识到这一点……每一次。【参考方案2】:

对于“工作”的足够宽松的定义,您的代码似乎有效。除非你已经修改了代码(相当多的)以使其工作,否则我的建议是找到一个不同的教程来遵循——至少对我来说,现在的大部分内容都很不起眼。

例如,Game_Run() 将位图文件的名称作为参数传递给Draw_Bitmap(),但该参数被忽略,Draw_Bitmap() 使用硬编码的文件名。

PeekMessage() 循环使程序看起来像是在大约 25 年前编写的,当时是 16 位 Windows 时代(即使在那时也可以说不是那么好)。在新代码中使用PeekMessage() 很少(如果有的话)有充分的理由,而且确实使用它的代码可能早就应该进行大修了。主循环通常使用GetMessage(),您可以(例如)使用SetTimer(持续时间为0)计算绘制位图的新坐标,然后调用InvalidateRect() 进行绘制。曾经有一个公平的论点认为,其中涉及的额外消息会导致过多的开销,但在现代机器上,它会在使用大约 10% 或更少的 CPU 时跟上显示器刷新率。

但是,为了降低 CPU 使用率,您需要稍微重构代码 - 现在,每次绘制时,您都会获得窗口矩形,从磁盘重新加载 BMP,将 BMP 选择到兼容的 DC ,最后BitBlting 将图像显示在屏幕上。这就是优化将产生影响的代码部分——根据强烈的偏好,您希望它只需调用BitBlt 并完成。其余代码应移至其他地方,以便仅在需要时发生。例如,您可以检索响应WM_SIZE 的窗口矩形,并将其保存在中间。由于您在持续时间内使用相同的位图,请加载一次,然后从它们中显示它。

【讨论】:

是的,我注意到 Draw_Bitmap() 中的忽略参数。以及。我纠正了它。我正在努力为这本书找一个勘误表。本书为《游戏编程入门》第三版。阿瑟还表示,这种格式将是他在书中最后一次使用的格式,他承认这不是绘制对象的正确方法。他正在演示如果您不使用直接 x sdk,您将如何渲染对象。这是本书的开头,只是为了让事情顺利进行。我打算再给它一个机会。 @numerical25:即使不使用 DirectX,这也不是真正(至少在 IMO)绘制任何东西的“正确”方式。

以上是关于图像不会绘制到屏幕 C++的主要内容,如果未能解决你的问题,请参考以下文章

在屏幕上绘制图像后背景发生变化

如何在 C++ 中使用 glutBitmapString() 将文本绘制到屏幕上?

Gdiplus::屏幕上的图像 (C++)

将对象放入容器类时,OpenGL 不绘制

如何在 p5.js 中裁剪图像而不在屏幕上绘制图像

Directx C++ - 绘制 DNA 形状