Programming 版 (精华区)

发信人: superman (☆风雨无阻☆), 信区: Programming
标  题: [转载] DOS到Windows的 游 戏 移 植(8)
发信站: 紫 丁 香 (Sat Aug 29 07:35:56 1998), 站内信件

【 以下文字转载自 cnprogram 讨论区 】
【 原文由 Young_Yang@bbs.ustc.edu.cn 所发表 】

                    从DOS 到Windows 的 游 戏 移 植(8)
                                      
                                   谭 翁
                                      
     _________________________________________________________________
                                      
   ---- 在 本 系 列 文 章 的 前 面 几 部 分 中, 我 们 介 绍 了 一 个 简
   单 的DOS 游 戏Moby Dick, 并 且 带 它 走 过 了 在 Win32 环 境 下 开 发
   的 第 一 阶 段。 现 在, 我 们 将 对 该 游 戏 的 Windows 版 添 加 更 多
   的 功 能: 立 体 声 效 果、MIDI 音 乐、TrueType 字 体、 和
   用DirectDraw 图 形 实 现 的 透 明 效 果 的“ 捣 蛋 鬼”。
   
   ---- Moby Dick 只 是 为 Windows 95 编 写 的, 不 是 为 Windows NT。 同
   时 因 为 该 游 戏 的 图 形 程 序 使 用 了 DirectDraw , 所 以 必 须 在
   系 统 中 安 装 DirectX。
   
   ---- 所 提 供 的 可 执 行 文 件 使 用 了 DirectSound。 要 编 译 一 个
   不 支 持DirectSound 的 版 本, 注 释 掉 文 件 MOBY.CPP 中 的 "#define
   USE_DIRECTSOUND" 一 行 即 可。 提 供 这 个 选 项 是 为 了 能 够 比 较
   使 用 DirectSound 方 法 和 使 用 Windows 中 传 统 方 式 播 放 声 音 的
   差 异。 这 里 对 主 游 戏 循 环 做 了 一 些 很 小 却 非 常 重 要 的 修
   改。 在 以 前 的 文 章 中, 我 们 讲 述 了 在 实 时 游 戏 中 使 用
   PeekMessage 好 处。 然 而,PeekMessage 循 环 会 大 量 消 耗 CPU 时 间,
   即 使 该 应 用 程 序 是 处 于 后 台 并 且 理 论 上 没 有 做 任 何 事 情
   。 所 以, 当 Moby Dick 被 放 在 后 台 暂 停 执 行 时, 我 们 添 加 了
   一 个 对 WaitMessage 的 调 用。 该 函 数 悬 挂 该 线 程, 直 到 在 队
   列 中 出 现 一 个 消 息。
   
  本 文 讨 论 声 音 的 处 理
  
  从.VOC 到.WAV 的 转 变
  
   ---- 有 多 种 免 费 软 件 和 共 享 实 用 程 序 可 以 将8 位 .VOC 文 件
   转 换 为 .WAV 文 件; 可 以 查 阅 CompuServe 上 的 Windows AV 论 坛
   (WINAV) 或 在 ftp://x2ftp.oulu.fi/pub/msdos/programming 站 点 上 的 大
   量 与 编 程 有 关 的 文 章。 在 购 买 声 卡 时 也 可 能 得 到 了 这 样
   的 实 用 程 序, 例 如 购 买 Sound Blaster 会 随 卡 奉 送 VOC2WAV.EXE。
   
  使 用 PlaySound 播 放 声 音
  
   ---- 将.WAV 文 件 编 译 到 可 执 行 程 序 中 并 播 放 的 步 骤 如 下:
   
   ---- 1. 从 一 个 .WAV 文 件 直 接 播 放 声 音。 要 使 Moby 有 声 音 的
   “ 喷 气”, 仅 需 写 一 行 代 码: PlaySound("blow.wav", NULL,
   SND_ASYNC | SND_FILENAME);
   
   ---- 其 参 数 是: (1) 文 件 名; (2) 包 含 该 资 源 的 程 序 模 块 句
   柄, 我 们 用NULL 表 示 没 有 把 他 编 译 进 程 序 的 资 源 中, 因 为
   我 们 没 有 使 用 一 个 已 编 译 的 资 源; (3) 标 志, 确 保 该 函 数
   能 够 尽 可 能 快 的 返 回, 而 不 是 等 待 声 音 播 放 结 束, 并 且
   指 明 第 一 个 参 数 是 文 件 名。 要 把 该 声 音 文 件 作 为 一 个 资
   源 编 译 到 可 执 行 文 件 中, 需 要 在 资 源 (.RC) 文 件 中 添 加 下
   面 一 行:
   
   ---- IDR_WAVE_BLOW WAVE "blow.wav"
   
   ---- IDR_WAVE_BLOW 是 在 头 文 件 RESOURCE.H 中 定 义 的 一 个ID。
   WAVE 是 应 用 程 序 中 定 义( 主 观 命 名 的) 的 资 源 类 型。 声 音
   与 图 标 和 位 图 不 同, 不 是 标 准 资 源, 所 以 必 须 分 配 一 个
   类 型 名。
   
   ---- 当 需 要 从 资 源 中 播 放 声 音 时, 下 面 的 这 行 代 码 完 成
   这 个 工 作:

