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

2007-01-08 10:58 发布

引擎学习交流 /[参考文档]
4317 0 0
本 期 将 讨 论 鼠 标 方 面 的 问 题。Moby Dick DOS 实 际 上 没 有 使 用 鼠 标 光 标, 并 且 切 换 到 图 形 模 式 时, 默 认 情 况 下 是 鼠 标 光 标 是 不 可 见 的。 在 Windows 中, 情 形 刚 好 相 反。 光 标 总 是 出 现 在 窗 口 中, 除 非 特 意 将 它 藏 起 来, 比 如 在 全 屏 幕 的 应 用 程 序 中。

自 定 义 光 标

---- 在DOS 下 实 现 一 个 光 标, 需 要 使 用DOS 中 断 33h 的 子 调 用 09h, 将 一 个 位 图 分 配 给 光 标 作 为 其 图 像。 如 果 光 标 在 屏 幕 的 不 同 点 上 改 变 了 形 状, 那 么 在 每 次 调 用 该 中 断 之 后, 必 须 保 存 光 标 的 位 置。 应 用 程 序 负 责 跟 踪 光 标 位 置 并 相 应 地 改 变 光 标 形 状。

---- 在Windows 下, 实 现 自 定 义 光 标 变 得 十 分 容 易。 如 果 仍 想 使 用 现 有 的DOS 游 戏 中 的 硬 代 码 图 像 数 据, 就 需 要 利 用 CreateCursor 在 程 序 运 行 时 动 态 地 绘 制 一 个 光 标。 但 在 大 多 数 情 况 下 采 用 的 方 法 是, 在 资 源 编 辑 器 中 画 出 图 像, 将 资 源 文 件 链 接 到 应 用 程 序, 用 LoadCursor 使 图 像 在 运 行 时 可 见。 当 然, 使 用 标 准 的 光 标 前 必 须 先 加 载 它。

---- 可 以 使 用 SetCursor 在 任 何 时 间 改 变 光 标 的 形 状, 其 唯 一 的 输 入 参 数 是 新 光 标 的 句 柄。 只 要 光 标 已 经 被 加 载,LoadCursor 将 仅 返 回 已 存 在 的 句 柄, 所 以 下 面 的 代 码 即 使 在 循 环 中 执 行, 也 丝 毫 不 会 浪 费 系 统 资 源:

---- SetCursor(LoadCursor(MAKEINTRESOURCE(IDC_MYCURSOR)));

---- 想 要 使 用 自 定 义 光 标, 必 须 将 窗 口 默 认 光 标 设 成 NULL。 有 关 SetCursor 请 参 阅 API 参 考。

---- 在SVGA 模 式 下 的 基 于DOS 的 游 戏 中, 大 多 数 卡 甚 至 连 最 基 本 的“ 指 针” 状 光 标 也 必 须 在 软 件 中 实 现。 在 Windows 下, 这 当 然 是 不 必 要 的, 因 为 它 能 够 轻 松 地 适 应 图 形 驱 动 器 所 支 持 的 任 何 显 示 模 式。

鼠 标 逃 逸(Mouse Escapes) 时 怎 么 办 ?

---- 根 据 定 义, 基 于DOS 的 游 戏 是 全 屏 的, 所 以 当 鼠 标 游 走 到 边 界 之 外 时, 程 序 员 不 必 担 心 会 发 生 什 么 问 题。 但 是, 在 基 于 Windows 的 游 戏 中, 即 使 鼠 标 不 在 应 用 程 序 窗 口 中, 也 有 必 要 跟 踪 鼠 标 光 标。

---- 一 般 情 况 下, 只 有 当 鼠 标 活 动 发 生 在 应 用 程 序 或 是 对 话 框 窗 口 内 部 时,Windows 才 将 鼠 标 消 息 发 送 给 应 用 程 序 或 者 对 话 框 窗 口。 而 且, 它 根 据 鼠 标 是 活 动 在 客 户 区 域 还 是 非 客 户 区 域( 例 如, 在 菜 单 栏, 或 者 是 在 边 框 上), 发 送 不 同 的 消 息。

