前腐后继 发表于 2007-1-8 11:29:00

游戏入门基础]DOS到Windows的 游 戏 移 植(4)

<font color="#000000">&nbsp;</font><h3><font face="Tahoma" color="#000000" size="2">使 用 时 钟</font></h3><p><font face="Tahoma" color="#000000" size="2">---- Moby Dick DOS 使 用 了 一 个 时 钟 中 断 服 务 程 序, 以 确 保 Ahab 和 鲸 鱼 以 一 种 独 立 于 处 理 器 速 度 的 稳 定 速 率 移 动。Windows 没 有 提 供 这 种 访 问 硬 件 的 机 制, 但 是 它 提 供 了 许 多 的 时 钟(timer), 可 以 完 成 此 工 作。</font></p><p><font face="Tahoma" color="#000000" size="2">---- 当 在 程 序 中 创 建 一 个 时 钟 时, 实 际 是 在 告 诉 Windows 以 一 个 特 定 的 时 间 间 隔 来 做 某 事。 根 据 不 同 的 时 钟,Windows 完 成 的 操 作 也 不 同。 标 准 时 钟, 使 用 SetTimer 来 调 用, 只 是 简 单 地 寄 出 一 个 WM_TIMER 消 息, 该 消 息 分 发 给 标 准 的 窗 口 过 程 或 一 个 已 经 定 义 好 的 特 殊 的 回 调 函 数。 多 媒 体 时 钟 同 时 忽 略 消 息 队 列。</font></p><h3><font face="Tahoma" color="#000000" size="2">标 准 时 钟 的 限 制</font></h3><p><font face="Tahoma" color="#000000" size="2">---- 标 准 时 钟 与 我 们 在 Moby Dick DOS 中 所 使 用 的 正 常 时 钟 中 断 有 着 相 同 的 分 辨 率, 大 约 55 毫 秒。 换 句 话 说, 无 论 程 序 员 设 定 的 时 间 输 出 值 是 多 少, 在 两 个 WM_TIMER 消 息 之 间 至 少 要 有 55 毫 秒。 而 且 到 它 被 处 理 之 前 可 能 时 间 还 要 长, 因 为 Windows 不 给 时 钟 消 息 分 配 任 何 优 先 权, 它 们 只 能 像 其 它“ 人” 一 样 在 那 里 排 队 等 候。</font></p><p><font face="Tahoma" color="#000000" size="2">---- 同 样,WM_TIMER 消 息 也 像 WM_PAINT 消 息 一 样: 如 果 在 队 列 中 已 经 有 一 个 在 等 待, 则 不 能 添 加 更 多 的。 所 以, 如 果 Windows 恰 好 正 忙 于 其 它 的 事 情, 有 几 个 时 钟“ 滴 答” 被 消 耗 掉, 程 序 没 有 得 到 机 会 响 应。 这 时, 只 是 简 单 地 跳 过 几 个“ 拍 节”, 而 不 是 跑 着 去 追 回 来。 对 于 依 靠 频 繁“ 世 界” 更 新 的 实 时 游 戏 来 说, 无 法 选 择 跳 过 一 个“ 拍 节”。</font></p><h3><font face="Tahoma" color="#000000" size="2">多 媒 体 时 钟</font></h3><p><font face="Tahoma" color="#000000" size="2">---- Windows 的 多 媒 体 功 能 的 扩 展 包 括 一 个 高 分 辨 率 的 时 钟, 可 以 用 timeSetEvent 来 调 用, 其 分 辨 率 可 高 达 1 毫 秒。 除 了 具 有 非 常 高 的 分 辨 率 之 外, 该 时 钟 还 能 产 生 更 加 准 确 的 结 果, 因 为 它 不 需 要 依 赖 通 过 队 列 发 送 的 WM_TIMER 消 息。</font></p><p><font face="Tahoma" color="#000000" size="2">---- 事 实 上, 每 一 个 多 媒 体 时 钟 是 在 其 自 身 的 线 程 中 的, 而 且 无 论 是 否 有 中 止 的 消 息 或 其 它 正 在 进 行 的 事 情, 其 回 调 函 数 是 直 接 被 调 用 的。 这 一 点 很 重 要, 因 为 这 意 味 着 在 处 理 全 局 数 据 时, 程 序 员 必 须 特 别 小 心。 变 量 有 可 能 被 时 钟 程 序 改 变, 而 也 许 这 个 变 量 正 被 其 他 一 般 的 消 息 响 应 函 数 所 使 用。 如 果 确 实 设 置 了 一 个 多 媒 体 时 钟, 一 定 要 理 解 有 关 同 步、 信 号 语 言(semaphores)、 以 及 所 有 其 它 的 多 媒 体 编 程 的 机 构(apparatus)( 对 此 不 熟 悉 的 程 序 员 请 参 考 有 关 资 料)。</font></p><p><font face="Tahoma" color="#000000" size="2">---- 要 使 用 timeSetEvent, 必 须 包 含 MMSYSTEM.H 并 且 要 链 接 WINMM.LIB。</font></p><p><font face="Tahoma" color="#000000" size="2">---- 尽 管 有 着 很 高 的 分 辨 率, 多 媒 体 时 钟 还 是 可 能 会 有 延 迟, 而 且 这 种“ 潜 在 的 问 题” 在 Windows 95 下 比 在 3.1 下 要 大 得 多。 对 于 那 些 需 要 非 常 高 的 时 钟 精 确 度 的 应 用 程 序, 可 能 不 得 不 在 16- 位 DLL 中 实 现 多 媒 体 时 钟。</font></p><h3><font face="Tahoma" color="#000000" size="2">不 使 用 时 钟 来 完 成 工 作</font></h3><p><font face="Tahoma" color="#000000" size="2">---- 如 前 所 述, 使 用 一 个 多 媒 体 时 钟 将 自 动 在 程 序 中 创 建 一 个 单 独 的 线 程, 可 能 还 同 时 产 生 了 安 全 防 卫 的 需 求, 以 避 免 对 数 据 的 不 适 时 访 问。 但 是 并 不 是 一 定 要 设 置 好 信 号 语 言(semaphores) 和 关 键 段(critical sections), 因 为 程 序 员 可 以 根 本 不 使 用 时 钟 也 同 样 能 够 简 单 地 编 写 出 游 戏, 这 种 方 法 就 是 轮 询 系 统 时 钟。 表 面 上 看 来, 轮 询 的 效 率 好 象 比 较 低, 但 是 Windows 有 其 自 身 的 框 架 以 决 定 何 时 触 发 一 个 时 钟, 所 以 这 两 种 方 法 的 差 别 可 能 没 有 那 么 大。</font></p><p><font face="Tahoma" color="#000000" size="2">---- 有 两 个 在 高 分 辨 率 下 可 用 的 轮 询 函 数。 第 一 个 是 timeGetTime, 它 返 回 自 Windows 启 动 以 来 经 过 的 毫 秒 数。 默 认 的 分 辨 率 是 1 毫 秒, 但 在 Windows NT 中 除 外( 参 见 API 参 考)。 对 于 timeSetEvent, 要 使 用 该 函 数 需 要 链 接 到 多 媒 体 库。</font></p><p><font face="Tahoma" color="#000000" size="2">---- 有 些 程 序 员 可 能 觉 得 1 毫 秒 的 分 辨 率 太 高 了, 以 至 在 实 时 游 戏 中 并 不 需 要, 实 际 上 却 恰 恰 相 反, 有 时 会 发 生 延 迟 事 件。 对 于 高 性 能 的 游 戏 来 说, 解 决 的 方 法 有 两 个:(1) 在 16- 位 的 DLL 中 使 用 多 媒 体 时 钟;(2) 转 移 到 所 有 时 间 服 务 中 分 辨 率 最 高 的 QueryPerformanceCounter, 这 个 函 数 主 要 是 为 配 置 而 设 计 的, 但 是 我 们 同 样 可 以 把 它 作 为 一 个 普 通 目 的 的 时 钟 来 使 用。</font></p><p><font face="Tahoma" color="#000000" size="2">---- 同 timeGetTime 一 样,QueryPerformanceCounter 也 返 回 自 系 统 启 动 以 来 经 过 的 时 间。 度 量 的 单 位 是 由 硬 件 决 定 的; 对 于 基 于 Intel 的 CPU, 大 概 是 0.8 微 秒。</font></p><p><font face="Tahoma" color="#000000" size="2">---- 下 面 给 出 的 是 WinMain 函 数 的 一 段, 显 示 如 何 使 用 QueryPerformanceCounter 来 使 游 戏“ 世 界” 每 1/10 秒 更 新 一 次。</font></p><pre><font face="Tahoma" size="2">
                        <font color="#000000">#define UPDATE_TICKS_MS 100



      // 每 次“ 世 界” 更 新 的 毫 秒 数







