大雀软件园

首页 软件下载 安卓市场 苹果市场 电脑游戏 安卓游戏 文章资讯 驱动下载
技术开发 网页设计 图形图象 数据库 网络媒体 网络安全 站长CLUB 操作系统 媒体动画 安卓相关
当前位置: 首页 -> 技术开发 -> 程序开发 -> 游戏中的多任务处理

游戏中的多任务处理

时间: 2021-07-31 作者:daque

---- windows 最 杰 出 的 功 能 之 一 是 能 够 同 时 运 行 多 个 程 序, 但 有 时 也 会 让 人 感 到 头 疼, 特 别 是 对 于 那 些 习 惯 于 完 全 控 制 计 算 机 甚 至 时 钟 频 率、 非 常 自 信 的 游 戏 程 序 员( 当 然, 我 们 的 确 在 乎 那 些 没 礼 貌 的、 在 退 出 时 不 恢 复 正 确 的 系 统 时 间 的 游 戏。 但 是 幸 好, 现 在 我 们 可 以 忘 掉 这 些 了)。  ---- 在 多 任 务 环 境 下, 游 戏 程 序 员 需 要 注 意 三 个 大 的 负 效 应:  当 游 戏 失 去 焦 点 而 进 入 后 台 后, 其 执 行 不 得 不 被 挂 起( 可 以 在 moby dick windows 中 使 用“ 中 止 的” 变 量 观 察 它 是 如 何 工 作 的)。 如 果 是 一 个 实 时 游 戏, 程 序 员 当 然 希 望 它 被 悬 挂。 但 在 回 合 制 游 戏 中, 当 玩 家 去 做 其 它 事 情 时, 程 序 员 可 能 不 希 望 计 算 机 一 方 作 任 何 动 作, 但 希 望 后 台 的 人 工 智 能(ai) 运 算 依 旧 执 行。  其 它 的 任 务 占 用 cpu 时 间, 结 果 造 成 我 们 不 能 一 直 控 制 游 戏 中 事 情 发 生 时 的 速 度。 我 们 将 在 后 面 讨 论 这 个 痛 苦 的 问 题。  每 当 游 戏 回 到 前 台, 程 序 员 不 得 不 重 画 游 戏 窗 口。windows 并 不 负 责 记 忆 它 所 覆 盖 或 隐 藏 的 窗 口 的 内 容; 它 所 能 做 的 最 多 是 通 知 一 个 窗 口 需 要 重 画 其 客 户 区 域。 这 在 有 关 windows 的 文 章 中 都 有 论 述( 参 见 wm_paint 的 内 容), 我 们 在 这 里 就 不 讨 论 了。 事 实 上,moby dick windows 并 不 恢 复 其 自 己 的 窗 口; 我 们 将 在 讲 到 directdraw 下 的 双 缓 冲 时 看 它 是 如 何 实 现 的。  程 序 中 的 多 任 务  ---- 尽 管 moby dick dos 在 使 用 中 断 处 理 程 序 时 展 示 了 内 部 多 任 务( 或 者 说 多 线 程) 的 一 种 原 始 形 式, 但 是 该 程 序 仍 然 没 有 突 破 dos 的 单 主 题 特 性, 即 在 一 个 时 间 只 做 一 件 事 情。 有 些 dos 程 序 的 确 作 到 了 真 正 的 多 线 程, 但 是 那 需 要 非 常 巨 大 的 编 程 工 作。windows 95 sdk 使 这 项 工 作 简 单 了 许 多, 把 线 程 放 进 每 一 个 游 戏 开 发 者 的“ 锦 囊” 之 中( 如 果 读 者 还 不 熟 悉 这 个 概 念, 那 么 简 单 说 明 一 下, 一 个 线 程 就 是 程 序 的 一 部 分, 它 执 行 时 独 立 于 其 它 的 部 分, 并 且 不 需 要 与 其 它 部 分 同 步。 线 程 不 是 由 中 断 来 驱 动 的; 它 们 只 是 在 每 一 次 windows 给 它 们 cpu 时 间 时 继 续 其 执 行。)  ---- 在 下 列 情 况 下, 可 能 要 考 虑 实 现 独 立 的 线 程:  允 许 后 台 ai。 就 算 是 用 户 正 忙 于 来 回 移 动(moving pieces around)、 打 开 对 话 框 等 事 情, 计 算 机 也 能 够 考 虑 其 下 一 步。 处 理 这 类 线 程 非 常 方 便, 因 为 它 不 需 要 与 其 它 的 事 情 同 步。  预 先 加 载 数 据。 例 如, 当 玩 家 正 努 力 向 下 一 级 奋 斗 时, 使 一 个 线 程 负 责 读 取 文 件 并 准 备 好 游 戏“ 世 界”。  给 予 时 间 紧 迫(time-critical) 的 任 务 优 先 权。 我 们 将 在 后 面 会 到 这 个 主 题。  游 戏 循 环  ---- 游 戏 循 环 的 概 念 在 各 编 程 环 境 下 都 比 较 相 似。 第 一 步, 需 要 获 取 输 入: 可 以 是 轮 询 它, 等 待 它, 或 者 在 它“ 运 行” 时 通 过 中 断 或 一 个 消 息 队 列 拦 截 它。 第 二 步, 处 理 该 输 入, 并 且 把 它 变 成 一 个 在 游 戏 中 有 实 际 意 义 的 动 作, 如: 使 飞 机 倾 斜 飞 行 或 小 卒 向 前 走 一 步。 然 后, 把 结 果 显 示 出 来。 当 然, 在 这 个 主 题 中 也 要 求 精 雕 细 刻 和“ 变 奏 曲”, 包 括 计 算 ai 的 移 动、 把 控 制 权 从 一 个 玩 家 移 交 给 另 一 个 玩 家、 检 查 胜 负 等 等。  ---- 然 而, 在 windows 和 dos 下 实 现 循 环 的 机 制 迥 然 不 同。 每 个 windows 程 序 都 建 立 于 一 个 消 息 循 环 之 上。 尽 管 一 个 游 戏 循 环 可 以 建 立 在 消 息 循 环 之 上, 但 是 这 两 者 仍 有 本 质 的 差 别。  moby dick dos 的 循 环  ---- moby dick dos 演 示 了 一 种 简 单 的 游 戏 循 环, 在 这 里 我 们 所 做 的 工 作 是: (a) 检 查 是 否 有 什 么 东 西 要 移 动, (b) 移 动 它, (c) 显 示 结 果。  while (!gamedone) {   //挪用功夫步调 -即使功夫未到,则没有任何相应。   ahabmoved = move_ahab();   //仅当 ahab没有挪动时挪动 moby dick。   //要不它们大概擦肩而过却不许阻挡。   if (!ahabmoved) move_moby();   //即使有任何一个挪动,革新屏幕,   //并查看能否有成功和波折。   if ((mobyx != oldmobyx) || (mobyy != oldmobyy)     || (ahabmoved))   {    updatescreen();    if ((mobyx == ahabx) && (mobyy == ahaby)       && (painted[mobyx][mobyy]))    {     gamedone = 1;     cprintf("\a");     cprintf("you win!");    }    if (timesup <= 0) { cprintf("\a"); cprintf("time's up!"); gamedone="1;" } if (raw_key="=" make_esc) { gamedone="1;" progdone="1;" } } //中断革新 } //中断游戏里面轮回 (while !gamedone) moby dick windows的轮回 从外表可见,犹如没有多大的分辨: do { if (peekmessage(&msg, null, 0, 0, pm_remove)) { if (msg.message="=" wm_quit) break; //独一的退出轮回的出口。 translatemessage(&msg); dispatchmessage(&msg); } else { if ((mobyx !="oldmobyx)" || (mobyy !="oldmobyy)" || (ahabmoved)) { updatescreen(); if ((ahabx="=" mobyx) && (ahaby="=" mobyy) && (painted[ahaby][ahabx])) { control="messageboxex(hwnd," "you caught moby! play again?", "call me ishmael", mb_iconquestion | 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 消 息 响 应 程 序 中。 回 合 制 游 戏 则 常 常 在 输 入 消 息 的 响 应 函 数 中 做 大 量 的 工 作。 

热门阅览

最新排行

Copyright © 2019-2021 大雀软件园(www.daque.cn) All Rights Reserved.