当前位置: 首页 > news >正文

doom3 代码结构

doom3代码结构 code

原文地址 https://www.iddevnet.com/doom3/code.php

原来 我认为这个网站已经倒闭了,毕竟从Doom4,quake4是2004,2005的,

关注的人太少了 ,我觉得这些文章有助于对于doom3,代码的理解,

比单纯的看源代码要好的多了

idcevNet是介绍doom3和quake4的Mod关卡制作的网站,

我以前翻阅时候,网站还在....其他 不知道.........

但是我也没有太多的时间来翻译 这个,我看 有道翻译 插件 的质量还 可以,

有的英文网页,使用 有道 翻译 插件 查看……

译文如下

该守则是所有 真正的乐趣 开始 发生 的 地方。

Doom 3 SDK拥有相当于游戏源代码的一半。

我将简要介绍 SDK 中 的 主要部分,

并触摸 主引擎 中 的一些 子系统。

编译

您将需要做的第一件事是确保您可以构建和运行代码。

我们使用Visual Studio.Net开发它,

它可能或可能不工作在6.0。

理想情况下,您只需双击解决方案文件并点击构建即可。

它将在输出文件夹中创建一个gamex86.dll。

您将要使用批处理文件,后期制作步骤或仅通过更改链接器输出目录

将其移动到您的mod文件夹。

测试您的代码是否正在使用的一种快速方法是通过打开Entity.cpp,

滚动idEntity :: Spawn并在“if

(def)”行之后的开头插入此代码:

gameLocal.Printf(“Hello%s!\ n”,classname);

这应该导致“Hello <classname>!”随时在新的实体中出现在控制台中。

idlib

idLib只是一个存储随机,通用,经常使用的代码的库。

它包含字符串代码,解析器,几个哈希表,

数学库,计时器,容器等等。

它也是存储所有 SSE 代码的地方,所以 检查idLib / Math / Simd _ *。

*如果你喜欢这样的事情。

游戏系统

游戏代码有很多部分与Doom 3没有任何关系,

而是基于游戏代码构建的基础。

GameSys


游戏代码的核心是GameSys。

这包含了基本的idClass类,

以及事件系统和保存游戏系统。

游戏系统是非常抽象的,

并没有真正 了解 任何建立在 其上的实际游戏。

它知道如何做是创建对象,消防事件,并走走对象进行保存和 恢复。

当在 entitydef中 指定“spawnclass”时,

它会 调用 idClass :: CreateInstance来创建 该 spawn 类 的 实例。

类通过 使用 Class.h中定义的CLASS_DECLARATION宏来 注册到idClass

AI


AI文件夹实际上 并不包含 怪物的AI(在脚本中定义)。

相反,C ++ AI代码是将脚本与游戏的其余部分联系起来的“胶”。

它包含通过AAS(区域意识系统)的路由和路径,以及事件处理。

核心对象是idAI,

它来源于

idActor-> idAFEntity_Gibbable-> idAFEntity_Base->

idAnimatedEntity-> idEntity-> idClass。

在Doom 3中,

路由是“如何从地图的一个区域到另一个区域”,

而路径是“如何在该椅子周围导航”。

差异是微妙但重要的。

AI是与正在生产的实际游戏最紧密的 游戏系统。

一个例子是 idAI_Vagary,

它包含 Vagary 在播放器上 拾取 和 抛出对象的 特殊代码。

AI_events.cpp包含处理AI脚本中的事件的所有代码。

大多数函数只是调用AI.cpp的存根,

其中代码的大部分是。

一个例子是 Event_KickObstacles,

它刚刚 修复 了 参数 并 调用了 KickObstacles()。

物理学


Doom 3游戏代码附带了整个Doom 3物理系统。

核心引擎 本身绝对 没有物理代码。

即使LCP 解决方案都在 idLib中。

物理代码绝对是巨大的,但幸运的是,您不需要在“”中了解

其中的大部分内容,(更重要的是)如何使用它。

idPhysics 对象 是用于 操纵 实体 的 位置 和 方向 的 工具。

物理对象是用于碰撞检测的idClipModels的容器。

物理系统 根据 物理学规律 或 其他规则 处理通过 世界移动 这些 碰撞模型。

