Classes:VisualThinker

From ZDoom Wiki
Jump to navigation Jump to search
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.

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

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

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.
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();
	}
}

See also