Following one from parts 1 and 2 of this section, I have implemented the trace functions to measure changes in elevation in front of the player and to adjust the aim.

In the RetroShooterPlayerController class I have created a new function that takes care of this calculation. This new function, WeaponYaw is called just before the Pawn.FaceRotation line in the playerwalking state.

class RetroShooterPlayerController extends GamePlayerController; var Rotator playerRot; <span style="color: #ff0000;">var int aimRot;</span> state PlayerWalking { ignores SeePlayer, HearNoise, Bump; function ProcessMove(float DeltaTime, vector NewAccel, eDoubleClickDir DoubleClickMove, rotator DeltaRot) { local Vector tempAccel; local Rotator CameraRotationYawOnly; local bool moving, rotating; if( Pawn == None ) { return; } moving = false; rotating = false; if(PlayerInput.aStrafe !=0.0 || PlayerInput.aForward !=0.0) moving = true; if(PlayerInput.aLookup !=0.0 || PlayerInput.aTurn !=0.0) rotating = true; tempAccel.Y = PlayerInput.aStrafe * DeltaTime * 100; tempAccel.X = PlayerInput.aForward * DeltaTime * 100; CameraRotationYawOnly.Yaw = 8192;//Yaw, Roll and Pitch are measured from 0 to 65536 tempAccel = tempAccel>>CameraRotationYawOnly; //transform the input by the camera World orientation so that it's in World frame Pawn.Acceleration = tempAccel; if(!rotating && moving) { playerRot.yaw = ((Atan2(PlayerInput.aForward,PlayerInput.aStrafe))+3.1416)*-10430.35; playerRot.Yaw-=8191; }else{ if(rotating) { playerRot.yaw = ((Atan2(PlayerInput.aLookUp,PlayerInput.aTurn))+3.1416)*-10430.35; playerRot.Yaw-=8191; } } <span style="color: #ff0000;">WeaponYaw(); //new code</span> Pawn.FaceRotation(playerRot,DeltaTime); CheckJumpOrDuck(); } } function UpdateRotation( float DeltaTime ) { } <span style="color: #ff0000;">function WeaponYaw() { local vector infBeam, norm, norm2, infEnd, playerLoc, playerLoc2, downStart, downTrace, downEnd; local TraceHitInfo hitInfo, hitInfo2; local Rotator pawnView; local float heightDiff, dist; playerLoc=Pawn.Location; // Player location playerLoc2=Pawn.Location; playerLoc.Z+=25.35+18; // Offset location to gun height pawnView = Pawn.Rotation; // direction the player is facing downStart = playerLoc + normal(vector(pawnView))*(72+18); // point 72 units in front of pawn infEnd = playerLoc2 + normal(vector(pawnView))*32768; // point 32768 units in front of pawn downEnd =downStart; downEnd.Z-=1000; trace(infBeam, norm, infEnd, playerLoc2, true,, hitInfo); // trace from player location to to infinte point in front of player trace(downTrace, norm2, downEnd, downStart, true,, hitInfo2); // trace from point 72 units in front of player to infinite point downwards. DrawDebugLine (playerLoc, infEnd, 0,255,0,false); // draw line from player to infinite point in front. DrawDebugSphere (infBeam, 20, 8, 255, 0, 0, false); // draw sphere to indicate where beam intersects with object. DrawDebugSphere (downStart, 16, 8, 0, 0, 255, false); // darw sphere 72 units in front of pawn DrawDebugSphere (downTrace, 16, 8, 255, 0, 255, false); // draw sphere at ground intersection 72 units in front of pawn. heightDiff = downStart.Z - downTrace.Z; aimRot = ((Atan2(heightDiff,(72+18))/Pi*180)-45)*182.04;//*10430.35; dist = Sqrt(((playerLoc2.X-infBeam.X)*(playerLoc2.X-infBeam.X))+((playerLoc2.Y-infBeam.Y)*(playerLoc2.Y-infBeam.Y)))+((playerLoc2.Z-infBeam.Z)+(playerLoc2.Z-infBeam.Z)); if(dist<90) { aimRot = 0; } } </span> DefaultProperties { CameraClass=class'RetroShooter.RetroIsoCamera'; } simulated event PostBeginPlay() { super.PostBeginPlay(); `Log("I am alive"); }

So what does this all do?

playerLoc=Pawn.Location; // Player location playerLoc2=Pawn.Location; playerLoc.Z+=25.35+18; // Offset location to gun height pawnView = Pawn.Rotation; // direction the player is facing

The variable playerLoc2 is a vector which stores the players location, this point is dead centre (around the hips of the pawn). playerLoc is the same point but then offset 43.25 units higher, around the eyes. pawnView is the current rotation or the direction of the pawn.

downStart = playerLoc + normal(vector(pawnView))*(72+18); infEnd = playerLoc2 + normal(vector(pawnView))*32768;

downStart is another vector that is used to identify a point from the playerLoc but 90 units in the direction of the pawnView. infEnd is similar, but a point extremely far infront of the pawn, but at waist hight.

downEnd =downStart; downEnd.Z-=1000;

downEnd is a vector 1000 units directly beneath downStart. They will serve as the start and end points for the second trace to indicate the height.

trace(infBeam, norm, infEnd, playerLoc2, true,, hitInfo); trace(downTrace, norm2, downEnd, downStart, true,, hitInfo2);

The first line runs a trace from playLoc2(The waist of the pawn) to infEnd, way in front of the player and stores the collision point of the trace as infBeam.

The second line runs a trace from downStart to downEnd to find a point in the ground 90 units directly infront of the pawn. Check the video for this. The downStart is indicated by the blue sphere and the collision point is shown with the purple sphere.

DrawDebugLine (playerLoc, infEnd, 0,255,0,false); // draw line from player to infinite point in front. DrawDebugSphere (infBeam, 20, 8, 255, 0, 0, false); // draw sphere to indicate where beam intersects with object. DrawDebugSphere (downStart, 16, 8, 0, 0, 255, false); // darw sphere 72 units in front of pawn DrawDebugSphere (downTrace, 16, 8, 255, 0, 255, false); // draw sphere at ground intersection 72 units in front of pawn.

These lines draw Debug points for the line of sight from the pawns eyes, a sphere to indicate where the collision point directly infront of the player, the point 90 units in front of the players eyes and the point directly beneath the last point where the trace intersects with the ground.

heightDiff = downStart.Z - downTrace.Z;

heightdiff takes the Z values of the downStart (Blue sphere) and subtracts downTrace.Z (Purple Sphere) to find the elevation of the ground 90 units ahead of the player.

aimRot = ((Atan2(heightDiff,(72+18))/Pi*180)-45)*182.04;

aimRot is a 16 integer than stores the change in elevation as a angle that UDK understands. Using aTan2, we can take the distance from the player (90 units) and the distance from there to the ground to produce an angle.

dist = Sqrt(((playerLoc2.X-infBeam.X)*(playerLoc2.X-infBeam.X))+((playerLoc2.Y-infBeam.Y)*(playerLoc2.Y-infBeam.Y)))+((playerLoc2.Z-infBeam.Z)+(playerLoc2.Z-infBeam.Z));

Here is a bit of 3D Pythagoras to calculate the distance form the player to any object in front of it. Essentially the square root of (A

^{2}; + B

^{2}) +C

^{2}or to stretch it out:

((X1-X2)

^{2}+ (Y1-Y2)

^{2})+(Z1-Z2)

^{2}

if(dist<90) { aimRot = 0; }

If the distance between the player is less than the distance given to work out the angle, then set the pitch change to 0.

Now to look at a change to MyPawn.uc

simulated singular event Rotator GetBaseAimRotation() //Found from cached site http://webcache.googleusercontent.com/search?q=cache:GevFWh1ARvgJ:thronic.com/devnotes/UDK%2520Third%2520Person%2520Camera.htm+udk+override+aim&cd=4&hl=en&ct=clnk&gl=uk&source=www.google.co.uk { local rotator POVRot, tempRot; <span style="color: #ff0000;">local int aimR; local RetroShooterPlayerController PC; PC = RetroShooterPlayerController(Controller); aimR = PC.aimRot;</span> tempRot = Rotation; tempRot.Pitch = 0;//-aimR; //This will change the pitch of the player. SetRotation(tempRot); POVRot = Rotation; POVRot.Pitch = <span style="color: #ff0000;">-aimR*2</span>; //This will adjust the pitch of the projectile. return POVRot; }

The only change here is the Pawn Class accesses a variable from the retroShooterPlayerController class. You can’t believe how much of a headache this rather simple call was to get right. Once again the documentation wasn’t clear what you need to set PC as… Anyway. aimRot, a varilable set witha 16bit integer representation of the angle needed to change the pitch of the aim is called and applied to POVRot.Pitch.