每个idEntity都有一个指向idPhysics对象的指针,该对象可以使用idForces移动,

尽管还有其他方法可以移动它。每一帧idEntity从物理系统的原点和轴信息更新其视觉模型。

渲染系统 具有每个 实体 的视觉模型,物理系统具有每个实体的剪辑模型(有时称为战斗模型)。

可以从地图模型(使用标记为剪辑的任何曲面)加载碰撞模型,或者可以从渲染模型生成

(默认情况下,它使用渲染模型中的所有曲面,但可以使用“纹理/普通/碰撞“应用它的材料,

在这种情况下,它使用该简化模型),或者它可以从.cm文件加载(使用DOOMEdit创建)。

idPhysics 有多个子类,它们都实现了专门的物理类型。

例如,门使用idPhysics_Parametric,抹布娃娃使用idPhysics_AF等等。

大多数 物理类型 都是自解释的,并且它们 都在.h文件的顶部有一个简短的描述。

如果您不希望在物体上运行物理,请确保TH_PHYSICS标志已被清除

(例如,当对象进入休息状态时)。如果不能触摸对象,而不是仅将内容掩码设置为0,

则应该取消链接剪辑模型。这将加速碰撞检测,因为它甚至不会访问该剪辑模型。

你应该确保没有任何可能导致物理学不断运行在物体上的东西的小动作。

有几个控制台命令帮助调试物理减速。最有用的可能是g_showActiveEntities。

anim动画动画


系统不会决定要播放哪些动画(在脚本中完成),而是在动画中进行混合动画,帧之间的拖动,

混合骨骼权重和调用帧命令。

在Doom 3中,有4个不同的动画通道(“躯干”,“腿”,“头”,“眼皮”)以及第五个伪通道(“全”)。

每个动画漫画可以同时播放不同的动画。这样可以避免地震2“射击时出现”问题,

以及Quake3 “我的模式是碎片”的问题。

有一个单一的网格,但每个动画影响一组不同的骨头。

所有这些都在Anim_Blend中处理。它还可以处理两种完全不同的动画之间的混合

(例如当您在武器之间切换时)。

框架命令(在modelDef中定义)从ServiceAnims调用。

每次更新动画时,它会看到它是否通过了定义了frame命令的“边界”。

实际上真的很容易添加自己的帧命令。您只需要将一个项目添加到frameCommandType_t

枚举中,

然后在 AddFrameCommand 和 CallFrameCommands 中 实现 它 的 case 语句。

Script脚本

(很多我看源码,是根据Quake3的 Script 改进而来..只不过加入了c++的一些语法)


类似于Anim,脚本子系统是非常通用的,根本不知道Doom。

脚本系统的主要入口点是通过idProgram。

系统中只有一个程序(它是idGameLocal的成员)。

它扫描脚本目录并编译其中包含的所有脚本。它拥有所有的功能和变量信息。

idProgram 是唯一使用idCompiler的类。

idCompiler是Op代码生成器。

它使用idLib中定义的词法分析器和解析器。

要实际调用脚本函数,创建一个新的idThread(它应该被分配给新的,不是在堆栈上创建的)。

idThread中有静态函数来处理当前活动线程的跟踪。

每个线程都有一个idInterpreter,它包含一个线程的所有堆栈信息和指令指针。

游戏线程不是实际的操作系统线程。

它的工作方式是脚本系统为每个线程提供运行每个帧的机会。

线程运行,直到它获得多帧事件或遇到暂停事件,如sys.pause,sys.waitFor或sys.wait

(还有一个对ai对象的等待命令)。

游戏实用程序文件

Net网络


原始网络代码仍然在引擎内,但Doom 3暴露了以前的id引擎没有的很多网络。

在Doom 3中,您可以将包含您想要的所有内容的自定义位消息雕刻成任意客户端。

这显然是一个非常强大的工具。

大部分的代码都在Game_network.cpp中,但网络代码几乎遍布所有的游戏文件。

两个最重要的功能是WriteToSnapshot和ReadFromSnapshot。这两个功能处理实体的定期更新。

所有的客户端实际上都是运行与服务器完全相同的游戏代码,

所以在理论上他们永远不会失去同步,

