21xrx.com
2025-03-29 19:31:11 Saturday
文章检索 我的文章 写文章
C++ ImGui实现血条界面
2023-07-10 13:31:54 深夜i     --     --
C++ ImGui 血条 界面 实现

在游戏开发中,血条界面是一个非常重要的元素,能够直观地显示角色的生命值,帮助玩家更好地掌握游戏场景。本文将介绍如何使用C++和ImGui实现一款简单的血条界面。

步骤一:新建工程

首先,我们需要在Visual Studio中新建一个空项目。在该项目中创建一个源文件,我们将在这个文件中编写我们的代码。为了使用ImGui,我们还需要在项目中引入ImGui的头文件和源文件。可以在ImGui的官网上下载ImGui的源码,然后将其中的imgui.cpp和imgui.h文件添加到我们的项目中。此外,我们还需要添加ImGui的源码所在目录到项目的包含目录中。

步骤二:初始化ImGui

在启动应用程序时,我们需要初始化ImGui库,并创建一个ImGui的窗口。以下是初始化ImGui的代码:

IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
ImGui::StyleColorsDark();
ImGui_ImplWin32_Init(hwnd); // hwnd为窗口句柄
ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);

在以上代码中,IMGUI_CHECKVERSION() 用于检查当前ImGui的版本号,ImGui::CreateContext() 用于创建一个ImGui的上下文。接下来,我们设置ImGui的颜色主题为暗色,可以根据个人喜好设置。

最后,我们需要调用 ImGui_ImplWin32_Init(hwnd) 和 ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext) 初始化ImGui窗口,其中hwnd为窗口句柄,g_pd3dDevice和g_pd3dDeviceContext分别为D3D设备和D3D设备上下文。

步骤三:绘制血条

接下来,我们需要编写代码来绘制我们的血条。我们可以使用ImGui的ImDrawList类来绘制我们的血条。以下是绘制血条的代码:

ImGuiIO& io = ImGui::GetIO();
ImDrawList* draw_list = ImGui::GetWindowDrawList();
ImVec2 p = ImGui::GetCursorScreenPos();
const float percent = 0.65f;
const ImVec2 size = ImVec2(100, 8);
const ImVec4 filled_color = ImVec4(0.4f, 0.8f, 0.4f, 1.0f);
const ImVec4 unfilled_color = ImVec4(0.8f, 0.4f, 0.4f, 1.0f);
draw_list->AddRectFilled(p, ImVec2(p.x + size.x, p.y + size.y), unfilled_color, 4.0f);
draw_list->AddRectFilled(p, ImVec2(p.x + size.x * percent, p.y + size.y), filled_color, 4.0f);

在以上代码中,我们首先获取ImGui的IO对象,并获取窗口的绘制列表。接着,我们获取窗口当前位置,可以将血条绘制在窗口的上下文中。我们使用percent变量来控制血条的填充百分比,size变量控制血条的大小,filled_color和unfilled_color分别表示血条填充部分和未填充部分的颜色。

使用AddRectFilled方法,我们可以快速的绘制一个矩形,并填充其颜色。最后一个参数为矩形的圆角值。

步骤四:渲染ImGui窗口

最后一步是渲染ImGui窗口,我们需要在主循环中调用以下代码:

ImGui_ImplDX11_NewFrame();
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
// 在这里绘制我们的UI元素
DrawHealthBar();
ImGui::Render();
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());

在以上代码中,我们首先调用三个函数初始化ImGui的新一帧。接着,我们绘制我们的UI元素,也就是我们的血条,在本例中是通过DrawHealthBar()函数来绘制的。最后,我们调用 ImGui::Render() 和 ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()) 渲染ImGui窗口。

完整代码示例:

#include "imgui.h"
#include "imgui_impl_dx11.h"
#include "imgui_impl_win32.h"
#include <d3d11.h>
#include <Windows.h>
void DrawHealthBar()
{
  ImGuiIO& io = ImGui::GetIO();
  ImDrawList* draw_list = ImGui::GetWindowDrawList();
  ImVec2 p = ImGui::GetCursorScreenPos();
  const float percent = 0.65f;
  const ImVec2 size = ImVec2(100, 8);
  const ImVec4 filled_color = ImVec4(0.4f, 0.8f, 0.4f, 1.0f);
  const ImVec4 unfilled_color = ImVec4(0.8f, 0.4f, 0.4f, 1.0f);
  draw_list->AddRectFilled(p, ImVec2(p.x + size.x, p.y + size.y), unfilled_color, 4.0f);
  draw_list->AddRectFilled(p, ImVec2(p.x + size.x * percent, p.y + size.y), filled_color, 4.0f);
}
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
    return true;
  switch (msg)
  {
  case WM_PAINT:
  {
    ImGui_ImplDX11_NewFrame();
    ImGui_ImplWin32_NewFrame();
    ImGui::NewFrame();
    // 在这里绘制我们的UI元素
    DrawHealthBar();
    ImGui::Render();
    ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
    ValidateRect(hWnd, NULL);
  }
  break;
  case WM_DESTROY:
    ::PostQuitMessage(0);
    break;
  default:
    return ::DefWindowProc(hWnd, msg, wParam, lParam);
  }
  return false;
}
int main()
{
  // 创建窗口
  WNDCLASS wc = { 0 };
  wc.lpfnWndProc = WndProc;
  wc.hInstance = ::GetModuleHandle(NULL);
  wc.lpszClassName = "ImGui Example";
  ::RegisterClass(&wc);
  HWND hwnd = ::CreateWindow(wc.lpszClassName,
    "ImGui Example",
    WS_OVERLAPPEDWINDOW,
    100, 100,
    640, 480,
    NULL,
    NULL,
    wc.hInstance,
    NULL);
  // 初始化D3D设备和ImGui
  ID3D11Device* g_pd3dDevice = NULL;
  ID3D11DeviceContext* g_pd3dDeviceContext = NULL;
  DXGI_SWAP_CHAIN_DESC sd;
  ZeroMemory(&sd, sizeof(sd));
  sd.BufferCount = 1;
  sd.BufferDesc.Width = 640;
  sd.BufferDesc.Height = 480;
  sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
  sd.BufferDesc.RefreshRate.Numerator = 60;
  sd.BufferDesc.RefreshRate.Denominator = 1;
  sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
  sd.OutputWindow = hwnd;
  sd.SampleDesc.Count = 1;
  sd.SampleDesc.Quality = 0;
  sd.Windowed = TRUE;
  D3D_FEATURE_LEVEL feature_level;
  DXGI_SWAP_EFFECT swap_effect;
  if (D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &feature_level, &g_pd3dDeviceContext) == S_OK)
    swap_effect = DXGI_SWAP_EFFECT_DISCARD;
  else if (D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_WARP, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &feature_level, &g_pd3dDeviceContext) == S_OK)
    swap_effect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
  else
    return 1;
  if (!ImGui_ImplWin32_Init(hwnd)) return 1;
  if (!ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext)) return 1;
  // 显示窗口
  ShowWindow(hwnd, SW_SHOWDEFAULT);
  UpdateWindow(hwnd);
  // 进入主循环
  MSG msg;
  ZeroMemory(&msg, sizeof(msg));
  while (msg.message != WM_QUIT)
  {
    if (::PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
    {
      ::TranslateMessage(&msg);
      ::DispatchMessage(&msg);
      continue;
    }
  }
  // 清理ImGui
  ImGui_ImplDX11_Shutdown();
  ImGui_ImplWin32_Shutdown();
  ImGui::DestroyContext();
  // 清理D3D设备和窗口
  if (g_pd3dDeviceContext) g_pd3dDeviceContext->ClearState();
  if (g_pSwapChain) g_pSwapChain->Release();
  if (g_pd3dDeviceContext) g_pd3dDeviceContext->Release();
  if (g_pd3dDevice) g_pd3dDevice->Release();
  DestroyWindow(hwnd);
  ::UnregisterClass(wc.lpszClassName, wc.hInstance);
  return 0;
}

总结

本文介绍了如何使用C++和ImGui实现血条界面,并提供了一段示例代码。通过本文的学习,希望可以帮助大家更好地掌握ImGui的使用方法和技巧,加快游戏开发的速度和效率。

  
  

评论区