Programming 版 (精华区)
发信人: superman (☆风雨无阻☆), 信区: Programming
标 题: [转载] DOS到Windows的 游 戏 移 植(4)
发信站: 紫 丁 香 (Sat Aug 29 07:35:45 1998), 站内信件
【 以下文字转载自 cnprogram 讨论区 】
【 原文由 Young_Yang@bbs.ustc.edu.cn 所发表 】
从DOS 到Windows 的 游 戏 移 植(4)
谭 翁
_________________________________________________________________
使 用 时 钟
---- Moby Dick DOS 使 用 了 一 个 时 钟 中 断 服 务 程 序, 以 确 保
Ahab 和 鲸 鱼 以 一 种 独 立 于 处 理 器 速 度 的 稳 定 速 率 移 动
。Windows 没 有 提 供 这 种 访 问 硬 件 的 机 制, 但 是 它 提 供 了 许
多 的 时 钟(timer), 可 以 完 成 此 工 作。
---- 当 在 程 序 中 创 建 一 个 时 钟 时, 实 际 是 在 告 诉 Windows 以
一 个 特 定 的 时 间 间 隔 来 做 某 事。 根 据 不 同 的 时 钟,Windows
完 成 的 操 作 也 不 同。 标 准 时 钟, 使 用 SetTimer 来 调 用, 只 是
简 单 地 寄 出 一 个 WM_TIMER 消 息, 该 消 息 分 发 给 标 准 的 窗 口
过 程 或 一 个 已 经 定 义 好 的 特 殊 的 回 调 函 数。 多 媒 体 时 钟
同 时 忽 略 消 息 队 列。
标 准 时 钟 的 限 制
---- 标 准 时 钟 与 我 们 在 Moby Dick DOS 中 所 使 用 的 正 常 时 钟
中 断 有 着 相 同 的 分 辨 率, 大 约 55 毫 秒。 换 句 话 说, 无 论 程
序 员 设 定 的 时 间 输 出 值 是 多 少, 在 两 个 WM_TIMER 消 息 之 间
至 少 要 有 55 毫 秒。 而 且 到 它 被 处 理 之 前 可 能 时 间 还 要 长
, 因 为 Windows 不 给 时 钟 消 息 分 配 任 何 优 先 权, 它 们 只 能
像 其 它“ 人” 一 样 在 那 里 排 队 等 候。
---- 同 样,WM_TIMER 消 息 也 像 WM_PAINT 消 息 一 样: 如 果 在 队 列
中 已 经 有 一 个 在 等 待, 则 不 能 添 加 更 多 的。 所 以, 如 果
Windows 恰 好 正 忙 于 其 它 的 事 情, 有 几 个 时 钟“ 滴 答” 被 消
耗 掉, 程 序 没 有 得 到 机 会 响 应。 这 时, 只 是 简 单 地 跳 过 几
个“ 拍 节”, 而 不 是 跑 着 去 追 回 来。 对 于 依 靠 频 繁“ 世 界”
更 新 的 实 时 游 戏 来 说, 无 法 选 择 跳 过 一 个“ 拍 节”。
多 媒 体 时 钟
---- Windows 的 多 媒 体 功 能 的 扩 展 包 括 一 个 高 分 辨 率 的 时
钟, 可 以 用 timeSetEvent 来 调 用, 其 分 辨 率 可 高 达 1 毫 秒。 除
了 具 有 非 常 高 的 分 辨 率 之 外, 该 时 钟 还 能 产 生 更 加 准 确
的 结 果, 因 为 它 不 需 要 依 赖 通 过 队 列 发 送 的 WM_TIMER 消 息
。
---- 事 实 上, 每 一 个 多 媒 体 时 钟 是 在 其 自 身 的 线 程 中 的,
而 且 无 论 是 否 有 中 止 的 消 息 或 其 它 正 在 进 行 的 事 情, 其
回 调 函 数 是 直 接 被 调 用 的。 这 一 点 很 重 要, 因 为 这 意 味
着 在 处 理 全 局 数 据 时, 程 序 员 必 须 特 别 小 心。 变 量 有 可
能 被 时 钟 程 序 改 变, 而 也 许 这 个 变 量 正 被 其 他 一 般 的 消
息 响 应 函 数 所 使 用。 如 果 确 实 设 置 了 一 个 多 媒 体 时 钟,
一 定 要 理 解 有 关 同 步、 信 号 语 言(semaphores)、 以 及 所 有 其
它 的 多 媒 体 编 程 的 机 构(apparatus)( 对 此 不 熟 悉 的 程 序 员
请 参 考 有 关 资 料)。
---- 要 使 用 timeSetEvent, 必 须 包 含 MMSYSTEM.H 并 且 要 链 接
WINMM.LIB。
---- 尽 管 有 着 很 高 的 分 辨 率, 多 媒 体 时 钟 还 是 可 能 会 有
延 迟, 而 且 这 种“ 潜 在 的 问 题” 在 Windows 95 下 比 在 3.1 下 要
大 得 多。 对 于 那 些 需 要 非 常 高 的 时 钟 精 确 度 的 应 用 程 序
, 可 能 不 得 不 在 16- 位 DLL 中 实 现 多 媒 体 时 钟。
不 使 用 时 钟 来 完 成 工 作
---- 如 前 所 述, 使 用 一 个 多 媒 体 时 钟 将 自 动 在 程 序 中 创
建 一 个 单 独 的 线 程, 可 能 还 同 时 产 生 了 安 全 防 卫 的 需 求
, 以 避 免 对 数 据 的 不 适 时 访 问。 但 是 并 不 是 一 定 要 设 置
好 信 号 语 言(semaphores) 和 关 键 段(critical sections), 因 为 程
序 员 可 以 根 本 不 使 用 时 钟 也 同 样 能 够 简 单 地 编 写 出 游 戏
, 这 种 方 法 就 是 轮 询 系 统 时 钟。 表 面 上 看 来, 轮 询 的 效
率 好 象 比 较 低, 但 是 Windows 有 其 自 身 的 框 架 以 决 定 何 时
触 发 一 个 时 钟, 所 以 这 两 种 方 法 的 差 别 可 能 没 有 那 么 大
。
---- 有 两 个 在 高 分 辨 率 下 可 用 的 轮 询 函 数。 第 一 个 是
timeGetTime, 它 返 回 自 Windows 启 动 以 来 经 过 的 毫 秒 数。 默 认
的 分 辨 率 是 1 毫 秒, 但 在 Windows NT 中 除 外( 参 见 API 参 考)
。 对 于 timeSetEvent, 要 使 用 该 函 数 需 要 链 接 到 多 媒 体 库。
---- 有 些 程 序 员 可 能 觉 得 1 毫 秒 的 分 辨 率 太 高 了, 以 至 在
实 时 游 戏 中 并 不 需 要, 实 际 上 却 恰 恰 相 反, 有 时 会 发 生
延 迟 事 件。 对 于 高 性 能 的 游 戏 来 说, 解 决 的 方 法 有 两 个:
(1) 在 16- 位 的 DLL 中 使 用 多 媒 体 时 钟;(2) 转 移 到 所 有 时
间 服 务 中 分 辨 率 最 高 的 QueryPerformanceCounter, 这 个 函 数 主
要 是 为 配 置 而 设 计 的, 但 是 我 们 同 样 可 以 把 它 作 为 一 个
普 通 目 的 的 时 钟 来 使 用。
---- 同 timeGetTime 一 样,QueryPerformanceCounter 也 返 回 自 系 统 启
动 以 来 经 过 的 时 间。 度 量 的 单 位 是 由 硬 件 决 定 的; 对 于
基 于 Intel 的 CPU, 大 概 是 0.8 微 秒。
---- 下 面 给 出 的 是 WinMain 函 数 的 一 段, 显 示 如 何 使 用
QueryPerformanceCounter 来 使 游 戏“ 世 界” 每 1/10 秒 更 新 一 次。
#define UPDATE_TICKS_MS 100
// 每 次“ 世 界” 更 新 的 毫 秒 数
_int64 start, end, freq, update_ticks_pc
MSG msg;
// 获 得 性 能 计 数 器 的 每 秒“ 滴 答” 数
// 注 意, 必 须 将 类 型 强 制 转 换 为LARGE_INTEGER 结 构
if (!QueryPerformanceFrequency((LARGE_INTEGER*)&freq))
return -1; // 错 误 * 硬 件 不 支 持 性 能 计 数 器
// 将 每 次 更 新 的 毫 秒 数 转 换 为 每 次 更 新 的 性 能 计 数 器 单 位。
update_ticks_pc = UPDATE_TICKS_MS * freq / 1000;
// 初 始 化 计 数 器。
QueryPerformanceCounter((LARGE_INTEGER*)&start);
// 主 消 息 循 环 从 这 里 开 始
-- while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
QueryPerformanceCounter((LARGE_INTEGER*)&end);
// 内 部 的 循 环 保 证 如 果 需 要 的 话,
// “ 世 界” 的 更 新 次 数 多 于 一 次。
while ((end - start) >= update_ticks_pc)
{
UpdateWorld();
start += update_ticks_pc;
}
} // 消 息 循 环 结 束
return msg.wParam;
---- 注 意, 如 果 硬 件 不 支 持 性 能 计 数 器
,QueryPerformanceFrequency 将 返 回 FALSE。 这 种 情 况 通 常 不 会 发
生, 如 果 真 的 发 生 了, 只 有 使 用 timeGetTime 的 程 序 来 替 代。
有 关 竞 争
---- 有 时 Windows 看 起 来 好 象 用 一 只 手 给 出, 但 同 时 又 用 另
一 只 手 把 它 拿 走。 用 它 的 右 手 提 供 了 时 间 测 量 达 1 毫 秒
的 能 力, 但 同 时 左 手 又 过 来, 在 最 需 要 的 时 候 把 CPU 时 间
抓 走 了, 于 是 游 戏 中 的“ 捣 蛋 鬼”(sprites) 就 会“ 死” 在 那
里, 蹒 跚 地 走 过 屏 幕, 就 像 许 多 个 穿 着 木 底 鞋 的 芭 蕾 舞
女 演 员 一 样。
---- 下 面 我 们 要 更 形 象 地 看 一 下 该 问 题。 启 动 Moby Dick,
然 后 运 行 多 个 Time Waster 的 实 例。 单 击 Moby Dick 窗 口, 重 新
激 活 该 游 戏, 然 后 观 察 云 的 不 稳 定 的 移 动 情 况。 如 果
Time Waster 真 的 任 意 消 耗 CPU 的 时 间, 甚 至 船 的 动 画 也 会 被
破 坏。 甚 至 在 所 有 的 Time Waster 的 实 例 都 已 关 闭 之 后, 它
们 仍 能 使 系 统 的 工 作 陷 入 沼 泽。 这 是 因 为 所 有 分 配 到 硬
盘 上 的 虚 拟 内 存 都 必 须 被 释 放。Windows 有 可 能 正 在 做 一 些
交 换 文 件 的 清 除 工 作。
---- 尽 管 对 一 般 玩 家 来 说, 不 需 要 在 后 台 运 行 消 耗 处 理
器 时 间 的 任 务, 游 戏 仍 然 要 与 网 络 动 作 和 Windows 日 常 事
务 分 享 时 间。 程 序 员 不 能 向 在 DOS 下 工 作 时 那 样 独 占 CPU,
充 其 量 最 大 的 期 望 就 是 给 游 戏 分 配 一 个 比 较 大 块 的 时 间
“ 馅 饼”。
调 整 优 先 级
---- Windows 并 不 需 要 给 每 一 个 正 在 处 理 的 任 务 分 配 相 等
的 CPU 时 间 数。 根 据 应 用 程 序 的 综 合 的 优 先 类 别(priority
class), 以 及 在 这 些 应 用 程 序 内 部 的 每 个 线 程 的 线 程 优
先 级(thread priority),Windows 把 时 间“ 馅 饼” 分 割 开 来。 这 两
种 优 先 级 都 是 由 应 用 程 序 的 开 发 者 决 定 的。
---- 然 而, 在 某 些 特 定 的 时 候, 此 时 Windows 也 会 提 升 该 线
程 的 优 先 级。 这 种 现 象 可 以 在 Moby Dick 中 非 常 形 象 地 观 察
到, 方 法 是 当 云 彩 的 线 程 遇 到 麻 烦 而 不 能 得 到 足 够 的
CPU 时 间 时, 打 开 一 个 菜 单 或 对 话 框, 此 时, 云 彩 的 移 动
会 立 刻 变 得 平 滑 起 来。Windows 动 态 地 提 升 在 应 用 程 序 中 的
所 有 线 程 的 优 先 级, 这 是 因 为 它 在 猜 测 是 否 用 户 想 要 做
点 什 么 事 情, 并 在 期 待 快 速 的 响 应。
---- Moby Dick Windows 的 View 菜 单 的 Settings 命 令 允 许 程 序 员
改 变 该 应 用 程 序 的 优 先 类 别, 程 序 员 还 可 以 设 置 主 线 程
和 移 动 云 彩 通 过 屏 幕 的 线 程 的 优 先 级。 警 告: 某 些 优 先
级 的 组 合 可 能 导 致 Windows 无 法 正 常 工 作, 只 能 通 过 使 用
CTRL+ALT+DEL 来 关 闭 Moby Dick。
---- 改 变 优 先 级 类 别 和 线 程 优 先 级 是 非 常 危 险 的。 特 别
要 注 意 的 是“ 一 个 具 有 高 于 11 的 优 先 级 的 线 程 会 与 操 作
系 统 的 正 常 操 作 相 冲 突。” 这 就 意 味 着 如 果 使 用 高 于
HIGH_PRIORITY_CLASS 和 THREAD_PRIORITY_LOWEST 或 者
NORMAL_PRIORITY_CLASS 和 THREAD_PRIORITY_HIGHEST 的 组 合, 程 序 就 不
能 安 全 工 作。
---- 读 者 可 以 在 实 验 Moby Dick Windows 的 优 先 级 的 同 时, 在
后 台 运 行 一 个 或 多 个 Time Waster 的 实 例, 同 时 计 量(gauge) 出
其 对 游 戏 和 对 系 统 的 效 果。 最 后, 可 能 会 得 出 这 个 结 论,
在 程 序 的 整 个 生 命 期 中, 重 新 设 置 优 先 级 所 带 来 的 问 题
要 比 解 决 的 问 题 还 多。 但 是, 暂 时 地 提 升 某 些 时 间 紧 迫
任 务 的 优 先 级, 还 是 有 用 的。
_________________________________________________________________
--
※ 来源: 中国科大BBS站 [bbs.ustc.edu.cn]
--
※ 转载:.紫 丁 香 bbs.hit.edu.cn.[FROM: poster.hit.edu.c]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:209.530毫秒