但是众所周知,他们确实失去了同步。快照机制将定期捕获客户端以与服务器同步。

Game / GameLocal


idGame是整个游戏dll的界面类。这是核心引擎唯一看到的。

引擎在加载游戏DLL时首先要调用GetGameAPI,将其接口指针传递给一系列内部系统类。

该函数将系统类指针复制到dll中的全局指针,

然后返回一个指向idGameLocal对象(指向idGame)的指针。

idGameLocal是游戏界面的实际实现。

由于gameLocal是游戏中的全局对象,所以很多真正的随机函数最终都会被抛出来。

在idGame中定义了非常重要的功能(如InitFromNewMap,RunFrame和Draw)。

MultiplayerGame定义了所有多人游戏的特定游戏代码,例如保持得分和投票。

Pvs
PVS(潜在可见集)跟踪从其他方面可以看到的区域。

它是从渲染门户的地图加载计算的。

它允许游戏代码确定对象或怪物是否应该处于休眠状态,

网络代码也可以使用它来确定哪些更新发送到哪些客户端。

AF


idAF是一个铰接的图形助手类。

它包含一个指向动画师的指针,它用于围绕对象移动。

它没有做任何解决(这都是在idPhysics_AF中完成的),

但是将解决的AF位置应用于实体模型(记住,物理模型是与渲染系统完全分离的系统)。

IK


idIK是逆运动学助手类。

目前只有Actor角色才能将他们的脚放在地上,但很容易被用于更多的地方。

它与idAF类似。

PlayerIcon


idPlayerIcon是一个帮助类,用于在多人游戏中头部绘制滞后和聊天图标。

PlayerView


idPlayerView是一个帮助器实用程序,从玩家角度呈现场景。

这是PDA被绘制的地方,以及最后一刻的影响,如屏幕血溅,狂战士,影响力和双重视觉观察,

以及屏幕淡入淡出。

SmokeParticles


烟雾 粒子系统 用于该不断变化 以完全非 paramentric 方式位置或取向的颗粒的效果。

这样的一个例子是烟雾的影响

GameEdit


好我说谎,核心引擎也看到了 idGameEdit。

这是一个实用程序类,允许编辑器(如AFEditor)在游戏运行时操纵实体。

比如在控制台中用来进行对于游戏关卡编辑器的加载,灯光编辑器的使用了。

游戏实体

现在我已经浏览了游戏制作的主要系统,我可以开始谈论实际的游戏代码。

我要讨论的其余代码几乎都是从idEntity派生的。

这些是门,怪物,玩家,物品,火车,触发器,灯光和其他众多的东西。

我认为最简单的方法是逐个谈论每个文件。

实体


idEntity是派生所有实体的基类。它处理所有实体常见的大多数“低级”维护功能,如诞生,思考,

运行物理,绑定,播放声音,显示,隐藏等。

Entity.cpp 还包含 idAnimatedEntity,它只是一个具有 关联动画师(可以播放动画)的 实体。

WorldSpawn

Worldspawn是一个代表整个级别本身的实体。

这里唯一的代码是从地图读取一些属性,以设置 重力 和 耐力,并调用 级别 脚本。

相机


idCamera用于客观截图(当客观工具提示弹出时)以及 电影摄影机。

大部分代码涉及以下动画 (在md5camera类中定义)。

摄像机 也可以绑定到移动实体(因为任何实体可以绑定到任何其他实体)。

SecurityCamera


安全摄像机用于制作平移,可拆卸的安全摄像机(如CPU中的)。

他们只是左右移动,找出自己的事情。

脆性断裂脆性


断裂是任何物体在损坏时相当壮观的物体的术语。

通常这意味着玻璃,但从技术上讲,您可以在BrittleFracture对象上放置所需的任何纹理。

脆性断裂会将平面细分成多个碎片,然后跟踪 碎片 之间 的 连接,

因此当两个碎片之间有足够的损坏时,链接 将 断开。

单个玻璃片 通过物理系统 作为 idPhysics_StaticMulti 的一部分。

这使得 破碎玻璃 相当 缓慢。

可以通过将碎片作为粒子进行处理(从而不通过物理系统运行)来加快它的加速,

但是看起来不会那么好。

Fx


