|
Turret Pt. 2
Mod Code : ca Mod Text : ca
12
November 1998
Download
the Mod
//=============================================================================
// Turret - How to make a simple player-controlled Turret
//
// Part 2:
//
// In Part 2 we add the ability to make our Turret Fire, either
// a chosen projectile, or just regular bullets. Also modify
// the way the Turret is controlled a little bit so that it can
// be rotated using the mouse. The majority of the code is the
// same as in Part 1, except for a few new functions/states.
//
// -ca
// ca@planetunreal.com
//
//=============================================================================
//=============================================================================
// Turret
//
// In this class we need to basically add a new state and 2 new functions.
// The Fire() function just sends the Turret into the Firing state, where
// the function FireShot() either spawns a projectile or does a bullet trace.
// Most of this code is based on the same setup as normal Unreal weapons,
// albeit there are a few differences.
//=============================================================================
class Turret expands Actor;
var() float MaxYaw, MaxPitch, YawRate, PitchRate, FireRate;
// TurretDamage determines the amount of damage done when bInstantHit is set to true.
// TurretHeight has been implemented to automatically place the Turret a certain distance
// above the ground. This allows for mappers to create different "bases" for the Turret
// to sit upon.
var() int TurretDamage, TurretHeight;
// FireOffset is used to determine the spawning location of fired projectiles.
var() vector FireOffset;
// bInstantHit tells the Turret whether to simulate a bullet-firing sequence similiar to
// the way the automag/rifle works. If bInstantHit is false, then the Turret will fire
// whatever projectile determined by ProjClass.
var() bool bInstantHit;
var() class ProjClass;
var rotator CurRot, InitialRot;
var Pawn User;
function PreBeginPlay()
{
local vector HitLocation, HitNormal, newLoc;
local actor other;
InitialRot = Rotation;
CurRot.Yaw = 0;
CurRot.Pitch = 0;
// This is the code to set the Turret above the ground.
// It performs a trace down (relative to the Turret) and then
// sets the gun TurretHeight above whatever it hits.
Trace(HitLocation, HitNormal, vect(0,0,-1) * 1000, Location);
if (HitLocation.Z != 0)
{
newLoc = Location;
newLoc.Z = HitLocation.Z + TurretHeight;
setLocation(newLoc);
}
}
// Fire() is used to send the Turret into a firing sequence. This is also a good
// place to call any animations/sound functions for Turrets more detailed than this
// one..:)
function Fire()
{
GotoState('Firing');
}
// Nothing has changed in either YawTurret or PitchTurret.
function YawTurret(int Sign)
{
local rotator newRot;
CurRot.Yaw += YawRate * 1024 * Sign;
if (CurRot.Yaw > MaxYaw)
CurRot.Yaw = MaxYaw;
else if (CurRot.Yaw <-maxyaw) CurRot.Yaw="-MaxYaw;" newRot="InitialRot;" newRot +="CurRot;" SetRotation(newRot); } function PitchTurret(int Sign) { local rotator newRot; CurRot.Pitch +="PitchRate" * 1024 * Sign; if (CurRot.Pitch> MaxPitch)
CurRot.Pitch = MaxPitch;
else if (CurRot.Pitch <-maxpitch) CurRot.Pitch="-MaxPitch;" newRot="InitialRot;" newRot +="CurRot;" SetRotation(newRot); } auto state Idle { Begin: }
// The Firing state is the where the good stuff happens. When we are first put into this state
// the Turret fires a shot, then sleeps for FireRate (in seconds). After that if the Turret
// still has a User and the User is no longer pressing the fire button (bFire == 0), then go
// back to the Idle state, else loop the whole sequence again.
state Firing
{
// FireShot functions two different ways depending on whether bInstantHit == true.
// If bInstantHit == true, then the Turret traces a line in the direction it is
// facing (EndTrace), and if it finds a Pawn then it damages the pawn, else it
// makes a little smokepuff.
//
// if bInstantHit == false, then the Turret spawns a projectile starting from the
// Turret's Location, plus FireOffset. By setting ProjClass in the default
// properties to any projectile, the Turret can be used for any type of flying
// death that you can imagine (er code).
function FireShot()
{
local vector HitLocation, HitNormal, StartTrace, EndTrace, X,Y,Z;
local actor Other;
if (bInstantHit)
{
GetAxes(Rotation,X,Y,Z);
StartTrace = Location + FireOffset;
EndTrace = StartTrace + vector(Rotation) * FRand() * 5000;
Other = Trace(HitLocation,HitNormal,EndTrace,StartTrace);
if (Other.IsA('Pawn'))
Other.TakeDamage(TurretDamage, User, HitLocation, 3000.0*X, 'shot');
else if (Other != none)
spawn(class'SpriteSmokePuff',,,HitLocation+HitNormal*9);
}
else if (ProjClass != none)
{
GetAxes(Rotation, X, Y, Z);
spawn(ProjClass,,,Location + FireOffset, rotator( Location + FireOffset + X * 5000 + vector(Rotation) * 10000));
}
}
Begin:
// Firing is just an easy way to keep looping inside the Firing state.
Firing:
FireShot();
Sleep(FireRate);
if (PlayerPawn(user) != none)
if (User.bFire == 0)
GotoState('Idle');
Goto('Firing');
}
defaultproperties
{
MaxYaw=12192.000000
maxPitch=12192.000000
YawRate=0.400000
PitchRate=0.400000
FireRate=0.600000
TurretDamage=15
ProjClass=Class'UnrealI.Rocket'
DrawType=DT_Mesh
Mesh=Mesh'UnrealI.QuadShotHeld'
DrawScale=1.500000
bCollideActors=True
bCollideWorld=True
bBlockActors=True
bBlockPlayers=True
}
//=============================================================================
// End Turret
//=============================================================================
//=============================================================================
// TurretMaleOne
//
// The major changes we need to make in our Player class is to override the
// Fire function so that the Turret fires instead of the current weapon, also
// we need to make a few minor changes in ActivateItem() to let the Turret
// know who is using it, so that it can know when to stop firing.
//=============================================================================
class TurretMaleOne expands MaleOne;
var bool bUsingTurret;
var Turret TGun;
// Only need to check if we're using a Turret, if so then Fire the Turret and
// not the weapon.
exec function Fire( optional float F )
{
if( bShowMenu || Level.Pauser!="" )
return;
if (bUsingTurret && TGun != none)
{
TGun.Fire();
}
else if( Weapon!=None )
{
Weapon.bPointing = true;
Weapon.Fire(F);
PlayFiring();
}
}
// The only major change needed here is TGun.User = self, that way the Turret
// has a reference of us to check to see if bFire == 0, ie whether or not
// we still want to Fire the gun.
exec function ActivateItem()
{
local actor a;
if (!bUsingTurret)
{
log("ActivateItem(): !bUsingTurret");
foreach RadiusActors(class'Actor', a, 150)
if (a.IsA('Turret'))
{
bUsingTurret = true;
TGun = Turret(a);
TGun.User = self;
log("ActivateItem(): !bUsingTurret: a.IsA('Turret')");
}
}
else
{
bUsingTurret = false;
TGun.User = none;
TGun.GotoState('Idle');
TGun.setRotation(TGun.InitialRot);
TGun = none;
}
if( bShowMenu || Level.Pauser!="" )
return;
if (SelectedItem!=None)
SelectedItem.Activate();
}
// PlayerInput has been completely changed now to incorporate the Mouse into
// the rotation of the Turret. Instead of relying on aBaseX and aBaseY for
// movement, we use aForward and aLookUp for pitching the Turret, and aTurn
// and aStrafe for yawing the Turret.
event PlayerInput( float DeltaTime )
{
local float SmoothTime, MouseScale;
if ( bShowMenu && (myHud != None) )
{
if ( myHud.MainMenu != None )
myHud.MainMenu.MenuTick( DeltaTime );
// clear inputs
bEdgeForward = false;
bEdgeBack = false;
bEdgeLeft = false;
bEdgeRight = false;
bWasForward = false;
bWasBack = false;
bWasLeft = false;
bWasRight = false;
aStrafe = 0;
aTurn = 0;
aForward = 0;
aLookUp = 0;
return;
}
else if ( bDelayedCommand )
{
bDelayedCommand = false;
ConsoleCommand(DelayedCommand);
}
// Check for Dodge move
// flag transitions
bEdgeForward = (bWasForward ^^ (aBaseY > 0));
bEdgeBack = (bWasBack ^^ (aBaseY <0)); bEdgeLeft="(bWasLeft" ^^ (aStrafe> 0));
bEdgeRight = (bWasRight ^^ (aStrafe <0)); bWasForward="(aBaseY"> 0);
bWasBack = (aBaseY <0); bWasLeft="(aStrafe"> 0);
bWasRight = (aStrafe <0); if (aLookUp !="0)" bKeyboardLook="true;" if (bSnapLevel !="0)" bKeyboardLook="false;"
// Smooth and amplify mouse movement
SmoothTime = FMin(0.2, 3 * DeltaTime);
MouseScale = MouseSensitivity * DesiredFOV * 0.0111;
aMouseX = aMouseX * MouseScale;
aMouseY = aMouseY * MouseScale;
if ( (SmoothMouseX == 0) || (aMouseX == 0)
|| ((SmoothMouseX > 0) != (aMouseX > 0)) )
SmoothMouseX = aMouseX;
else if ( (SmoothMouseX <0.85 * aMouseX) || (SmoothMouseX> 1.17 * aMouseX) )
SmoothMouseX = 5 * SmoothTime * aMouseX + (1 - 5 * SmoothTime) * SmoothMouseX;
else
SmoothMouseX = SmoothTime * aMouseX + (1 - SmoothTime) * SmoothMouseX;
if ( (SmoothMouseY == 0) || (aMouseY == 0)
|| ((SmoothMouseY > 0) != (aMouseY > 0)) )
SmoothMouseY = aMouseY;
else if ( (SmoothMouseY <0.85 * aMouseY) || (SmoothMouseY> 1.17 * aMouseY) )
SmoothMouseY = 5 * SmoothTime * aMouseY + (1 - 5 * SmoothTime) * SmoothMouseY;
else
SmoothMouseY = SmoothTime * aMouseY + (1 - SmoothTime) * SmoothMouseY;
aMouseX = 0;
aMouseY = 0;
// Remap raw x-axis movement.
if( bStrafe!=0 )
{
// Strafe.
aStrafe += aBaseX + SmoothMouseX;
aBaseX = 0;
}
else
{
// Forward.
aTurn += aBaseX + SmoothMouseX;
aBaseX = 0;
}
// Remap mouse y-axis movement.
if( bAlwaysMouseLook || (bLook!=0) )
{
// Look up/down.
bKeyboardLook = false;
if ( bInvertMouse )
aLookUp -= SmoothMouseY;
else
aLookUp += SmoothMouseY;
}
else
{
// Move forward/backward.
aForward += SmoothMouseY;
}
// Remap other y-axis movement.
aForward += aBaseY;
aBaseY = 0;
// Here is the change, basically we use aForward, aLookUp, aStrafe, and aTurn
// because the rest of the code has already calculated both normal key movement
// (aBaseX, aBaseY) and mouse movement. Other than that we still rotate
// the Turret as before.
if (bUsingTurret && TGun != none)
{
if (aForward > 0 || aLookUp > 0)
TGun.PitchTurret(-1);
else if (aForward <0 || aLookUp < 0) TGun.PitchTurret(1); if (aStrafe> 0 || aTurn > 0)
TGun.YawTurret(1);
else if (aStrafe <0 || aTurn < 0) TGun.YawTurret(-1);
// clear inputs
bEdgeForward = false;
bEdgeBack = false;
bEdgeLeft = false;
bEdgeRight = false;
bWasForward = false;
bWasBack = false;
bWasLeft = false;
bWasRight = false;
aStrafe = 0;
aTurn = 0;
aForward = 0;
aLookUp = 0;
return;
}
// Handle walking.
HandleWalking();
}
// No change to UpdateRotation
function UpdateRotation(float DeltaTime, float maxPitch)
{
local rotator newRotation;
local vector X,Y,Z, newLoc;
DesiredRotation = ViewRotation; //save old rotation
ViewRotation.Pitch += 32.0 * DeltaTime * aLookUp;
ViewRotation.Pitch = ViewRotation.Pitch & 65535;
If ((ViewRotation.Pitch > 18000) && (ViewRotation.Pitch <49152)) { If (aLookUp> 0)
ViewRotation.Pitch = 18000;
else
ViewRotation.Pitch = 49152;
}
ViewRotation.Yaw += 32.0 * DeltaTime * aTurn;
ViewShake(deltaTime);
ViewFlash(deltaTime);
newRotation = Rotation;
newRotation.Yaw = ViewRotation.Yaw;
newRotation.Pitch = ViewRotation.Pitch;
If ( (newRotation.Pitch > maxPitch * RotationRate.Pitch) && (newRotation.Pitch <65536 maxPitch * RotationRate.Pitch) ) { If (ViewRotation.Pitch < 32768) newRotation.Pitch="maxPitch" * RotationRate.Pitch; else newRotation.Pitch="65536" maxPitch * RotationRate.Pitch; } if (bUsingTurret && TGun !="none)" { newRotation="TGun.Rotation;" GetAxes(newRotation, X,Y,Z); newLoc="TGun.Location" + X * 50; newLoc.Z="Location.Z;" SetLocation(newLoc); ViewRotation="newRotation;" } setRotation(newRotation); } defaultproperties { }
//=============================================================================
// End TurretMaleOne
//=============================================================================
//=============================================================================
// So now the Turret is able to fire, and it has learned how to use the
// mouse to determine rotation. There are definitely some areas where
// this Turret could be improved (but thats what coders are for:). I hope
// this helps you with a starting base to make all of your wonderous (and
// destructive) Turret creations. Good luck!
//
// -ca
// ca@planetunreal.com
//=============================================================================
Opinions on this article, love it, hate it? - feedback |