Linetracer to detect dropoffs

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!

Moderator: GZDoom Developers

Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.

Please bear in mind that the people helping you do not automatically know how much you know. You may be asked to upload your project file to look at. Don't be afraid to ask questions about what things mean, but also please be patient with the people trying to help you. (And helpers, please be patient with the person you're trying to help!)
User avatar
Custodian
Posts: 55
Joined: Fri Jan 29, 2021 8:24 pm
Github ID: disasteroftheuniverse
Graphics Processor: ATI/AMD (Modern GZDoom)
Location: Minneapolis MN, USA

Linetracer to detect dropoffs

Post by Custodian »

I'm trying to make a method which can detect if an actor is able to move to another position without being blocked by a dropoff (this is really more of a stair-detector).

Pastebin Link

The script I wrote (below) does well to determine if an actor is unable to reach a position above them, but this script cannot seem to detect dropoffs. I did some debugging and found that this was only detecting steps above the calling actor, but not below it.

Do line traces not consider all lines?

It seems to simply ignore lines where the floor position is lower. I can get it to detect dropoffs when I set the starting position to be well below the map, but this is far from an ideal solution because I would like to be able to detect 3D floors as well.

Code: Select all

Class WalkTracer : LineTracer 
{
    Line lastLine; //unused right now
    Sector LastSector; //store last found sector
    double LastStepHeight; //last sector height
    vector3 HitPoint; //place where I found a ledge
    bool HitLedge; //did I find a ledge?
    actor owner; //caller
    int hitcount; //count the number of times there's an intersection
    double MaxStepHeight; //gotten from actor

    override ETraceStatus TraceCallback() 
    {
        
        sector NextSector = Results.HitSector;
        if (!NextSector) return TRACE_skip; //if sector has not changed, continue tracing

        if(NextSector != LastSector) //sector has changed
        {
            //count the number of times i encounter a new sector
            hitcount++;
            console.printf('HIT %i', hitcount);
            
            vector3 hitpos = Results.HitPos;

            //get the floor height at this point
            double NextStepHeight = NextSector.floorplane.ZatPoint(hitpos.XY);
            //difference between current and last floor height
            double stepDifference =  NextStepHeight - LastStepHeight;

            //store last sector
            LastSector = NextSector;

            //store last step height
            LastStepHeight = NextStepHeight;
            

            if ( stepDifference > MaxStepHeight ) {
                HitLedge = true;
                return TRACE_Stop;

            } else if (stepDifference < -MaxStepHeight ) {
                HitLedge = true;
                return TRACE_Stop;

            } else {
                return TRACE_skip;
            }

        } else {
            return TRACE_skip;
        }

        if(Results.HitType == TRACE_HitActor)
        {
            return TRACE_skip;
        }
        
        return TRACE_Stop;
    }

    bool TraceFrom (actor caller, vector3 start, Sector sec, vector3 direction, double maxDist, ETraceFlags traceFlags) 
    {
        self.hitcount = 0; //reset count
        self.owner = caller;   //the thing that is doing the trace
        self.MaxStepHeight = caller.MaxStepHeight; //the maximum vertical movement we consider a blocking height

        self.LastSector = sec; //record sector
        self.lastLine = null; //unused

        self.HitLedge = false; //reset hit 
        self.LastStepHeight = sec.floorplane.ZatPoint(start.XY); //get starting floor height

        return Trace (start, sec, direction, maxDist, traceFlags);
    }
}
Alternatively, if anyone has any ideas for how I can check if an actor can move from its current position to another without being blocked by a dropoff, please let me know. I've been struggling to find a good and performant solution for this. Checkblock and Checkposition and CheckMove don't really seem to follow the same rules and none yield the most desirable result.

The next best solution I could come up with was this, which feels like it's not the best way to tackle this (maybe it is? just feels crude and clunky). It's also not super reliable... it only seems to detect dropoffs about half the time, which isn't terribly useful.

Code: Select all

    
bool CheckWalk (double dist, double NextMoveAngle)
    {
        if (radius == 0) return false;
        int MaxSteps =  (dist / radius) + 1;
        bool blocked;
        for (int i = 1; i < MaxSteps; i++)
        {
            int stepdist = (radius * i) + 1;
            blocked = CheckBlock( CBF_DROPOFF | CBF_ABSOLUTEANGLE | CBF_NOACTORS, AAPTR_DEFAULT, stepdist, 0, 0, NextMoveAngle);
            if (blocked) 
            {
                return false;
            }
        }
        return true;
    }

Return to “Scripting”