FX实体是特殊效果的容器对象。该文件 还包含作为 传送目的地 实体 的idTeleporter。


IdLight实体代表了可以用灯光完成的所有事情:打开和关闭,有声音脉动,衰落进出等。

声音


idSound就像idLight,但是声音

项目


项目是东西玩家可以拿起得到的东西。武器,健康,盔甲等都是物品。

该文件定义了基本idItem(大多数情况下使用),以及

idMoveableItem(用于装甲和其他较大的对象),

idItemPowerup(隐形,berserk等),idObjective(表示一个目标),

idVideoCDItem,idPDAItem和idMoveablePDAItem。它还定义了idItemRemover和idObjectiveComplete,

它们是从玩家iventory中删除项目的实体。

项目和可移动项目之间的区别在于环境(如门)在触摸项目时的反应。

对于常规项目,对象将直接通过它,

但对于可移动项目,项目将被移动器推动。

idMoveabe可移动物体的类


idMoveable 就像一个可移动的项目,你不能拿起来。

例子是 人 们喜欢打汉堡包,箱子 ,苏打水罐,垃圾桶,垃圾桶等。

有两种特殊情况 下 可移动 的 定义:idBarrel和idExplodingBarrel。

我希望这两个行为是显而易见的。

trigger触发器


触发器是触发目标实体或发生事件时调用脚本的实体。

“某事”取决于它是什么样的触发器。

有玩家的触发触发器,怪兽的触发触发器,定时器触发器,伤害触发器,褪色触发器,

仅在触发一定次数后触发的触发器,触发器仅触发某些实体等。

主要的是请记住,

每当触发器被触发时,它将向其目标的任何实体发送一个Activate事件。

target目标


目标被用作触发的目标。有大约30种不同的目标实体类型,它们做的是非常不同的事情,

所以我不会提及它们。

幸运的是,大多数目标往往相当小(只有一个Event_Activate功能),

所以我需要一分钟才能通过Target.h扫描

其他杂

是我们将实体放在其他地方并不合适的地方。

它包含像idVacuumEntity和idPlayerStart这样的东西。

它还包含约30个实体,所以我不会去那些。

AFEntity


AFEntity是一个具有关联关联数字的实体。

它实际上可以是许多不同类型的实体之一。玩家,怪物,车辆,链条(如起重机)

和通用的尸体都是AF实体。

有一个idAFEntity_Base类,其中包含所有AF实体共享的一些基本功能,

然后派生自idAFEntity_Gibbable,idAFEntity_Vehicle,idAFEntity_SteamPipe和

idAFEntity_ClawFourFingers。

除了产生和销毁AF实体之外,AFEntity实际上并不做很多事情,

因为所有的真实工作都是在idAF和idPhysics_AF中完成的。

idClass + -Identity + -idAnimatedEntity | -idWeapon | -idAFAttachment + -idAFEntity_Base ----使用idAF | -idAFEntity_ClawFourFingers | -idAFEntity_Vehicle | | -idAFEntity_VehicleFourWheels | + -idAFEntity_VehicleSixWheels + -idAFEntity_Gibbable | -idAFEntity_WithAttachedHead | -idAFEntity_Generic | -idAnimated + -idActor ----使用idIK | -idPlayer + -idAI

Actor

一个演员是需要一些AI的东西。一般来说,一个actor有一个与它相关联的.script,

但并不总是需要一个(一个没有脚本的演员,只要站在那里,眨眼就像在现实生活中)。

idActor源自idAFEntity_Gibbable。

播放器


idPlayer是...播放器。它处理输入处理,项目处理,电影,动画,传送和一整套其他事情

(大概8000行)。

Player.cpp也是idInventory的所在地,它只是玩家库存的辅助类。

射弹


一个物体是一个飞过世界的物体,对任何物体造成伤害。

一般来说,他们被武器开枪(见下文),但不一定是。

例如,“雷约”创造了射弹,但他技术上没有任何武器

(肩上安装的火箭发射器是他的模型的一部分,岩石是由脚本产生的)。

武器


一个idWeapon是玩家在游戏中跑到身边的一个实体。

它可能会也可能不会射出射弹,但大部分时间都是这样。

