[摘要]MB_YESNO, 0); if (Control="=" IDYES) InitializeGame(); else break; //如果有人移动了 //如果屏幕已更新...
MB_YESNO, 0); if (Control="=" IDYES) InitializeGame(); else break; } } //如果有人移动了 } //如果屏幕已更新 } //结束循环 while (TRUE);
---- 前 面 已 经 提 到 过, 这 里 没 有 检 查 是 否 运 行 超 时, 请 忽 略 它, 笔 者 在 Windows 版 中 未 实 现 它 是 为 了 避 免 令 人 烦 恼 的 中 断。 中 断 并 退 出 无 限 循 环 的 机 制 有 一 点 儿 而 且 并 不 重 要。 我 们 把 精 力 集 中 在 消 息 循 环 本 身, 所 以 把 其 它 的 无 关 代 码 都 删 掉, 只 留 下 最 基 本 的 部 分:
do
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else DoSomething();
}
while (TRUE)
---- 这 是 一 个 非 常 典 型 的 消 息 循 环。 唯 一 有 点 特 殊 的 地 方 就 是 它 使 用 的 是 PeekMessage 而 不 是 GetMessage。
GetMessage 与 PeekMessage 的 比 较
---- 为 什 么 要 用 PeekMessage 呢 ? 原 因 很 简 单,GetMessage 等 待 一 个 消 息( 就 像 _getch), 而 PeekMessage 不 是 这 样( 就 像_kbhit)。 请 考 虑 下 面 的 循 环:
while (GetMessage(&msg, NULL, 0, 0))
{
// 我 们 并 不 进 入 括 号 内 部, 直 到 有 一 个 消 息
TranslateMessage(&msg);
DispatchMessage(&msg);
DoSomething()
}
// 当 GetMessage 返 回 NULL 时, 退 出 该 程 序
return msg.wParam;
---- 在 这 里,DoSomething 不 会 完 成, 除 非 一 个 消 息-- 或 许 多 消 息-- 被 放 入 队 列 中 并 被 处 理。 如 果 DoSomething 恰 好 产 生 一 个 消 息, 例 如, 如 果 它 更 新 了 屏 幕 并 且 因 此 而 产 生 了 一 个 WM_PAINT 消 息, 那 么 好 了, 水 泵 注 水 后 将 开 始 启 动 了。 要 使 DoSomething 可 靠 地 完 成 其 工 作, 这 并 不 是 一 个 好 方 法, 它 使 代 码 有 点 混 淆, 但 它 工 作 的 还 不 错。
---- 相 比 之 下,PeekMessage 则 无 论 是 否 有 消 息 在 等 待, 只 要 检 查 一 下 消 息 队 列 就 完 成 其 操 作(yields the floor)。 在 我 们 的 例 子 中, 我 们 实 际 上 是 使 用 PeekMessage 来 处 理 消 息 的( 通 过 分 发 它 所 找 到 的 每 一 个 消 息 并 使 用 PM_REMOVE 参 数 从 队 列 中 清 除 它)。 同 下 面 同 样 有 效 的 代 码 相 比, 它 要 更 加 直 接:
if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if (!GetMessage(&msg, NULL, 0, 0)) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else DoSomething();
---- 在 这 里 有 非 常 重 要 的 一 点 要 说 明, 我 们 的 伪 代 码 DoSomething 是 独 立 于 消 息 的; 无 论 队 列 中 送 出 的 什 么 消 息, 甚 至 无 论 有 没 有 消 息 在 那 儿, 它 都 将 执 行。 在 Moby Dick 中, 我 们 将 屏 幕 更 新 和 胜 利 条 件 的 检 查 放 在 这 里, 因 为 在 这 里 检 查 一 个 或 多 个 消 息 被 响 应 后 是 否 需 要 更 新 屏 幕 或 是 否 达 到 胜 利 条 件 很 方 便。
---- 那 么, 消 息 循 环 就 是 游 戏 循 环 吗 ? 从 抽 象 的 角 度, 是 的, 因 为 它 是 大 的 齿 轮, 带 动 那 些 小 的 齿 轮。 但 是, 尽 管 把 一 些 函 数 调 用 放 在 此 处 可 能 比 较 方 便,Windows 编 程 规 则 却 要 求 任 何 响 应 一 个 消 息 的 动 作 都 应 该 放 在 消 息 响 应 程 序 中( 就 是 说, 放 在 窗 口 过 程 中)。 在 一 个 实 时 游 戏 中, 绝 大 多 数 的 动 作 发 生 在 一 个 或 多 个 WM_TIMER 消 息 响 应 程 序 中。 回 合 制 游 戏 则 常 常 在 输 入 消 息 的 响 应 函 数 中 做 大 量 的 工 作。
关键词:游戏中的多任务处理