_int64 start, end, freq, update_ticks_pc



MSG   msg;







// 获 得 性 能 计 数 器 的 每 秒“ 滴 答” 数



//   注 意, 必 须 将 类 型 强 制 转 换 为LARGE_INTEGER 结 构



if (!QueryPerformanceFrequency((LARGE_INTEGER*)&amp;freq))



return -1;// 错 误 * 硬 件 不 支 持 性 能 计 数 器







// 将 每 次 更 新 的 毫 秒 数 转 换 为 每 次 更 新 的 性 能 计 数 器 单 位。



update_ticks_pc = UPDATE_TICKS_MS * freq / 1000;







// 初 始 化 计 数 器。



QueryPerformanceCounter((LARGE_INTEGER*)&amp;start);







// 主 消 息 循 环 从 这 里 开 始



    -- while (GetMessage(&amp;msg, NULL, 0, 0))



    {



    TranslateMessage(&amp;msg);



    DispatchMessage(&amp;msg);



    QueryPerformanceCounter((LARGE_INTEGER*)&amp;end);



// 内 部 的 循 环 保 证 如 果 需 要 的 话,



// “ 世 界” 的 更 新 次 数 多 于 一 次。



    while ((end - start) &gt;= update_ticks_pc)



      {



      UpdateWorld();



      start += update_ticks_pc;



      }



    } // 消 息 循 环 结 束