idWeapon有趣的是每个玩家有一个,而不是一个武器。

当玩家切换武器时,只需将一个新的武器脚本加载到现有的idWeapon中。

引擎 代码

现在我们已经完成了一大堆的源代码,我们来看一些您没有代码的系统。

System


Sys是所有操作系统特定呼叫所在的地方。像锁定内存和诞生 线程 的东西在这里。

所有的函数和类都在sys_public.h中定义在'sys'文件夹中。

游戏中的所有功能都可以通过idSys单例 (通过全局'sys'对象访问)的成员。

Common
idCommon处理启动和关闭所有其他系统(包括游戏系统)。

它还执行错误,警告和调试消息打印

(它将消息路由到日志文件,控制台,早期控制台,专用控制台或任何其他需要它)。


在引擎中,代码看起来像这样:

void main(void){ Sys_Init(); 共>初始化(); 而(1){ 共>框架(); } }Sys_Init(); 共>初始化(); 而(1){ 共>框架(); } }

命令系统


idCmdSystem处理用户键入任何一个控制台(游戏中,专用或编辑器)的命令。

游戏代码也可以直接将命令传递给命令系统进行处理。

命令系统的每个帧都将解析出命令缓冲区,并通过调用与命令关联的回调函数

来执行任何等待命令。

例如,“quit”将调用Com_Quit_f回调函数(然后调用common-> Quit)。

CVar System


idCVarSystem处理 控制台 变量。

Doom 3中的控制台变量 比 以前的引擎中的控制台变量 更冷。

它们被添加到CVar系统中:

idCVar com_showFPS(“com_showFPS”,“0”,CVAR_BOOL | CVAR_SYSTEM,“”);

idCVar的构造函数将cvar添加到cvar的静态列表中,然后在启动时将其添加到cvar系统中。

然后,您可以通过实例化对象访问cvar。您还可以通过实际cvar系统中的函数来访问cvars,

但是这有点慢(因为它必须每次执行查找,而不是将其存储在cvar对象中)。

文件系统


idFileSystem允许访问文件。

这是非常抽象的,因为您请求的文件可能在真实的文件系统中,

或者它可能在包文件系统中。

它也可能在mod目录或游戏目录中。

当你要求“cheese / gouda.jpg”时,它将搜索游戏目录,然后是 游戏包 文件

,然后是基本目录,然后是 基本包 文件。

如果服务器以纯模式运行,则 文件系统 将只检查 包文件。

文件系统跟踪在服务器上进行纯检查的所有文件,

也可以设置为复制模式(fs_copyfiles)以帮助进行构建。

网络系统


游戏系统真的只能访问网络系统的两个部分:

回读读/写(idGame :: ClientReadSnapshot / idGame :: ServerWriteSnapshot),

并 发送 和 接收 可靠消息(在idNetworkSystem中)的功能。

idNetworkSystem中还有其他一些功能来获取 ping 和 丢包 等 统计 信息。

渲染系统


渲染器分为3个不同的概念部分:

  • RenderWorld与场景图非常相似。它包含场景中的所有渲染模型和纹理,
  • 以一些易于剔除的方式排列。它处理对后端的剔除和调度命令。
  • 后端是一个经过优化的系统,用于渲染三角汤(待定)。
  • 为Doom 3支持的每个主要硬件架构(NV20,R300,ARB,ARB2,CG)
  • 编写了一个单独的后端。
  • 渲染系统管理所有的渲染世界(可以有多个渲染),并且作为渲染系统的入口点。
  • 声音系统


  • 声音系统非常类似于渲染系统,

  • 因为有一个声音世界(或两个或三个)处理所有真正难处理的东西,

  • 声音系统 只是作为一个戒指领袖。

  • 声音世界 跟踪所有发射器的位置,它们在什么状态以及听众的位置。

  • 渲染模型管理器

    idRenderModelManager处理渲染模型的加载和释放。

  • 这些型号可以是各种文件格式,包括BSP,LWO和ASE

  • 。模型管理器首次在请求时缓存模型数据。

  • 每个要用于级别的模型都应该在级别加载期间由模型管理器加载

  • (在BeginLevelLoad和EndLevelLoad调用之间)。

  • 这将确保在实际游戏过程中最小的磁盘命中。

  • user 用户界面管理器

  • idUserInterfaceManager的行为与模型管理器完全相同,除了GUI。

  • decl 声明管理器

  • idDeclManager处理加载,缓存,读取和写入任何种类的声明。

  • 它扫描目录并解析出decils,为每种类型自动创建适当的decl对象。

  • 您可以使用decl管理器注册自己的定制声明类型,以及要扫描的新文件夹。

  • 就像其他管理者一样,它所加载的任何decls都应该在指定的级别加载时间内完成,

  • 以防止不必要的磁盘命中。

  • AAS文件管理器

  • idAASFileManager加载并释放AAS(区域感知系统)文件。

  • 这是在游戏代码中获取idAASFile的唯一方法。

  • 碰撞模型管理器

  • 碰撞模型管理器与渲染模型管理器完全相同,除了物理系统而不是渲染系统。

