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.