PlaySound(MAKEINTRESOURCE(IDR_WAVE_BLOW), hTheInstance,
                SND_ASYNC | SND_RESOURCE);

   ---- 在 这 里, 第 一 个 参 数 是 资 源 名( 由 宏 MAKEINTRESOURCE 将
   数 字 标 识 符 转 换 而 来)。 第 二 个 参 数 是 包 含 资 源 的 程 序
   模 块 句 柄( 在 Moby 的 例 子 中 , 就 是 主 程 序 句 柄)。 最 后 面
   的 标 志 已 经 被 改 变, 以 指 示 第 一 个 参 数 是 资 源 名 而 不 是
   文 件 名。
   
  使 用 DirectSound 播 放 声 音
  
   ---- 在 游 戏 中 的 不 同 时 间 点 播 放 简 单 的 声 音, 使 用
   PlaySound 就 足 够 了, 但 是 这 种 方 法 不 允 许 运 行 中 混 频 或 其
   他 效 果。Windows API 的 多 媒 体 扩 展 中 有 一 组 函 数, 它 们 的 名
   称 大 多 以 WAVE 开 头, 允 许 更 高 级 的 调 整, 但 是 这 些 都 被
   DirectX Software Development Kit (SDK) 的 一 个 部 件 DirectSound 所 取
   代。DirectSound 3 有 许 多 高 级 的 功 能, 包 括 自 动 混 频、3D 声 音
   ( 在 双 声 道 系 统 模 拟“ 环 绕 音 响”) 和 立 体 声, 使 用 它 可
   以 带 来 很 大 好 处。 DirectSound 不 提 供 幕 后 加 载 和 解 释 能 力
   , 而 这 些 功 能 PlaySound 都 提 供。 解 释 .WAV 文 件 是 程 序 员 的
   责 任, 并 且 要 把 数 据 复 制 到 第 二 缓 冲 区( 第 二 缓 冲 区 在
   后 台 保 持 数 据, 当 播 放 声 音 时, 这 些 数 据“ 流 入” 第 一 缓
   冲 区。 程 序 员 无 须 考 虑 第 一 缓 冲 区 的 问 题, 它 由
   DirectSound 保 持。) 示 例 工 程 在 文 件 WAVE.CPP 中 完 成 声 音 的
   加 载 和 解 释, 声 音 数 据 是 从 一 个 资 源 加 载 的。 这 段 代 码
   很 长, 所 以 在 这 里 就 不 引 述 它。 有 关 直 接 读 取 .WAV 文 件 的
   简 单 代 码, 请 您 参 阅 有 关 文 章。
   
   ---- 一 旦 建 立 起 DirectSound 的 第 二 缓 冲 区, 事 情 就 又 变 得
   简 单 了。 要 播 放 声 音, 只 需 调 用 DIRECTSOUNDBUFFER 对 象 的
   Play 方 法 即 可:
   
   ---- lpDSB_Blow- > Play(0, 0, 0);
   
   ---- 在 当 前 版 本 的 DirectSound 中, 头 两 个 参 数 总 是 为 0 。 如
   果 要 重 复 播 放 声 音, 可 以 把 第 三 个 参 数 设 置 为
   DSBPLAY_LOOPING。
   
   ---- Moby Dick Windows 版 演 示 了 循 环 声 音, 以 及 当 两 个 .WAV 文
   件 竞 争 时, 使 用 PlaySound 和 DirectSound 的 Play 方 法 的 不 同 结
   果。 在 Settings 菜 单 中 打 开 声 音, 并 且 单 击 左 键 开 始
   "boing" 声 音( 这 是 Queequeg 的 鱼 叉 的 声 音, 它 在 bungee 绳 索
   上)。 使 用 右 键 停 止 声 音。 如 果 编 译 该 程 序 时 预 定 义 了
   USE_DIRECTSOUND( 或 者 使 用 所 提 供 的 可 执 行 程 序),"boing" 和
   Moby 的 沉 重 呼 吸 声 被 DirectSound 混 在 一 起 同 时 播 放。 如 果
   没 有 定 义 USE_DIRECTSOUND,Moby 在 循 环 声 音 时 将 保 持 安 静, 因
   为 PlaySound 在 同 一 时 间 只 能 做 一 件 事 情。
   
   ---- 下 面 您 介 绍 一 下 如 何 实 现 一 个 简 单 的 立 体 声 效 果。
   假 设 有 一 个 立 体 声 的 声 卡, 在Moby 的 DirectSound 版 中, 鲸 鱼
   的 有 声 的 吹 气 的 移 动 步 伐, 依 赖 于 气 流 的 方 向 是 朝 向 游
   戏 屏 幕 的 右 边 还 是 左 边。Moby 每 呼 吸 一 次, 程 序 只 是 简 单
   地 以 -10,000 到 10,000 的 为 度 量 计 算 其 相 对 的 东 西 位 置。 然
   后 将 这 个 整 数 值 传 递 给 缓 冲 区 的 SetPan 方 法:
   
   ---- lpDSB_Blow- > SetPan(pan);
   
   ---- 这 一 操 作 在 Play 被 调 用 之 前 完 成。DirectSound 依 据 pan 的
   从 0 开 始 的 划 分, 自 动 按 比 例 地 减 弱 一 个 声 道 或 另 一 个
   声 道 的 回 放 声 音。 当 第 一 个 声 道 被 减 弱 时, 另 一 个 声 道
   保 持 全 高 的 声 音。 换 句 话 说, 当 Moby Dick 位 于 其 世 界 的 死
   角 时, 两 个 声 道 都 是 全 高 的 声 音; 当 它 走 到 最 东 或 最 西
   边 时, 有 一 个 声 道 是 没 有 声 音 的。
   
  播 放 MIDI 文 件
  
   ---- Windows 通 过 多 媒 体 API 提 供 了 对 回 放 MIDI 文 件 的 高 级
   和 低 级 支 持。 高 级 支 持 是 以 媒 体 控 制 接 口 (MCI) 函 数 的 形
   式 提 供 的。 这 种 情 况 下, 使 用 MIDI 格 式 0 和 1 可 以 工 作, 但
   是 MIDI 格 式 2 不 能 工 作。
   
   ---- MCI 函 数 实 际 上 可 以 有 两 种 不 同 的 调 用 方 法
   。mciSendString 函 数 使 用 看 起 来 不 象 计 算 机 代 码 的 字 符 串
   命 令 来 控 制 MIDI 序 列 器(sequencer)( 或 其 他 任 何 的 媒 体 播 放
   器)。 下 面 的 例 子 打 开 一 个 序 列 器, 并 且 读 要 回 放 的 文 件
   :

