news about forums links tools tutorials contact

Melee Weapon - author: Mr.Self-Destruct
Melee Weapons The scope of this tutorial is to provide an overview to the various techniques which can be used to locate target(s) for a melee weapon, demonstrate their usage and discuss the disadvantages of each technique. Also, the assumption is that you are familiar enough with UnrealScript to be able to create your own weapons, (if you aren't go read one of the tutorials on Chimeric).

TraceShot
The TraceShot function lets us trace along a line in 3D space to see whether it intersects an object. This approach is used by all "instant hit" weapons and the chain saw in Unreal Tournament, and happens to be the simplest method.

`actor TraceShot( out vector HitLoc, out vector HitNorm, vector End, vector Start );` Returns the first actor touched by the line traced from the Start point to the End point. HitLoc is set to the hit location and HitNorm is set to an outward-pointing hit normal.

Because it is only possible to "hit" one target this makes it unsuitable for weapons where you'd like to be able to hit several things at once, also it requires a high degree of accuracy on the users part.

Below is a demonstration of using TraceShot:

    // This code assumes it's part of a Weapon class
    function MeleeTargetting()
    {
      local vector HitLoc, HitNorm, End, X, Y, Z, Start;
      local actor Other;

      // Get vectors for where the player is aiming on each axis
      GetAxes(Pawn(Owner).ViewRotation, X, Y, Z);
      // Calculate starting location
      Start = Owner.Location + CalcDrawOffset() + FireOffset.X * X
              + FireOffset.Y * Y + FireOffset.Z * Z;
      AdjustedAim = Pawn(Owner).AdjustAim(1000000, Start, AimError, False, False);
      // Using an arbitrary range of 100 UUs
      End = Owner.Location + (100 * vector(AdjustedAim));
      Other = Pawn(Owner).TraceShot(HitLoc, HitNorm, End, Start);
      // Insert code to deal damage, spawn effects etc. here
    }

TraceActors
To directly quote the UnrealScript Language Reference:

`TraceActors( class BaseClass, out actor Actor, out vector HitLoc, out vector HitNorm, vector End, optional vector Start, option vector Extent );` Iterates through all actors which touch a line traced from the Start point to the End point, using a box of collision extent Extent. On each iteration HitLoc is set to the hit location and HitNorm is set to an outward-pointing hit normal.

So we have the capability to check what intersects a definable cuboid:

    // This code assumes it's part of a Weapon class
    function MeleeTargetting()
    {
      local vector HitLoc, HitNorm, End, X, Y, Z, Start;
      local actor Other;

      // Get vectors for where the player is aiming on each axis
      GetAxes(Pawn(Owner).ViewRotation, X, Y, Z);
      // Calculate starting location
      Start = Owner.Location + CalcDrawOffset() + FireOffset.X * X
              + FireOffset.Y * Y + FireOffset.Z * Z;
      AdjustedAim = Pawn(Owner).AdjustAim(1000000, Start, AimError, False, False);
      // Using an arbitrary range of 100 UUs
      End = Owner.Location + (100 * vector(AdjustedAim));
      // Using TraceActors and a 10x10x10 cube for the extents
      foreach TraceActors(class'Actor', Other, HitLoc, HitNorm,
             End, Start, vect(10.0, 10.0, 10.0)
      {
        // Insert code to deal damage, spawn effects etc. here
      }
    }

Of the three techniques in this tutorial, I would have to say that I feel TraceActors is the best one. The main limitation is that the Extent can only be a cuboid, and for example you may want to use an arc.

VisibleActors & Dot Product
Again quoting the UnrealScript Language Reference:

`VisibleActors( class BaseClas, out actor Actor, optional float Radius, optional vector Loc );` Iterates through a list of all actors who are visible to the specified location (or if no location is specified, this actor's location).

VisibleActors will iterate through a list of all visible actors within a specified radius, but we only want to deal actors who're within a specific area in front of the player. So we use dot product to calculate the angle between where the player is aiming and where each actor is located. Effectively we can filter out all actors apart from those who lie in a definable arc in front of the player:

    // This code assumes it's part of a Weapon class
    function MeleeTargetting()
    {
      local vector HitLoc, HitNorm, End, X, Y, Z, Start;
      local actor Other;

      // Get vectors for where the player is aiming on each axis
      GetAxes(Pawn(Owner).ViewRotation, X, Y, Z);
      // Iterate through all actors within 100 UUs of the player
      foreach VisibleActors(class'Actor', Other, 100.0, Owner.Location)
      {
        // Only deal with actor's within the ~45 degrees in front of the player
        if (normal(X) dot normal(Other.Location - Owner.Location) >= 0.7)
        {
          // Calculate the hit location
          HitLoc = Other.Location + (Other.Location - Owner.Location)
                   * Other.CollisionRadius;
          // Insert code to deal damage, spawn effects etc. here
        }
      }
    }

VisibleActors & Dot Product is the most complicated technique of the three and has a distinct disadvantage. The problem is that `HitLoc.Z` always equals `Other.Location.Z`, so it's impossible to have head shot detection. The main benefit of this technique is that it affects an arc, as would sweeping a great big axe in front of you.