---- 大 多 数 应 用 程 序, 包 括 简 单 的 指 点(point-and-click) 战 略 游 戏, 都 只 是 围 绕 着 客 户 区 域 消 息。 然 而, 游 戏 可 能 需 要 了 解 当 鼠 标 在 客 户 区 域 之 外 时, 向 上 到 达 了 什 么 位 置。 举 一 个 普 通 的 例 子---- 有 关 地 图 方 面 的 战 略 游 戏, 当 光 标 在 客 户 区 域 之 外 移 动 时, 地 图 将 会 自 动 地 卷 动。 在 Moby Dick 中, 非DirectInput 鼠 标 接 口 要 求 Ahab 移 向 光 标, 而 无 论 光 标 是 否 在 游 戏 窗 口 内 部( 注 意: 这 只 有 在 没 有 定 义 USE_DIRECTINPUT 时 编 译 该 程 序 才 有 效。)

---- 在 Windows 3.1 下,Moby Dick 应 用 程 序 可 能 已 经 使 用 了 SetCapture 函 数 来“ 捕 获 鼠 标”, 也 就 是 说 将 所 有 的 鼠 标 消 息 读 到 游 戏 中, 而 不 考 虑 光 标 所 在 的 位 置。 而 在 Windows 95 下 这 是 不 可 能 的, 原 因 是 异 步 输 入 处 理, 它 是 Windows 95 禁 止 任 何 一 个 应 用 程 序 独 占 系 统 的 一 种 方 法。 程 序 员 仍 可 以 捕 获 鼠 标, 但 只 有 在 按 钮 释 放 之 后。 很 显 然, 这 不 是 我 们 在 Moby Dick 中 所 想 要 的。

---- 还 有 两 种 更 为 复 杂 的 捕 获 鼠 标 的 方 法, 这 两 种 方 法 都 要 求 安 装 一 个“ 钩 子”(hook), 用 于 拦 截 在 应 用 程 序 之 外 的 Windows 消 息。 有 一 个 API 函 数 GetCursorPos, 无 论 光 标 在 屏 幕 上 的 什 么 位 置, 它 都 将 返 回 光 标 的 当 前 位 置。

---- GetCursorPos 以 屏 幕 坐 标 返 回 光 标 的 位 置, 然 而 本 程 序 中 的 图 形 函 数 是 以 窗 口 坐 标 为 基 础 的, 因 为 它 们 是 独 立 于 窗 口 的 实 际 位 置 的, 这 就 需 要 ClientToScreen。 它 将 窗 口 中 一 个 点 的 相 对 坐 标 转 换 为 绝 对 或 者 屏 幕 坐 标, 并 且 把 窗 口 的 当 前 位 置 考 虑 进 来。

---- 下 面 部 分 代 码 显 示 了 如 何 决 定 与 光 标 位 置 相 比 较 的 Ahab 的 矩 形 边 界 的 屏 幕 坐 标。

---- RECT AhabRect;

---- // 计 算 船 的 矩 形 网 格 的 窗 口 坐 标。

---- // 坐 标 将 由 船 的 行 和 列 的 单 元 格 数 乘 以 一 个 单 元 格 的 像 素 而 得 出。


			AhabRect.top = AhabY * SPRITE_HT;



AhabRect.bottom = AhabRect.top + SPRITE_HT;



AhabRect.left = AhabX * SPRITE_WD;



AhabRect.right = AhabRect.left + SPRITE_WD;



---- // 转 换 为 屏 幕 坐 标。 我 们 把 RECT 视 为 两 个 POINT ( 左 上 和 右 下) 的 一 个 数 组。

---- ClientToScreen(hMainWindow, (POINT*) &AhabRect);
---- ClientToScreen(hMainWindow, (POINT*) &AhabRect.right);

