A polyobject is a movable group of one-sided linedefs. This extension of the Doom engine was originally implemented in Hexen by programmer Ben Gokey of Raven Software. They were added to the game engine in order to give Raven's mappers a much more vast palette of doors, machinery, crushing traps, and secret push walls than was previously achievable, somewhat closing the gap with more modern engines.
Although binary space partitioning results in a static BSP tree which is not amenable to dynamic geometry, it is possible to exploit the complete convex mapping of space provided by the tree to insert dynamic objects, so long as they obey certain restrictions:
- The dynamic objects must not intersect with any static geometry.
- The dynamic objects must not intersect with one another.
- The dynamic objects must either be convex or have an explicitly specified draw ordering.
- The dynamic objects must either be contained entirely within a single subsector or be split into fragments which are themselves contained within single subsectors.
So long as the dynamic geometry in each subsector follows these rules, it can be drawn first, before the normal contents of the subsector, and the other assumptions implicit within the BSP rendering algorithm will be maintained.
Glitches in rendering that can be caused when polyobjects cross node lines (and thus overlap with static geometry or into adjacent subsectors) can be partially but not entirely abated by use of a so-called "polyobject-aware" node builder, which includes the popular ZDBSP.
As mentioned above, polyobjects were originally an innovation in the Hexen codebase. In Hexen, polyobjects are chiefly used to create sliding and rotating doors, pushable walls, and dangerous horizontal crushers. Since polyobjects are also linked into the blockmap like normal linedefs, it is possible for them to clip the movement of things, as well as push things that block them and optionally inflict crushing damage while doing this.
The Hexen line specials which allow the creation and manipulation of polyobjects are known by the following ACS names:
The latter two line specials are used to identify the lines that belong to the polyobject. Due to limitations of the Hexen map format, there cannot be more than 256 polyobjects in a single map. In addition, Hexen imposes an artificial limit of 64 segs per polyobject. Hexen can only reliably support one polyobject per subsector, and cannot deal properly with polyobjects that overlap into adjacent subsectors or that are made to move too far from their spawnpoint.
Polyobj_ExplicitLine allows the rendering order of each individual line of a polyobject to be defined by the map designer, at the expense of not being able to place other special actions on the polyobject's lines. This allows the visual glitches that may appear with non-convex shapes to be cleaned up.
Hexen polyobjects additionally require two mapthings to identify the position at which they were built on the map, and how that point relates to the position at which they should be placed at runtime. These thing types are the "anchor point," with DoomEd number 3000, which must be placed near the linedefs that are part of the object, and the "spawn points," with DoomEd numbers 3001 or 3002, which are used as the runtime spawning location of the polyobject. The polyobject is translated to this location by moving the anchor point to the spawn point, and moving all linedefs so that their relationship to the anchor point remains constant. Use of the 3002 spawnpoint type denotes that the polyobject should do crushing damage to objects which block its motion.
Via use of line arguments, it is also possible to cause polyobjects to mirror the motion of other objects. When a move or rotate special is applied to an object, it will cause any objects mirroring it to move or rotate in the opposite direction.
Source port implementations
Since the original Raven polyobject system left much to be desired with its restrictions of one polyobject per subsector, no intersections with static geometry, and difficulties wherever polyobjects were crossed by node lines, source port authors eventually sought more robust solutions to the problem.
The Eternity Engine was the first port to attempt to re-implement polyobjects. James Haley (Quasar) created a dynamic seg rendering system (dubbed "dynasegs" for short), which split the polyobjects through the static world BSP tree in order to generate fragments contained within each subsector contacted by the polyobject. This eliminated the need for a polyobject-aware node builder. It also lifted the one-object-per-subsector rule by performing a front-to-back z-sorting algorithm on fragments within each subsector. Polyobjects could also now move arbitrarily between subsectors, rather than being constrained within the single area in which they were spawned.
Limitations of this initial system were still evident, however. The ZDoom source port initially adapted the same approach developed for Eternity, but then went one step further by replacing the restrictive z-sort with generation of "MiniBSP" trees within each subsector, dynamically recomputed via the internal node builder whenever a fragment was added or removed from the subsector during dynaseg generation. These BSPs provide a complete ordering of the dynamic segs so that they draw in the correct sequence regardless of the camera view point. By including the static segs of the subsector into the BSP as well, this removed the remaining limitations: polyobjects could now be concave, intersect with static geometry, and intersect with each other.
ZDaemon and Eternity eventually both followed suit with independent implementations of MiniBSP construction.
Ports have also added various new mapping features related to polyobjects.
ZDoom prefers the use of thing types 9300, 9301, and 9302 to those used by Hexen so as to avoid editor number conflicts with Doom and Strife (for example, 3001 is also used by the Imp and the Reaver). It also adds a third type of polyobject (9303) which hurts on simple contact. Since version 2.6.0, ZDoom also allows to have a finite vertical range to polyobject, by using two-sided linedefs (which require to be explicitly marked as polyobject lines) with the 3D middle texture flag set. For this to work correctly, however, the floor and ceiling of the sector referenced by the polyobject lines (the holding sector) must match the heights of the sectors in which the polyobject will move, giving at least as much vertical room to move.
Eternity is currently capable of allowing use of polyobjects inside Doom-format maps via the use of ExtraData, and will also support them in the Hexen and UDMF map formats when support for those formats has been finalized. Like ZDoom and for the same reason, Eternity supports the editor numbers 9300, 9301, and 9302 for polyobject anchors and spawn points, and support for ZDoom's new type (9303) was added in r851.
EDGE also has PolyObject support, using ZDoom's system. Polyobjects are supported in normal Doom/Hexen formats, as well as UDMF.
- Polyobject at the Eternity Engine wiki
- Polyobject at the Sonic Robo Blast 2 wiki
- Polyobject at the ZDoom wiki