I love the smell of UnrealEd crashing in the morning. – tarquin

Legacy:One Way Volume

From Unreal Wiki, The Unreal Engine Documentation Site
Jump to: navigation, search

This is a two actor system I coded last night that only allows players to pass through it in one direction.

class OneWayPhysicsVolume extends PhysicsVolume;
 
// Volume to handle adding and removing players from the affected array.
 
var array<Pawn> MyPawns;
var array<vector> MyLocs;
var() bool bAffectsRed, bAffectsBlue;  // For team games.
 
simulated event PawnEnteredVolume(Pawn Other)
{
    local int i;
 
    if(Level.Game.bTeamGame && ((Other.GetTeamNum() == 0 && !bAffectsRed) || (Other.GetTeamNum() == 1 && !bAffectsBlue)))
        return;
 
    for(i=0; i<MyPawns.Length; i++)
    {
        if (MyPawns[i] == Other)
            return; // Make sure this pawn isn't already in the array.
        if (MyPawns[i] == None) {
            // remove empty slot
            MyPawns.Remove(i, 1);
            MyLocs.Remove(i, 1);
            i--;
        }
    }
 
    MyPawns[i] = Other;
    MyLocs[i] = Other.Location;
}
 
event PawnLeavingVolume(Pawn Other)
{
    local int m;
 
    for(m = MyPawns.Length - 1; m >= 0; m--)
    {
        if (MyPawns[m] == Other ||MyPawns[j] == None)
        {
            MyPawns.Remove(m, 1);
            MyLocs.Remove(m, 1);
        }
    }
}
 
DefaultProperties
{
    bAffectsRed=true
    bAffectsBlue=true
}

Then the actor that actually handles the movement:

class OneWayChecker extends Actor
    placeable;
 
var() edfindable OneWayPhysicsVolume MyVolume;
var float ObjectAngle;
 
function Tick(float DT)
{
    local int k;
    local rotator R;
    local vector B, NewLoc;
 
    if(MyVolume == none)
    {
        Destroy();
        return; // If there's no volume assigned, destroy this actor.
    }
 
    for(k=0; k<MyVolume.MyPawns.Length; k++)
    {
        if(MyVolume.MyPawns[k] != None)
        {
            // Find out the angle between this actor's rotation and
            // the rotator of the player's last and current position.
            // I know this next line could be optimized by not using acos.  :)
            if(acos(Normal(vector(Rotation)) dot Normal(MyVolume.MyLocs[k] - MyVolume.MyPawns[k].Location)) < ObjectAngle)
            {
                // Find the rotator perpendicular with this actor.
                R.Yaw = Rotation.Yaw + 16384;
                // Find a point along that rotator.
                B = MyVolume.MyLocs[k] + vector(R);
                // Find the point where the player's location intersects
                // perpendicularly with the line between those vectors.
                NewLoc = MyVolume.MyLocs[k] + Normal( B - MyVolume.MyLocs[k] ) * ((( B - MyVolume.MyLocs[k] )
                    dot ( MyVolume.MyPawns[k].Location - MyVolume.MyLocs[k] )) / VSize( MyVolume.MyLocs[k] - B ));
                // Keep the player's Z axis position.
                NewLoc.Z = MyVolume.MyPawns[k].Location.Z;
                // Move the pawn to this new position.
                MyVolume.MyPawns[k].SetLocation(NewLoc);
            }
        }
    }
}
 
DefaultProperties
{
    bDirectional=True
    bHidden=True
    ObjectAngle=1.5
}

Set up in the editor, it looks like this:

[[Image:Legacy_AngelMapperOneWayVolume.jpeg|]]

The direction of the checker's arrow indicates where the player will be able to walk. Trying to go against this arrow will stop the player.