mciSendString(
    "open song.mid type sequencer alias aria",
lpszReturnString, lstrlen(lpszReturnString), NULL);

   ---- 该 调 用 定 义 了 文 件 名、 设 备 类 型 以 及 别 名( 在 示 例 中
   是 "aria"), 它 可 用 于 后 续 的 调 用 中, 这 些 后 续 的 调 用 可
   以 播 放、 暂 停 或 以 其 他 的 方 法 控 制 数 据 回 放。
   
   ---- 下 面 是mciSendCommand 的 列 出 顺 序:
MCI_OPEN_PARMS  mciOpenParms;
MCI_PLAY_PARMS  mciPlayParms;
DWORD           dwReturn;

mciOpenParms.lpstrDeviceType = "sequencer";
mciOpenParms.lpstrElementName = "song.mid";
dwReturn = mciSendCommand(NULL, MCI_OPEN,
      MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,
     (DWORD)(LPVOID) &mciOpenParms));

   ---- 在 MOBY.CPP 中, 读 者 可 以 看 到 mciSendCommand 的 一 个 简 单
   实 现。 该 程 序 从 开 始 到 结 束 简 单 地 播 放 一 个 音 调, 同 时
   Windows 操 作 系 统 发 送 一 条 消 息 到 该 应 用 程 序。 程 序 对 该
   消 息 的 响 应 就 是 再 次 播 放 该 声 音。
   
   ---- 在 文 件 CGMIDI.CPP 中 演 示 了 一 个 播 放 MIDI 文 件 的 低 级 实
   现 方 法, 这 个 程 序 在 DirectX SDK 的 "Immortal Klowns" 示 例 的 源
   文 件 中 可 以 找 到。 这 个 示 例 没 有 使 用 MCI, 而 是 把 音 乐 文
   件 加 载 到 内 存 中, 然 后 使 用 Windows MIDI 流 设 备 把 数 据“ 流
   ” 到 MIDI 序 列 器 中,Windows MIDI 流 设 备 没 有 自 定 义 编 译 序
   列 代 码 的 效 率 高, 但 是 比 MCI 的 效 率 高。 如 果 不 想 要 程 序
   在 运 行 时 访 问 硬 盘 驱 动 器, 甚 至 访 问 CD-ROM, 预 先 加 载 数
   据 是 一 个 好 方 法。
   
   ---- 在DOS 下, 使 用“ 流” 到 序 列 器 的 方 法 可 能 能 够 抢 救 大
   多 数 现 存 代 码( 在 Windows 下 实 现 时 钟 时 允 许 不 同)。 但 是
   , 我 们 提 倡 使 用 CGMIDI.CPP 中 的 程 序, 无 论 是 否 修 改 它。
   
     _________________________________________________________________
                                      

--
※ 来源: 中国科大BBS站 [bbs.ustc.edu.cn]
--
※ 转载:.紫 丁 香 bbs.hit.edu.cn.[FROM: poster.hit.edu.c]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:207.702毫秒