Classes:LineTracer

From ZDoom Wiki
(Redirected from TraceCallback)
Jump to navigation Jump to search
Note: This feature is for ZScript only.


LineTracer is a class that allows for custom ray tracing (aka hitscan) behavior. It uses the same tracing technique that LineTrace and LineAttack use, but with some notable differences:

  • LineTracer acts similar to a projectile rather than a hitscan. This means that rather than obtaining a specific point, it actually passes through the map, reading its blockmap. This allows for custom collision logic and passing through multiple actors and geometry.
  • LineTracer is data-scoped, in contrast to LineTrace, which is play-scoped. This allows it to be instantiated from any scope, for example, firing it from a HUD to obtain some blockmap data(of course, in this case it won't be able to perform play-scoped changes, like dealing damage).

If there's no need to pass through geometry or actors, LineTrace should be used instead because it's easier to set up.

Note: LineTracer is not able to detect actors that aren't a part of the blockmap due to having the NOBLOCKMAP flag.


Setting up

Setting up a LineTracer requires several steps:

  1. First, a custom class based on LineTracer must be created. You can add custom fields to that class, as usual. Note, LineTracer is not an Actor, so it can't use Actor flags or the Default block.
  2. Override TraceCallBack() in this new class to add custom collision rules and manipulate data as necessary.
  3. To fire the LineTracer, use New() to instantiate it and Trace() to fire it.

Fields

The following fields are defined in the LineTracer class and can be read both inside its TraceCallBack call, and if you have a pointer to a LineTracer instance:

  • @TraceResults Results
A pointer to the TraceResults struct that contains information pertaining to what caused the trace to call TraceCallback.

TraceResults

A pointer to this struct is contained in the LineTracer's results field, as described above. This struct is normally read in a TraceCallBack override. Its fields can not only be read, but also modified to allow custom results. The following fields are available:

  • ETraceResult HitType
What the trace hit, if anything. Can be one of the following:
  • TRACE_HitNone
  • TRACE_HitFloor
  • TRACE_HitCeiling
  • TRACE_HitWall
  • TRACE_HitActor
  • TRACE_CrossingPortal (requires portal reporting flag in Trace to be set)
  • TRACE_HasHitSky (requires hitting sky flag in Trace to be set)
  • Sector HitSector
The sector where the trace called TraceCallback()
  • TextureID HitTexture
The texture of the surface that got hit, if any
  • Vector3 HitPos
The absolute map coordinates where the trace called TraceCallback()
  • Vector3 HitVector
The direction the trace was traveling
  • F3DFloor ffloor
The 3D floor that got hit, if any.
  • Vector3 SrcFromTarget
The starting position of the trace
  • double SrcAngleFromTarget
The angle of HitVector
  • double Distance
The distance from the starting point the trace has traveled
  • double Fraction
The fraction of the total distance the trace has traveled
  • Actor HitActor
The Actor that was hit, if any
  • Line HitLine
The Line that was hit, if any
  • uint Side
Which side of the line that was hit, if any. Can be one of the following:
  • Line.front
  • Line.back
  • uint Tier
Which part of the line was hit, if any. Can be one of the following:
  • TIER_Middle
  • TIER_Upper
  • TIER_Lower
  • TIER_FFloor (hit a line connected to a 3D floor)
  • bool unlinked
True if the trace passed through a portal that was not linked
  • Sector CrossedWater
The sector the trace hit that contained Boom-style deep water, if any
  • Vector3 CrossedWaterPos
The absolute map coordinates where the trace hit CrossedWater
  • Sector Crossed3DWater
The sector the trace hit that contained 3D floor-style deep water, if any
  • Vector3 Crossed3DWaterPos
The absolute map coordinates where the trace hit Crossed3DWater

Methods

Non-static

bool Trace(vector3 start, Sector sec, vector3 direction, double maxDist, ETraceFlags traceFlags, uint wallMask = 0xFFFFFFFF, bool ignoreAllActors = false, Actor ignore = null)

This is the primary method for spawning and "firing" a LineTracer. Once you've instantiated a LineTracer with New, this function can be called on a pointer to the LineTracer to launch it. The function has the following parameters:

  • vector3 start - The starting location of the trace. This is an absolute map coordinate
  • Sector sec - The sector that the trace is starting from. If LineTracer is meant to be "fired" from an actor, pass that actor's cursector field here.
  • vector3 direction - A 3D vector that points in the direction the trace should start traveling
  • double maxDist - How far the trace should travel before it terminates. Use PLAYERMISSILERANGE for player's standard hitscan distance (4096 units).
  • ETraceFlags traceFlags - Modifies the behavior of the trace. The following flags are available:
  • TRACE_NoSky - Hitting the sky sets the HitType to TRACE_HitNone
  • TRACE_PortalRestrict - Cannot travel through portals that are not linked
  • TRACE_ReportPortals - Update Results to accurately reflect traveling through a portal. TraceCallback is called with a HitType of TRACE_CrossingPortal when traveling through one
  • TRACE_HitSky - Hitting the sky sets the HitType to TRACE_HasHitSky

Extra arguments were added in GZDoom 4.12:

  • uint wallMask — This field accepts Line flags. If the default value (0xFFFFFFFF) is used, results.HitType will be set to TRACE_HitWall each time LineTracer crosses *any* line (including non-blocking sector boundaries). Otherwise, only lines with the provided flags will set it to TRACE_HitWall. Pass 0 if you only want to detect one-sided lines and exclude everything else.
  • bool ignoreAllActors — If true, all actors will set HitType to TRACE_HitNone.
  • Actor ignore — A pointer to an actor that will be ignored by the LineTracer.

Return value: returns true if LineTracer's results.HitType is not TRACE_HitNone. Returns false otherwise.

Note: this function only returns a bool, which is not the same as the return value of TraceCallBack. The latter's return value must be read with <pointer to LineTracer>.results.HitType.

Virtual

ETraceStatus TraceCallback()

This is called during a trace when any Actor in the blockmap is hit, any line is hit, or any plane is hit. This can also be called when crossing portals if set to do so. Custom logic handling for what happens when something is hit happens in this function. Generally Results' HitType is looked at to determine what should be examined in the results.

Return value: returns the status of the trace. The function can be overridden to set the return value manually after passing custom conditions. The status is used to determine whether to keep going or terminate the trace at that spot. Can be one of the following values:

  • TRACE_Stop - Terminates the trace at its current spot, returning the results from the current hit
  • TRACE_Continue - Tells the trace to keep going. If nothing else is hit along the way, the results from the current hit will be returned
  • TRACE_Skip - Similar to TRACE_Continue but will not return the results from the current hit
  • TRACE_Abort - Similar to TRACE_Stop but will not return the results from the current hit

Note: if not overridden, this function returns TRACE_Stop by default, causing it to stop at the first collision.

Examples

// This is meant to be a custom Weapon function that instantiates a custom LineTracer:
action void A_FindGhosts()
{
    // Create the tracer
    let tracer = new('GhostFinder');
    if (!tracer)
    {
        return;
    }

    // Get the current direction the player is looking
    Vector3 dir = (AngleToVector(angle, cos(pitch)), -sin(pitch));

    // Set the starting point to the player's eye level:
    Vector3 start = (pos.xy, player.viewz);

    tracer.Trace(start, CurSector, dir, PLAYERMISSILERANGE, 0);
    if (tracer.bHitGhost)
    {
        console.printf("Ahhh! A spooky ghost!");
    }
}

// This is our custom LineTracer:
class GhostFinder : LineTracer
{
    bool bHitGhost; //custom flag

    // This is where we'll examine the results to check for ghosts
    override ETraceStatus TraceCallback()
    {
        // Check if we hit an actor. If so, does it have the ghost flag?
        if (results.HitType == TRACE_HitActor && results.HitActor.bGhost)
        {
            bHitGhost = true;

            // Tell the trace to terminate
            return TRACE_Stop;
        }

        // If we didn't hit an actor or it doesn't have the ghost flag, ignore it and keep going
        return TRACE_Skip;
    }
}

See also