Classes:VisualThinker
Note: This feature is for ZScript only. |
(New from 4.12)
VisualThinker (formerly ZSprite (development version 4b54aac only)) is a class dedicated to rendering special effects that can be used en masse. They serve as a middle ground between particles and Actors with notable differences.
Aside from Actors, VisualThinkers are the only Thinker class that have rendering associated with them.
Contents
Advantages
VisualThinkers share almost all the rendering features Actors do, including scaling, rolling, and billboarding/flipping options (XY or Y). They also support semi-stencil coloring without needing to be set to a stencil renderstyle that's adjustable on the fly.
Like particles, they perform no collisions or physics at all, allowing for them to be used en masse. They are not bound to a limit and do not take up particle slots and last until Destroy() is called.
Limitations
- Like actors, they cannot be created with
new
like other Thinkers, unlike actors, they are abstract. A custom inheriting class must be made.
- VisualThinkers use the mutually exclusive
STAT_SPRITE
stat and cannot be changed for performance reasons.
- Models, states, and
Default {}
blocks are not supported. Control will primarily be done via overriding Tick().
- Does not perform sprite changing based on angle to the thinker on its' own. Meaning that sprites with multiple rotations (POSSA0) don't change based on angle.
Methods
- VisualThinker level.SpawnVisualThinker (Class<VisualThinker> type)
- The most basic spawning function called from the global
level
variable. The class must inherit from VisualThinker and must not be VisualThinker itself.
Static
- static VisualThinker Spawn(Class<VisualThinker> type, TextureID tex, Vector3 pos, Vector3 vel, double alpha = 1.0, int flags = 0, double roll = 0.0, Vector2 scale = (1,1), Vector2 offset ={{{1}}}
- Calls
level.SpawnVisualThinker(type)
if a level is present. Parameters are as follows:- Class<VisualThinker> type: Name of the VisualThinker child class to spawn.
- TextureID tex: The graphic to use.
- Vector3 pos: Absolute position coordinates to spawn at.
- Vector3 vel: Absolute velocity given to the class upon spawning.
- double alpha: Defines opacity. 1.0 is fully visible/opaque, 0.0 is invisible. Default is 1.0.
- int flags: See the flags variable below. Default is 0.
- double roll: The sprite will start with this much roll applied. Default is 0.
- Vector2 scale: Sets the X (horizontal) and Y (vertical) scale. Scaling is treated exactly the same as Actor's. Default is (1,1).
- Vector2 offset: Offsets the sprite similar to Actor's
SpriteOffset
field. Positive X/Y values offset to the left/up respectively, vice versa for negative. Default is (0,0). - int style: Renderstyle. Default is STYLE_Normal.
- void SetTranslation (Name trans)
- Sets the thinker's color translation as defined in the TRNSLATE lump. Works similar to the Actor's A_SetTranslation.
- void SetRenderStyle (int mode)
- Sets the thinker's Renderstyle. Works similar to the Actor's A_SetRenderStyle.
- bool IsFrozen()
- Returns true if the map is frozen and the sprite doesn't have SPF_NOTIMEFREEZE.
Virtual
- void PostBeginPlay()
- Called after BeginPlay and before the first call to Tick. This is done before the very first state of an actor is ever reached, useful for performing one-time setups like giving local variables a value, without worrying about a monster being dormant at the start and going to Deactivate instead of Spawn.
- void Tick()
- Called every tic, 35 times a second. As the name implies, this is what makes an entity 'tick', or operate on its own.
Variables
The following variables are available for modification.
- TextureID Texture
- The image to render out. This must be valid at all times, or the thinker will be destroyed.
- Color scolor
- Stencil coloring that is applied constantly on all render styles, allowing for unique colorizing effects. Default is white ("FFFFFF" in hexadecimal).
- TranslationID Translation
- Equivalent to Actor's Translation. Changing this should primarily be done with
SetTranslation()
above, but transference can be done with simple assignments.
- Sector cursector
- The current sector this sprite is in.
- WARNING: Can be
null
. Always perform a null check when using this variable.
- Vector3 pos
- World position of the sprite.
- Vector3 prev
- Previous position of the sprite, used for interpolating between the last position it was at during the previous tick.
- Vector3 vel
- Velocity of the sprite.
- Vector2 scale
- Scale of the sprite. Scaling is identical to Actor's.
- Vector2 offset
- The offset of the sprite, identical to Actor's
SpriteOffset
variable. Positive X/Y offsets the sprite left/up respectively, and vice versa for negative values.
- double alpha
- Opacity of the sprite. 1.0 is fully opaque, 0.0 is invisible.
- int16 LightLevel
- Same variable as Actor's
LightLevel
. Defaults to -1, meaning use the sector's light. Any other number between [0, 255] overrides the sector's brightness.
- uint16 Flags
- These are the same as A_SpawnParticleEx. Those not listed here have no effect. Multiple flags can be combined with
|
:- SPF_FULLBRIGHT — Makes the sprite full bright.
- SPF_NOTIMEFREEZE — The sprite is not affected by the time freeze powerup or cheat.
- SPF_ROLL - The sprite will be rotated akin to an Actor with the +ROLLSPRITE flag.
- SPF_NO_XY_BILLBOARD - Similar to an Actor with the +FORCEYBILLBOARD flag.
- SPF_LOCAL_ANIM - Performs animations defined in ANIMDEFS independently from the start instead of based on game time. This also means the animation will pause with the game too. Has no effect if the graphic doesn't have any animations. (Pull request #2354 only)
Unless noted otherwise, these are all false by default.
- bool bXFlip
- Flips the sprite on the X axis.
- bool bYFlip
- Flips the sprite on the Y axis.
- bool bAddLightLevel
- LightLevel adds the sector's brightness to its own instead of overriding completely.
- bool bDontInterpolate
- Disables interpolation for movement and roll changes over each tick.
- bool bFlipOffsetX
- bool bFlipOffsetY
- Flips the thinkers' texture on the X and Y axes respectively. Without changing the offsets of the graphic.
ZScript definition
Note: The ZScript definition below is for reference and may be different in the current version of GZDoom.The most up-to-date version of this code can be found on GZDoom GitHub. |
Class VisualThinker : Thinker native
{
native Vector3 Pos,
Prev;
native FVector3 Vel;
native Vector2 Scale,
Offset;
native float Roll,
PrevRoll,
Alpha;
native TextureID Texture;
native TranslationID Translation;
native uint16 Flags;
native int16 LightLevel;
native bool bFlipOffsetX,
bFlipOffsetY,
bXFlip,
bYFlip,
bDontInterpolate,
bAddLightLevel;
native Color scolor;
native Sector CurSector; // can be null!
native void SetTranslation(Name trans);
native void SetRenderStyle(int mode); // see ERenderStyle
native bool IsFrozen();
static VisualThinker Spawn(Class<VisualThinker> type, TextureID tex, Vector3 pos, Vector3 vel, double alpha = 1.0, int flags = 0,
double roll = 0.0, Vector2 scale = (1,1), Vector2 offset = (0,0), int style = STYLE_Normal, TranslationID trans = 0)
{
if (!Level) return null;
let p = level.SpawnVisualThinker(type);
if (p)
{
p.Texture = tex;
p.Pos = pos;
p.Vel = vel;
p.Alpha = alpha;
p.Roll = roll;
p.Scale = scale;
p.Offset = offset;
p.SetRenderStyle(style);
p.Translation = trans;
p.Flags = flags;
}
return p;
}
}
Examples
Class emit : Actor
{
TextureID tex;
Default
{
+NOINTERACTION
+NOBLOCKMAP
+BRIGHT
Scale 0.25;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
tex = TexMan.CheckForTexture("MISLB0");
}
States
{
Spawn:
MISL A 1;
Looping:
MISL A 1
{
angle = random(0,359);
pitch = random(-90,90);
Vel3DFromAngle(random(2,6), angle, pitch);
let p = Level.SpawnVisualThinker("ZRocketBoom");
if (p)
{
p.Texture = tex;
p.pos = pos;
p.vel = vel;
p.scolor = "FF0000";
p.SetRenderStyle(STYLE_Add);
p.flags = SPF_ROLL|SPF_FULLBRIGHT;
p.roll = random(0,359);
p.alpha = 1.0;
p.Scale = (1,1);
}
vel = (0,0,0);
}
Loop;
}
}
Class ZRocketBoom : VisualThinker
{
double RollVel;
override void PostBeginPlay()
{
Super.PostBeginPlay();
RollVel = frandom(-10.0, 10.0);
Alpha = 1.0;
}
override void Tick()
{
if (bDESTROYED || IsFrozen())
return;
Super.Tick();
Roll += RollVel;
Alpha -= 0.05;
if (Alpha <= 0.0)
Destroy();
}
}
//==============================================================================
Class spri : Actor
{
Default
{
+NOINTERACTION
+NOBLOCKMAP
+INVISIBLE
Scale 0.25;
}
Array<VisualThinker> spr;
TextureID tex;
void Make(double ox, double oy, double sc = 1.0)
{
VisualThinker p = Level.SpawnVisualThinker('testoff');
if (p)
{
p.texture = tex;
p.pos = pos;
p.vel = vel;
p.Scale = Scale;
p.SetRenderStyle(STYLE_Add);
p.flags = SPF_ROLL|SPF_FULLBRIGHT;
p.roll = random(0,359);
p.Offset = (ox, oy) * sc;
spr.Push(p);
}
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
spr.Clear();
tex = TexMan.CheckForTexture("MISLB0");
double sc = 10.0;
Make(0,0);
for (int i = 1; i < 5; i++)
{
Make(i,0,sc);
// Make(-i,0,sc);
Make(0,i,sc);
// Make(0,-i,sc);
}
}
override void OnDestroy()
{
foreach (p : spr)
if (p) p.Destroy();
}
}
Class testoff : VisualThinker
{
double RollVel;
override void PostBeginPlay()
{
Super.PostBeginPlay();
RollVel = frandom(-10.0, 10.0);
}
override void Tick()
{
Roll += RollVel;
Super.Tick();
}
}