http://www.jsqmd.com/news/1251188/

相关文章:

  • 2026小红书免费去水印工具怎么选?在线网站与小程序风险提醒及版权注意事项 - 耶斯去水印
  • 上市公司公开财报数据采集:OpenClaw批量抓取年报数据,自动生成财务对比分析表
  • 2026年商用智能4K电视靠谱合作厂家选购全指南 - 品牌优推
  • 从注射到口服:Lipfendra如何重塑高胆固醇血症长期管理的日常场景【海得康】
  • 2026年PA粉碎料生产厂家挑选实用指南与选购注意事项 - 品牌优推
  • 羽球搭子 HarmonyOS 实战(19):账号认证后的数据作用域
  • 2026济南白酒加盟品牌梳理 雨荷泉酒业相关资讯参考 - 起跑123
  • 400电话多场景架构适配与企业选型实战:从热线接待、中转分流到风控合规落地
  • YOLOv11目标检测中的ATEM模块:小目标检测新突破
  • 2026昆山中央空调安装/工厂智能照明厂家选购指南:5大维度避坑攻略,助你选对源头工厂 - mobible
  • hls高层次设计ii latency效率-好的设计判断标准
  • 【OpenHarmony/HarmonyOS】ArkUI 科幻星空动效:Canvas 粒子、流星与声明式多层动画
  • 基于BERT的中文文本情感分类实战指南
  • 【Android Performance】Vmpressure与LMKD协作机制详解——从内存压力公式到进程回收决策的完整链路
  • “AI画得再美也落不了地”?揭秘建筑可视化4大幻觉风险:结构冲突、材料失真、日照偏差、规范盲区
  • 2026实地走访宁波技工学校 聊聊择校的真实体验感受 - 起跑123
  • 2026 实测:抖音视频无水印保存怎么做?合法方法与第三方工具使用全解析 - 耶斯去水印
  • 2026年农资采购腐植酸粉 高性价比报价商家推荐哪家 - 品牌优推
  • 2026 年新消息:天门比较好的华美月饼批发厂家哪家靠谱,揭秘月饼背后的奢华:这才是真“华美”! - 行业推荐官【认证】
  • 2026 还在找小红书免费去水印工具?收藏这条教程就够了,手机电脑都用得上 - 耶斯去水印
  • 论文降重与AIGC检测技术解析及工具应用
  • 视频生成管线后端:从“异步等待”到“流式进度推送”的工程重构
  • 我们公司是做人力资源服务的,想在豆包AI进行推广,哪家豆包GEO服务商合适 - 品牌深度评测
  • MSPM0微控制器NONMAIN配置详解:从安全启动到量产避坑指南
  • 2026年不锈钢制药设备批发商哪家好 采购选型实用参考 - 品牌优推
  • 2026亚太EMBA排名前三|中立院校择校测评
  • K系列往复式给煤机公司联系方式正规获取实用指南 - 品牌优推
  • 【RT-DETR涨点改进】CCF-A 2026顶刊 | 独家注意力改进篇|引入RSWAttention​​​​​​​重构滑动窗口注意力模块,聚焦细粒度局部特征,含10种创新改进点,助力目标检测高效涨点
  • 想了解新型岩棉板源头厂家哪家好 实用选型参考全指南 - 品牌优推
  • AI证件照背景替换技术解析与应用实践