仓库 : https://gitee.com/mrxiao_com/2d_game
整理了一些需要完成的任务,确保所有内容都已清理完成,因为需要为后续的数学部分打好基础。下一步将认真开始处理数学相关内容,因此在此之前,需要彻底梳理未完成的事项,清除任何可能的障碍。
昨天已经完成了一些重要的任务,其中包括为调试符号创建一个锁文件,以避免热加载时出现问题,从而防止开发工具出现混淆。这个改进解决了一些稳定性问题。
还完成了一个重要的调整,使平台层的开发更加顺利。一些内容被移到了独立的模块中,以便更好地支持跨平台的开发流程。这部分工作也已完成。
目前剩余的内容中,有一些需要进一步核实的修复任务,以及为后续开发提供支持的改动。这些任务会在接下来的整理过程中逐步处理,以确保流程顺畅。
清理 tSine
发现有一个变量 tSine
的旧版本仍然存在,虽然已经不再使用,但它仍留在 win32
的声音模块中。这部分内容需要清理,以免后续开发者看到这个变量时感到困惑,不清楚它的用途。
计划清除这些遗留的变量,以确保代码的整洁和易读性。同时,还会对平台代码进行进一步梳理和优化,移除无用的内容,使代码更清晰,便于后续维护和扩展。
修改一下cmake的文件
关于 internal
、local_persist
和 global_variable
的用意
在讨论中提到的主要概念是如何使用 static
关键字和宏在 C++ 代码中的影响。人们在论坛上对使用 static
感到困惑,因为它在 C++ 中有多种含义,而宏则是处理代码的文本替换工具。使用宏时,关键字 static
会被替换为实际的定义,这样会影响代码的可搜索性和易于维护性,尤其在多线程编程和动态库(DLL)加载的情况下。
主要问题是,如果所有函数都前缀 static
,它会使得自动化的代码搜索(grep)更加复杂,难以区分全局变量和局部变量。虽然宏在 C++ 中是必要的文本处理工具,但它们的使用可能带来可读性问题。
因此,开发者需要谨慎使用 static
和宏,以避免引入维护上的复杂性和潜在的错误。这就是为什么尽管有宏和 static
的便利,很多人还是倾向于使用较少的全局变量,并进行更加精细的依赖管理。
解决 SetCursor
你似乎在讨论应用程序中光标行为的问题,尤其是当光标进入窗口时的处理。你描述的问题是,由于你的软件没有响应 WM_SETCURSOR
消息,导致 Windows 不会改变光标状态,当它进入应用程序的窗口时。
为了解决这个问题,你计划实现一种机制来正确处理光标的变化。这包括:
- 检测光标进入应用窗口 :通过响应
WM_SETCURSOR
消息并设置一个适当的光标来处理当前的状态或上下文。 - 避免意外的行为:目前,由于光标在进入你的窗口之前的状态会保留,因此光标可能会看起来不正确。通过正确处理光标变化,可以避免这种问题,并确保当光标进入应用程序时总是显示适当的状态。
这项调整应改善用户体验,尤其是在编辑环境中光标的外观和行为尤为关键。
LoadCursor
是一个 Windows API 函数,用于加载光标资源。它的作用是从系统或者应用程序的资源文件中加载一个光标,并返回一个指向该光标的句柄。可以使用该光标句柄来设置窗口的光标或改变光标的样式。
函数原型
cpp
HCURSOR LoadCursor(
HINSTANCE hInstance, // 模块实例句柄,通常传入 NULL 表示加载系统光标
LPCSTR lpCursorName // 光标名称,或者是光标的资源标识符
);
参数说明
-
hInstance:
- 如果
hInstance
为NULL
,则会加载系统默认的光标资源(如箭头、等待光标等)。 - 如果
hInstance
为非NULL
,则会加载指定模块(如应用程序的.exe
文件)中的光标资源。
- 如果
-
lpCursorName:
- 这是光标的名称或标识符。如果是系统光标,你可以传入一些预定义的标识符(例如:
IDC_ARROW
、IDC_WAIT
)。 - 如果是自定义光标,
lpCursorName
则是自定义光标资源的名称(该光标资源应该被打包到应用程序的资源文件中)。
- 这是光标的名称或标识符。如果是系统光标,你可以传入一些预定义的标识符(例如:
返回值
- 返回一个光标的句柄(
HCURSOR
),如果加载失败,则返回NULL
。
常用的光标资源标识符
IDC_ARROW
: 默认的箭头光标。IDC_WAIT
: 等待光标(通常是一个旋转的圆圈)。IDC_IBEAM
: 输入框光标(I-beam 光标,用于文本输入框)。IDC_CROSS
: 十字光标(通常用于选择区域或进行截图等操作)。IDC_HAND
: 手形光标(通常用于网页上的链接)。
示例代码
-
加载默认光标 :
如果你只想加载系统默认的箭头光标,可以直接调用
LoadCursor
,并传入NULL
和IDC_ARROW
。cppHCURSOR hCursor = LoadCursor(NULL, IDC_ARROW);
-
加载自定义光标 :
如果应用程序中包含自定义光标资源,你可以使用
LoadCursor
来加载它:cppHCURSOR hCursor = LoadCursor(hInstance, MAKEINTRESOURCE(IDR_MY_CURSOR));
这里
IDR_MY_CURSOR
是你在资源文件中定义的光标资源标识符。 -
改变窗口的光标 :
你可以使用
SetCursor
函数将加载的光标设置为当前窗口的光标。cppSetCursor(hCursor);
使用场景
- 在自定义应用程序中使用不同的光标样式来提供视觉反馈(例如,鼠标悬停在按钮上时更改光标样式)。
- 在不同的操作状态下(如加载状态、文本输入状态等)显示不同的光标。
注意事项
LoadCursor
只能加载 16×16 或 32×32 像素的光标资源。如果需要加载更大的光标,通常可以使用LoadImage
函数。- 需要记得在程序结束时释放通过
LoadCursor
加载的光标资源,虽然 Windows 系统会在程序结束时自动清理这些资源,但在使用一些特殊光标时可以主动释放。
总结来说,LoadCursor
是一个非常基础但重要的函数,用于管理和加载系统或自定义光标,是 GUI 开发中不可或缺的一部分。
全屏支持
cpp
internal void ToggleFullscreen(HWND Window) {
DWORD Style = GetWindowLong(Window, GWL_STYLE); // 获取当前窗口的样式标志
if (Style & WS_OVERLAPPEDWINDOW) { // 如果窗口当前是一个常规的重叠窗口
MONITORINFO MonitorInfo = {
sizeof(MonitorInfo)}; // 创建一个 MONITORINFO 结构,用于存储显示器信息
// 获取当前窗口的位置和大小,并获取该窗口所在的显示器信息
if (GetWindowPlacement(Window, &GlobalWindowPosition) &&
GetMonitorInfo(MonitorFromWindow(Window, MONITOR_DEFAULTTONEAREST), &MonitorInfo)) {
// 将窗口的样式从重叠窗口(有标题栏、边框等)改为无边框窗口
SetWindowLong(Window, GWL_STYLE, Style & ~WS_OVERLAPPEDWINDOW);
// 设置窗口的位置和大小为当前显示器的工作区(全屏显示)
SetWindowPos(
Window, HWND_TOP, MonitorInfo.rcMonitor.left, MonitorInfo.rcMonitor.top,
MonitorInfo.rcMonitor.right - MonitorInfo.rcMonitor.left, // 设置窗口宽度
MonitorInfo.rcMonitor.bottom - MonitorInfo.rcMonitor.top, // 设置窗口高度
SWP_NOOWNERZORDER | SWP_FRAMECHANGED); // 不改变窗口的 Z 顺序,更新窗口的边框和样式
}
} else { // 如果当前窗口已经是全屏(没有边框)模式
// 恢复窗口为一个常规的重叠窗口(恢复边框和标题栏)
SetWindowLongA(Window, GWL_STYLE, Style | WS_OVERLAPPEDWINDOW);
// 恢复窗口到之前的位置和大小
SetWindowPlacement(Window, &GlobalWindowPosition);
// 设置窗口不改变位置和大小,只更新窗口的显示状态
SetWindowPos(Window, 0, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
}
}