DrawableOrientedSprite
Extends: Sprite
A Sprite that swaps which named animation is active based on the angle between the camera and this entity - the classic Doom/Duke3D "billboard sprite" technique for faking full 3D orientation with pre-rendered 2D views. See docs/drawables-and-scene-objects.md for a full walkthrough and specs/2026-09-22-oriented-sprite-billboards-design.md for the design.
Properties
numAngles(integer) — Number of horizontal (azimuth) view buckets around the entity. Bucket 0 is thenumElevationBands(integer) — Number of vertical (elevation) view bands, from the camera looking up at the
Constructor
new DrawableOrientedSprite(
owner: GameEntity,
spriteSheet: ifDraw2d,
cellWidth: integer,
cellHeight: integer,
numAngles?: integer,
numElevationBands?: integer,
args?: roAssociativeArray,
): DrawableOrientedSpriteParameters
owner(GameEntity)spriteSheet(ifDraw2d)cellWidth(integer)cellHeight(integer)numAngles(integer, optional, default: 8)numElevationBands(integer, optional, default: 1)args(roAssociativeArray, optional, default: "{}")
Instance Methods
addOrientedAnimation(
baseName: string,
angleFrames: Array.<Array.<integer>>,
frameRate: integer,
playMode?: SpritePlayMode,
): void
Registers one animation per angle bucket under baseName (e.g. "walk"), for the single elevation band case (the common one - a sheet with no distinct top-down/ bottom-up art). Sugar for addElevationOrientedAnimation with a single-band wrapper; errors (via addElevationOrientedAnimation's own validation) if numElevationBands isn't actually 1.
Parameters
baseName(string)angleFrames(Array.<Array.<integer>>) — array of exactly numAngles entries, each an integer[] of frame indexes for that bucket's own art. Every bucket needs its own real art - there is no mirroring/flipping support (see issue #104's design notes for why).frameRate(integer)playMode(SpritePlayMode, optional, default: "SpritePlayMode.Loop")
Returns
void
addElevationOrientedAnimation(
baseName: string,
elevationBands: Array.<Array.<Array.<integer>>>,
frameRate: integer,
playMode?: SpritePlayMode,
): void
Registers the full elevation x angle grid under baseName. See specs/2026-09-22-oriented-sprite-billboards-design.md for the full bucket-index semantics.
Parameters
baseName(string)elevationBands(Array.<Array.<Array.<integer>>>) — array of exactly numElevationBands entries; each entry is itself an angleFrames array in the same shape addOrientedAnimation takes.frameRate(integer)playMode(SpritePlayMode, optional, default: "SpritePlayMode.Loop")
Returns
void
registeredAnimationNameForTests(
baseName: string,
elevationBand: integer,
angleBucket: integer,
): string
For tests only - the underlying Sprite animation name a bucket resolves to. Mirrors Sprite's own "for tests only" accessor convention (see rawAnimationClockMsForTests()).
Parameters
baseName(string)elevationBand(integer)angleBucket(integer)
Returns
string
getOrientedAnimationsDebugInfo(): roAssociativeArray
Debug helper - like Sprite.getAnimationsDebugInfo(), but grouped by baseName and (elevationBand, angleBucket) instead of raw internal Sprite animation names (e.g. "walk_e0_a3") - much easier to check "is the SE bucket for 'walk' really pointing at the sheet region I expect" than wading through synthesized names by hand. See logOrientedAnimationsDebugInfo() to print this as JSON instead of inspecting it directly.
Returns
roAssociativeArray
logOrientedAnimationsDebugInfo(): void
Prints getOrientedAnimationsDebugInfo() as JSON via this sprite's owner Game.log().
Returns
void
computeAngleBucket(
camera: BGE.Camera,
toCamera?: BGE.Math.Vector,
): integer
Computes which of numAngles horizontal view buckets is currently visible, from the angle between this entity's facing (rotation.y) and the direction from this entity to the camera. Bucket 0 = the entity's front is facing the camera; buckets increase clockwise as viewed from above. Always 0 for a camera that isn't a Camera3d (a 2D camera has no facing/orbit concept).
Parameters
camera(BGE.Camera)toCamera(BGE.Math.Vector, optional, default: "invalid") — the vector from the camera to this entity, if already computed this frame (e.g. by update()) - avoids recomputing it when both this and computeElevationBand() are called for the same camera/frame. Computed internally fromcamerawhen omitted.
Returns
integer
computeElevationBand(
camera: BGE.Camera,
toCamera?: BGE.Math.Vector,
): integer
Computes which of numElevationBands vertical view bands is currently visible, from the camera's pitch relative to this entity - band 0 is the camera below the entity looking up at it, band numElevationBands - 1 is the camera above looking down. Always 0 if numElevationBands is 1 (no vertical distinction requested) or the camera isn't a Camera3d.
Parameters
camera(BGE.Camera)toCamera(BGE.Math.Vector, optional, default: "invalid") — the vector from the camera to this entity, if already computed this frame (e.g. by update()) - avoids recomputing it when both this and computeAngleBucket() are called for the same camera/frame. Computed internally fromcamerawhen omitted.
Returns
integer
playOrientedAnimation(baseName: string): void
Selects which base animation is currently playing, analogous to Sprite. playAnimation - but this picks among the (numElevationBands x numAngles) per-bucket animations registered for baseName via addOrientedAnimation / addElevationOrientedAnimation, resolving which one to actually play every update() from the camera's angle to this entity.
Parameters
baseName(string)
Returns
void
update(): void
Returns
void