I search for solutions in this order: Past Code, Unreal Source, Wiki, BUF, groups.yahoo, google, screaming at monitor. – RegularX
Legacy:Hitscan Weapons
Work in progress!
This page is currently being created by computergod666. You are free to add helpful content in any way if you want.
Before reading this tutorial
This tutorial assumes that you have already read the first tutorial, Basic weapon class. If you haven't, it provides an analysis of the Fire and AltFire functions, animation, sound, and firing projectiles using TournamentWeapon.
Projectiles vs. Hitscans
When I first started scripting, I assumed that the ProjectileClass default property specified the kind of projectile that was fired, and that this was true for every UT weapon. So when I looked at the ShockRifle code, I was surprised to find that the ProjectileClass was the same as the AltProjectileClass! Everyone knows that the shock beam is not the same as the plasma grenade, so I went looking for an equivalent for ages. I was additionally confused by the absence of a ProjectileFire call in the ShockRifle code.
The mystery was explained by the TraceFire function. The Shock Rifle primary fire is an instant-hit attack instead of a projectile. Basically, a hitscan calculates a line between the player or bot who fired the weapon, finds the first actor that is in the way, and does whatever is supposed to happen when you shoot someone with it. For the Shock Rifle, it spawns a ShockBeam effect to make it look like there's a laser beam between the target and the player, it deals damage to the target, and spawns a ring explosion effect wherever the beam hits.
Analysis of a typical TournamentWeapon hitscan call
In the TournamentWeapon class, the Fire and AltFire functions support firing either a hitscan attack or a projectile, depending on how the variable bInstantHit is set:
function Fire( float Value ) { if ( (AmmoType == None) && (AmmoName != None) ) { // ammocheck GiveAmmo(Pawn(Owner)); } if ( AmmoType.UseAmmo(1) ) { GotoState('NormalFire'); bPointing=True; bCanClientFire = true; ClientFire(Value); if ( bRapidFire || (FiringSpeed > 0) ) Pawn(Owner).PlayRecoil(FiringSpeed); if ( bInstantHit ) TraceFire(0.0); else ProjectileFire(ProjectileClass, ProjectileSpeed, bWarnTarget); } }
If bInstantHit is true, the Fire function will call the TraceFire() function. If it is false, it will attempt to fire the ProjectileClass. Let's focus on TraceFire for now.
TraceFire() takes a single argument, which specifies the accuracy of the attack. Lower numbers mean higher accuracy. The following is a sample of the TraceFire code:
function TraceFire( float Accuracy ) { local vector HitLocation, HitNormal, StartTrace, EndTrace, X,Y,Z; local Actor Other; //Make sure that bots hear the weapon firing. Owner.MakeNoise(Pawn(Owner).SoundDampening); //Get three vectors corresponding to the player's axes: // X points forward, Y points right, and Z points up. GetAxes(Pawn(Owner).ViewRotation,X,Y,Z); //Calculate the coordinates for the beginning and end of the trace. StartTrace = Owner.Location + CalcDrawOffset() + FireOffset.Y * Y + FireOffset.Z * Z; EndTrace = StartTrace + Accuracy * (FRand() - 0.5 )* Y * 1000 + Accuracy * (FRand() - 0.5 ) * Z * 1000 ; //Adjust aim for bots. AdjustedAim = pawn(Owner).AdjustAim(1000000, StartTrace, 2.75*AimError, False, False); EndTrace += (10000 * vector(AdjustedAim)); //Do the actual tracing! Other = Pawn(Owner).TraceShot(HitLocation,HitNormal,EndTrace,StartTrace); ProcessTraceHit(Other, HitLocation, HitNormal, vector(AdjustedAim),Y,Z); }
This function only does the tracing. Then, it calls ProcessTraceHit() to do damage and effects.
WORK IN PROGRESS