return msg.wParam;



</font></font></pre><p><font face="Tahoma" color="#000000" size="2">---- 注 意, 如 果 硬 件 不 支 持 性 能 计 数 器,QueryPerformanceFrequency 将 返 回 FALSE。 这 种 情 况 通 常 不 会 发 生, 如 果 真 的 发 生 了, 只 有 使 用 timeGetTime 的 程 序 来 替 代。</font></p><h3><font face="Tahoma" color="#000000" size="2">有 关 竞 争</font></h3><p><font face="Tahoma" color="#000000" size="2">---- 有 时 Windows 看 起 来 好 象 用 一 只 手 给 出, 但 同 时 又 用 另 一 只 手 把 它 拿 走。 用 它 的 右 手 提 供 了 时 间 测 量 达 1 毫 秒 的 能 力, 但 同 时 左 手 又 过 来, 在 最 需 要 的 时 候 把 CPU 时 间 抓 走 了, 于 是 游 戏 中 的“ 捣 蛋 鬼”(sprites) 就 会“ 死” 在 那 里, 蹒 跚 地 走 过 屏 幕, 就 像 许 多 个 穿 着 木 底 鞋 的 芭 蕾 舞 女 演 员 一 样。</font></p><p><font face="Tahoma" color="#000000" size="2">---- 下 面 我 们 要 更 形 象 地 看 一 下 该 问 题。 启 动 Moby Dick, 然 后 运 行 多 个 Time Waster 的 实 例。 单 击 Moby Dick 窗 口, 重 新 激 活 该 游 戏, 然 后 观 察 云 的 不 稳 定 的 移 动 情 况。 如 果 Time Waster 真 的 任 意 消 耗 CPU 的 时 间, 甚 至 船 的 动 画 也 会 被 破 坏。 甚 至 在 所 有 的 Time Waster 的 实 例 都 已 关 闭 之 后, 它 们 仍 能 使 系 统 的 工 作 陷 入 沼 泽。 这 是 因 为 所 有 分 配 到 硬 盘 上 的 虚 拟 内 存 都 必 须 被 释 放。Windows 有 可 能 正 在 做 一 些 交 换 文 件 的 清 除 工 作。</font></p><p><font face="Tahoma" color="#000000" size="2">---- 尽 管 对 一 般 玩 家 来 说, 不 需 要 在 后 台 运 行 消 耗 处 理 器 时 间 的 任 务, 游 戏 仍 然 要 与 网 络 动 作 和 Windows 日 常 事 务 分 享 时 间。 程 序 员 不 能 向 在 DOS 下 工 作 时 那 样 独 占 CPU, 充 其 量 最 大 的 期 望 就 是 给 游 戏 分 配 一 个 比 较 大 块 的 时 间“ 馅 饼”。</font></p><h3><font face="Tahoma" color="#000000" size="2">调 整 优 先 级</font></h3><p><font face="Tahoma" color="#000000" size="2">---- Windows 并 不 需 要 给 每 一 个 正 在 处 理 的 任 务 分 配 相 等 的 CPU 时 间 数。 根 据 应 用 程 序 的 综 合 的 优 先 类 别(priority class), 以 及 在 这 些 应 用 程 序 内 部 的 每 个 线 程 的 线 程 优 先 级(thread priority),Windows 把 时 间“ 馅 饼” 分 割 开 来。 这 两 种 优 先 级 都 是 由 应 用 程 序 的 开 发 者 决 定 的。</font></p><p><font face="Tahoma" color="#000000" size="2">---- 然 而, 在 某 些 特 定 的 时 候, 此 时 Windows 也 会 提 升 该 线 程 的 优 先 级。 这 种 现 象 可 以 在 Moby Dick 中 非 常 形 象 地 观 察 到, 方 法 是 当 云 彩 的 线 程 遇 到 麻 烦 而 不 能 得 到 足 够 的 CPU 时 间 时, 打 开 一 个 菜 单 或 对 话 框, 此 时, 云 彩 的 移 动 会 立 刻 变 得 平 滑 起 来。Windows 动 态 地 提 升 在 应 用 程 序 中 的 所 有 线 程 的 优 先 级, 这 是 因 为 它 在 猜 测 是 否 用 户 想 要 做 点 什 么 事 情, 并 在 期 待 快 速 的 响 应。</font></p><p><font face="Tahoma" color="#000000" size="2">---- Moby Dick Windows 的 View 菜 单 的 Settings 命 令 允 许 程 序 员 改 变 该 应 用 程 序 的 优 先 类 别, 程 序 员 还 可 以 设 置 主 线 程 和 移 动 云 彩 通 过 屏 幕 的 线 程 的 优 先 级。 警 告: 某 些 优 先 级 的 组 合 可 能 导 致 Windows 无 法 正 常 工 作, 只 能 通 过 使 用 CTRL+ALT+DEL 来 关 闭 Moby Dick。</font></p><p><font face="Tahoma" color="#000000" size="2">---- 改 变 优 先 级 类 别 和 线 程 优 先 级 是 非 常 危 险 的。 特 别 要 注 意 的 是“ 一 个 具 有 高 于 11 的 优 先 级 的 线 程 会 与 操 作 系 统 的 正 常 操 作 相 冲 突。” 这 就 意 味 着 如 果 使 用 高 于 HIGH_PRIORITY_CLASS 和 THREAD_PRIORITY_LOWEST 或 者 NORMAL_PRIORITY_CLASS 和 THREAD_PRIORITY_HIGHEST 的 组 合, 程 序 就 不 能 安 全 工 作。</font></p><p><font face="Tahoma" color="#000000" size="2">---- 读 者 可 以 在 实 验 Moby Dick Windows 的 优 先 级 的 同 时, 在 后 台 运 行 一 个 或 多 个 Time Waster 的 实 例, 同 时 计 量(gauge) 出 其 对 游 戏 和 对 系 统 的 效 果。 最 后, 可 能 会 得 出 这 个 结 论, 在 程 序 的 整 个 生 命 期 中, 重 新 设 置 优 先 级 所 带 来 的 问 题 要 比 解 决 的 问 题 还 多。 但 是, 暂 时 地 提 升 某 些 时 间 紧 迫 任 务 的 优 先 级, 还 是 有 用 的。</font></p>
页: [1]
查看完整版本: 游戏入门基础]DOS到Windows的 游 戏 移 植(4)