---- 还 有 一 种 方 法 可 以 确 保 程 序 不 再 丢 失 对 鼠 标 的 控 制: 在 游 戏 启 动 时 将 窗 口 最 大 化, 并 且 不 提 供 恢 复 按 钮。 当 一 个 应 用 程 序 处 于 前 台 时, 就 把 所 有 其 他 应 用 程 序 都“ 挤” 出 去, 这 虽 然 不 是 好 的 Windows 做 法, 但 确 实 很 有 效。

鼠 标 单 击

---- 如 果 只 使 用 标 准 的 Windows API, 至 少 有 三 种 方 法 可 以 在 应 用 程 序 窗 口 中 监 视 鼠 标 的 单 击:

  1. 鼠 标 消 息。 这 是 捕 获 每 一 次 单 击 的 最 可 靠 的 方 法。 它 的 缺 点 是 快 速 的 单 击( 例 如 在 一 个 射 击 游 戏 中) 将 堆 积 在 消 息 列 队 中, 不 能 被 及 时 处 理。 如 果 使 用 GetCursorPos 轮 询 来 跟 踪 光 标 移 动 的 轨 迹, 也 许 会 遇 到 麻 烦, 不 得 不 同 时 响 应 鼠 标 单 击 和 光 标 移 动。
  2. GetKeyState。 该 函 数 可 用 来 测 试 鼠 标 按 钮 的 状 态, 但 是 与 键 的 情 况 一 样, 该 函 数 并 不 返 回 当 前 硬 件 的 实 际 状 态。 它 告 诉 程 序 员 当 最 后 一 次 从 队 列 中 取 出 消 息 时, 按 钮 处 在 什 么 状 态。 例 如, 如 果 处 理 的 最 后 一 个 消 息 是WM_LBUTTONDOWN,GetKeyState(VK_LBUTTON) 就 会 返 回 一 个 负 值( 最 高 位 是 1)。

---- GetKeyState 返 回 值 的 低 位 字 节 实 际 上 就 是 一 个“ 开 关” 动 作, 即 每 按 下 一 次 按 钮( 或 键) 都 切 换 该 键 对 应 的 值。 下 面 一 行 代 码( 在 游 戏 循 环 的 某 处 执 行), 允 许 用 户 用 右 边 的 按 钮 打 开 或 者 关 闭 音 乐:

---- BOOL MusicOn = (GetKeyState(VK_RBUTTON) & 1);

---- GetKeyState 是 设 计 用 来 响 应 设 置 按 钮 状 态 的 消 息 的, 不 能 用 类 似 下 面 的 语 句 来 等 待 鼠 标 单 击:

---- while (GetKeyState(VK_LBUTTON) >= 0); // *** 不 工 作 ! ***

---- 还 有, 象 下 面 这 样 轮 询 鼠 标 按 钮:

---- if (GetKeyState(VK_LBUTTON) <1) DoSomething();

---- 将 捕 获 不 到 所 有 的 单 击, 因 为 从 鼠 标 最 后 一 次 被 轮 询 之 后, 用 户 可 能 已 经 按 下 并 释 放 按 钮 了。

  • GetAsyncKeyState。 如 果 不 是 使 用 DirectInput 3.0 来 跟 踪 鼠 标 单 击, 并 且 游 戏 循 环 不 是 以 消 息 队 列 为 基 础 的, 那 么 使 用GetAsyncKeyState 可 能 是 最 好 的 方 法。 对 于 鼠 标, 它 的 工 作 方 式 是 相 同 的, 使 用 虚 键 VK_LBUTTON、VK_RBUTTON 和( 对 于 三 个 按 钮 的 鼠 标)VK_MBUTTON。 注 意 这 些 虚 键 被 映 射 到 鼠 标 的 实 际 按 钮, 而 不 是 用 户 在 控 制 面 板 所 定 义 的 第 一 和 第 二 按 钮。
B Color Smilies

你可能喜欢

游戏入门基础]DOS到Windows的 游 戏 移 植(6) 
联系
我们
快速回复 返回顶部 返回列表