1
0
KF2-Dev-Scripts/UDKBase/classes/SimplePC.uc
2020-12-13 18:01:13 +03:00

647 lines
19 KiB
Ucode

/**
* Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.
*/
class SimplePC extends GamePlayerController;
/** How fast to increase the rate of rotation toward the target */
var float AutoRotationAccelRate;
/** How quickly to decelerate when no rotation is applied */
var float AutoRotationBrakeDecelRate;
/** Maximum auto rotation velocity */
var float MaxAutoRotationVelocity;
/** How fast to increase the rate of rotation toward the target */
var float BreathAutoRotationAccelRate;
/** How quickly to decelerate when no rotation is applied */
var float BreathAutoRotationBrakeDecelRate;
/** Maximum auto rotation velocity */
var float MaxBreathAutoRotationVelocity;
/** When rotating to a touch-to-move target, how much to increase yaw acceleration when the target is nearby */
var float RangeBasedYawAccelStrength;
/** Distance at which we start to change rotation acceleration rate based on distance to touch-to-move target */
var float RangeBasedAccelMaxDistance;
/** True if we should look at our click-to-move destination. */
var bool bLookAtDestination;
/** Holds the location we are looking at */
var vector LookAtDestination;
var float LookAtDestAutoPitchAmount;
/** Is camera breathing engaged yet*/
var bool bCameraBreathing;
/** The location that the camera was approximately looking at when breathing began*/
var vector CameraBreathCenterLocation;
/** Delta from the desired rotation*/
var Rotator CameraBreathRotator;
/** Last location where breathing began */
var vector CameraBreathSampleLocation;
/** Time of the last random breath rotator sampling */
var float LastCameraBreathDeltaSelectTime;
/** Time between direction changes*/
var float TimeBetweenCameraBreathChanges;
/** How fast we're currently rotating toward the target (yaw, pitch) */
var vector2d AutoRotationVelocity;
/** Holds the dimensions of the viewport */
var vector2D ViewportSize;
/** List of footstep sounds, chosen at random to play while the player is walking */
var array<SoundCue> FootstepSounds;
/** How far we should move before playing the next footstep sound */
var float DistanceUntilNextFootstepSound;
/** Commandline to run when being a server */
var config string ServerCommandline;
/** Used for turn smoothing */
var float OldTurn, OldLookup;
/** How much to smooth rotation. */
var config float RotationSmoothingFactor;
/** Whether to use rotation smoothing */
var config bool bSmoothRotation;
var config int DefaultInputGroup;
/** Cache a reference to the MobilePlayerInput */
var MobilePlayerInput MPI;
/** Cache a reference to various zones */
var MobileInputZone SliderZone;
var MobileInputZone StickMoveZone;
var MobileInputZone StickLookZone;
var MobileInputZone FreeLookZone;
/** Used for stats tracking */
var int NoTapToMoves;
/** Used for stats tracking */
var float LastEnteredTapToMove;
/** Used for stats tracking */
var float TotalTimeInTapToMove;
/** Holds the time of the last movement/look change */
var float TimeOfLastUserViewChange;
/** If true, apply an offset to the view target during a matinee */
var bool bApplyBackTouchToViewOffset;
var bool bFingerIsDown;
var Vector2D TouchCenter;
var Rotator LastOffset;
var Rotator MatineeOffset;
/**
* When we init the input system, find the TapToMove zone and hook up the delegate
*/
event InitInputSystem()
{
Super.InitInputSystem();
SetupZones();
}
/**
* Kismet hook to trigger console events
*/
function OnConsoleCommand( SeqAct_ConsoleCommand inAction )
{
local string Command;
foreach inAction.Commands(Command)
{
// don't allow music before startmatch
if ( WorldInfo.Game.bWaitingToStartMatch && (Left(Command,15) ~= "mobile playsong") )
{
continue;
}
// prevent "set" commands from ever working in Kismet as they are e.g. disabled in netplay
if (!(Left(Command, 4) ~= "set ") && !(Left(Command, 9) ~= "setnopec "))
{
ConsoleCommand(Command);
}
}
}
/**
* Zones have to be setup on both sides of the network pond. This function is a good place to do that from.
*
* @param GameClass holds the class that's being setup.
*/
simulated function ReceivedGameClass(class<GameInfo> GameClass)
{
Super.ReceivedGameClass(GameClass);
// Setup the zones
SetupZones();
}
/**
* The main purpose of this function is to size and reset zones. There's a lot of specific code in
* here to reposition zones based on if it's an phone vs pad.
*/
function SetupZones()
{
// Cache the MPI
MPI = MobilePlayerInput(PlayerInput);
LocalPlayer(Player).ViewportClient.GetViewportSize(ViewportSize);
StickMoveZone = MPI.FindZone("UberStickMoveZone");
StickLookZone = MPI.FindZone("UberStickLookZone");
FreeLookZone = MPI.FindZone("UberLookZone");
}
/**
* Setup the in world indicator for Touch to move and some other subsystems
*/
simulated function PostBeginPlay()
{
Super.PostBeginPlay();
// Time of the last target sampling
LastCameraBreathDeltaSelectTime = 0;
// Setup footstep sounds
SetNextFootstepDistance();
}
/**
* Checks to see if we are moving via the virtual stick
*
* @returns true if the virtual stick is being used to move the player
*/
function bool IsStickMoveActive()
{
return StickMoveZone.State != ZoneState_Inactive;
}
/** Sets the distance until the next footstep sound plays */
function SetNextFootstepDistance()
{
// Determine how far to go until the next foot step (with a bit of randomness!)
DistanceUntilNextFootstepSound = 200 + FRand() * 32;
}
/**
* PlayerMove is called each frame to manage the input. We will use it to hook in and
* see if the player has changed their view. If they do, then stop auto-rotating
*/
function PlayerMove( float DeltaTime )
{
Super.PlayerMove(DeltaTime);
// @todo: Is this needed?
UpdateRotation( DeltaTime );
}
/**
* Optionally smooth rotation
*/
function UpdateRotation( float DeltaTime )
{
local float Smooth;
if ( bSmoothRotation )
{
Smooth = 1.0 - FMin(0.9, RotationSmoothingFactor*DeltaTime);
OldTurn = PlayerInput.aTurn * (1.0 - Smooth) + OldTurn * Smooth;
OldLookup = PlayerInput.aLookup * (1.0 - Smooth) + OldLookup * Smooth;
PlayerInput.aLookup = OldLookup;
PlayerInput.aTurn = OldTurn;
}
Super.UpdateRotation(DeltaTime);
}
/**
* Called from PlayerMove, it's here that we adjust the viewport
*/
function ProcessViewRotation( float DeltaTime, out Rotator out_ViewRotation, Rotator DeltaRot )
{
// Accumulate a desired new rotation.
local float DistToDestination;
local Vector2D MaxVelocityScalar;
local float YawRotationSign;
local float PitchRotationSign;
local float FinalYawAccelRate;
local float FinalPitchAccelRate;
local vector VectorToTarget;
local vector TargetDirection;
local Rotator NewRotation;
local Rotator CameraRotationYawOnly;
local Rotator CameraRotationPitchOnly;
local Rotator TargetRotationYawOnly;
local Rotator TargetRotationPitchOnly;
//values to use during calculation
local float RotationAccelRate;
local float RotationBreakDecelRate;
local float MaxRotationVelocity;
//Using a fixed time delta to avoid stutters on device
DeltaTime = FMin(DeltaTime, 1/25.0);
Super.ProcessViewRotation(DeltaTime, out_ViewRotation, DeltaRot);
if (PlayerInput.aTurn != 0.0 || PlayerInput.aLookUp != 0.0)
{
TimeOfLastUserViewChange = WorldInfo.RealTimeSeconds;
}
// If the player has moved the camera recently, then forcibly disable auto-rotation
if ( WorldInfo.RealTimeSeconds - TimeOfLastUserViewChange < 0.1 )
{
bLookAtDestination = false;
//reset camera breath
bCameraBreathing = false;
LastCameraBreathDeltaSelectTime = 0;
}
//Update camera breathing
UpdateCameraBreathing();
if (bLookAtDestination || !bCameraBreathing)
{
RotationAccelRate = AutoRotationAccelRate;
RotationBreakDecelRate = AutoRotationBrakeDecelRate;
MaxRotationVelocity = MaxAutoRotationVelocity;
}
else
{
RotationAccelRate = BreathAutoRotationAccelRate;
RotationBreakDecelRate = BreathAutoRotationBrakeDecelRate;
MaxRotationVelocity = MaxBreathAutoRotationVelocity;
}
MaxVelocityScalar.X = 1.0;
MaxVelocityScalar.Y = 1.0;
if( bLookAtDestination || bCameraBreathing)
{
CameraRotationYawOnly = out_ViewRotation;
CameraRotationYawOnly.Pitch = 0;
CameraRotationYawOnly.Roll = 0;
CameraRotationPitchOnly = out_ViewRotation;
CameraRotationPitchOnly.Yaw = 0;
CameraRotationPitchOnly.Roll = 0;
if( bLookAtDestination )
{
VectorToTarget = LookAtDestination;
}
else //breathing
{
VectorToTarget = CameraBreathCenterLocation - Pawn.Location;
}
TargetDirection = Normal( VectorToTarget );
TargetRotationYawOnly = Rotator( TargetDirection ) + CameraBreathRotator;
TargetRotationPitchOnly = TargetRotationYawOnly;
TargetRotationYawOnly.Pitch = 0;
TargetRotationYawOnly.Roll = 0;
TargetRotationPitchOnly.Yaw = 0;
TargetRotationPitchOnly.Roll = 0;
if( bLookAtDestination )
{
// For click to move, we limit the amount of pitching the camera will do since usually the height
// of the target isn't that interesting, however sometimes a bit of pitching helps with slope-alignment
TargetRotationPitchOnly = RLerp( CameraRotationPitchOnly, TargetRotationPitchOnly, LookAtDestAutoPitchAmount, true /* Take shortest route? */ );
}
// How close is the current camera rotation to the target orientation? We'll rotate more quickly if
// we're further off course, and more slowly as we approach the desired angle. This makes the rotation
// appear to ease-out as we approach the desired orientation.
if (!bCameraBreathing)
{
MaxVelocityScalar.x *= 1.0 - FMax( 0.0, Vector( CameraRotationYawOnly ) dot Vector( TargetRotationYawOnly ) );
MaxVelocityScalar.y *= 1.0 - FMax( 0.0, Vector( CameraRotationPitchOnly ) dot Vector( TargetRotationPitchOnly ) );
}
DistToDestination = VSize2D( VectorToTarget );
// For destination-look at, allow distance to affect speed. (Note, we take the 2D distance here)
FinalYawAccelRate = RotationAccelRate;
FinalPitchAccelRate = RotationAccelRate;
if( bLookAtDestination )
{
// Increase the yaw rate as we get closer to the target (up to 1.0 + RangeBasedYawAccelStrength).
// This is because the yaw angle relative to the target may still be very wide as we approach
// (especially if the user touched a location near the player) we want to get most of the horizontal
// turning out of the way early so the player can see where they're going
FinalYawAccelRate *= 1.0 + ( 1.0 - FMin( DistToDestination, RangeBasedAccelMaxDistance ) / RangeBasedAccelMaxDistance ) * RangeBasedYawAccelStrength;
// Decrease the pitch rate as we get closed to the target. This is because the pitch angle relative
// to the target will usually become steeper as we approach the target and we won't want to pitch
// up and down erratically as we're arriving
FinalPitchAccelRate *= FMin( DistToDestination, RangeBasedAccelMaxDistance ) / RangeBasedAccelMaxDistance;
}
CheckDistanceToDestination(DistToDestination);
// Accelerate yaw
YawRotationSign = ( out_ViewRotation.Yaw ClockwiseFrom TargetRotationYawOnly.Yaw ) ? -1.0 : 1.0;
AutoRotationVelocity.x += YawRotationSign * FinalYawAccelRate * DeltaTime;
// Accelerate pitch
PitchRotationSign = ( out_ViewRotation.Pitch ClockwiseFrom TargetRotationPitchOnly.Pitch ) ? -1.0 : 1.0;
AutoRotationVelocity.y += PitchRotationSign * FinalPitchAccelRate * DeltaTime;
}
else
{
// Yaw brake
if( AutoRotationVelocity.x > 0.01 )
{
AutoRotationVelocity.x = FMax( 0.0, AutoRotationVelocity.x - RotationBreakDecelRate * DeltaTime );
}
else if( AutoRotationVelocity.x < -0.01 )
{
AutoRotationVelocity.x = FMin( 0.0, AutoRotationVelocity.x + RotationBreakDecelRate * DeltaTime );
}
else
{
AutoRotationVelocity.x = 0.0;
}
// Pitch brake
if( AutoRotationVelocity.y > 0.01 )
{
AutoRotationVelocity.y = FMax( 0.0, AutoRotationVelocity.y - RotationBreakDecelRate * DeltaTime );
}
else if( AutoRotationVelocity.y < -0.01 )
{
AutoRotationVelocity.y = FMin( 0.0, AutoRotationVelocity.y + RotationBreakDecelRate * DeltaTime );
}
else
{
AutoRotationVelocity.y = 0.0;
}
}
// Clamp max velocity
if( AutoRotationVelocity.x > MaxRotationVelocity * MaxVelocityScalar.x )
{
AutoRotationVelocity.x = MaxRotationVelocity * MaxVelocityScalar.x;
}
else if( AutoRotationVelocity.x < -MaxRotationVelocity * MaxVelocityScalar.x )
{
AutoRotationVelocity.x = -MaxRotationVelocity * MaxVelocityScalar.x;
}
if( AutoRotationVelocity.y > MaxRotationVelocity * MaxVelocityScalar.y )
{
AutoRotationVelocity.y = MaxRotationVelocity * MaxVelocityScalar.y;
}
else if( AutoRotationVelocity.y < -MaxRotationVelocity * MaxVelocityScalar.y )
{
AutoRotationVelocity.y = -MaxRotationVelocity * MaxVelocityScalar.y;
}
if( Abs( AutoRotationVelocity.X ) > 0.01 || Abs( AutoRotationVelocity.Y ) > 0.01 )
{
// Rotate!
NewRotation.Yaw = fixedTurn(out_ViewRotation.Yaw, out_ViewRotation.Yaw + AutoRotationVelocity.x * DeltaTime, Abs( AutoRotationVelocity.x * DeltaTime ));
NewRotation.Pitch = fixedTurn(out_ViewRotation.Pitch, out_ViewRotation.Pitch + AutoRotationVelocity.y * DeltaTime, Abs( AutoRotationVelocity.y * DeltaTime ));
NewRotation.Roll = out_ViewRotation.Roll;
// Set new rotation
out_ViewRotation = NewRotation;
}
}
/**
* Stub Function. It get's called by ProcessViewRotation and allows children to perform actions based on the
* distance to a destination.
*/
simulated function CheckDistanceToDestination(float DistToDestination)
{
}
/**Function that selects a slightly offset direction to look and will trend the camera towards that*/
simulated function UpdateCameraBreathing()
{
local Vector PawnX, PawnY, PawnZ;
local float DegreeDelta;
local float YawSign;
local float PitchDegrees;
local float YawDegrees;
if ( Pawn == None )
{
bCameraBreathing = false;
LastCameraBreathDeltaSelectTime = 0;
return;
}
//if we've just moved
if (IsInState('PlayerClickToMove') || (CameraBreathSampleLocation != Pawn.Location))
{
bCameraBreathing = false;
LastCameraBreathDeltaSelectTime = 0;
CameraBreathSampleLocation = Pawn.Location;
return;
}
//if it's time to try to breath again
if (WorldInfo.TimeSeconds - LastCameraBreathDeltaSelectTime >= TimeBetweenCameraBreathChanges)
{
DegreeDelta = 0.5;
PitchDegrees = ((FRand() * 2.f) - 1.f);
YawSign = (FRand() >= 0.5f) ? 1.0f : -1.0f;
YawDegrees = YawSign * (Sqrt(1.0f - PitchDegrees*PitchDegrees));
//+ or - DegreeDeltas
CameraBreathRotator.Pitch = (PitchDegrees*DegreeDelta*65536/360);
CameraBreathRotator.Yaw = (YawDegrees*DegreeDelta*65536/360);
CameraBreathRotator.Roll = 0.0;
//if we're not actively tracking something, set a new desired look location relative to where we are already looking
if (!bLookAtDestination && !bCameraBreathing)
{
//`log("NOTE: Chosen a new look at dest"@CameraBreathRotator);
GetAxes(Rotation, PawnX, PawnY, PawnZ);
CameraBreathCenterLocation = Pawn.Location + PawnX*1000.0;
bCameraBreathing = true;
}
LastCameraBreathDeltaSelectTime = WorldInfo.TimeSeconds;
}
}
function ActivateControlGroup()
{
MPI.ActivateInputGroup("UberGroup");
}
/** Offset matinee via back touch */
function OffsetMatineeTouch(int Handle, ETouchType Type, Vector2D TouchLocation, float DeviceTimestamp, int TouchpadIndex)
{
// only first finger on back panel
if (Handle != 0 || TouchpadIndex != 1)
{
return;
}
if (Type == Touch_Began)
{
TouchCenter = TouchLocation;
bFingerIsDown = true;
}
else if (Type == Touch_Ended)
{
LastOffset = MatineeOffset;
bFingerIsDown = false;
}
else if (bFingerIsDown)
{
MatineeOffset.Yaw = LastOffset.Yaw + 60 * (TouchLocation.X - TouchCenter.X);
MatineeOffset.Pitch = LastOffset.Pitch + -60 * (TouchLocation.Y - TouchCenter.Y);
}
}
event NotifyDirectorControl(bool bNowControlling, SeqAct_Interp CurrentMatinee)
{
super.NotifyDirectorControl(bNowControlling, CurrentMatinee);
if (bNowControlling)
{
MPI.OnInputTouch = OffsetMatineeTouch;
}
else
{
MPI.OnInputTouch = none;
LastOffset.Yaw = 0;
LastOffset.Pitch = 0;
MatineeOffset.Yaw = 0;
MatineeOffset.Pitch = 0;
bFingerIsDown = false;
}
// remember if we are controlling or not
bApplyBackTouchToViewOffset = bNowControlling;
}
simulated event GetPlayerViewPoint( out vector out_Location, out Rotator out_Rotation )
{
super.GetPlayerViewPoint(out_Location, out_Rotation);
if (bApplyBackTouchToViewOffset)
{
out_Rotation += MatineeOffset;
}
}
/**
* Handle footsteps
*/
function PlayerTick(float DeltaTime)
{
local float CurrentWalkSpeed;
local int FootstepSoundIndex;
local TraceHitInfo HitInfo;
local Vector TraceStart;
local Vector TraceEnd;
local Vector TraceExtent;
local Vector OutHitLocation, OutHitNormal;
local Actor TraceActor;
if (bApplyBackTouchToViewOffset && !bFingerIsDown)
{
MatineeOffset.Yaw *= 0.99;
MatineeOffset.Pitch *= 0.99;
LastOffset.Yaw *= 0.99;
LastOffset.Pitch *= 0.99;
}
// Only play footsteps if we're actually walking at a decent speed
if ( Pawn != None )
{
CurrentWalkSpeed = VSize2D( Pawn.Velocity );
}
if ( CurrentWalkSpeed > 32.0 )
{
// Update distance until the next foot step
DistanceUntilNextFootstepSound -= CurrentWalkSpeed * DeltaTime;
if( DistanceUntilNextFootstepSound < 0.0 )
{
TraceStart = Pawn.Location;
// @todo probably need a better way to get the end location instead of a magic number
TraceEnd = Pawn.Location;
TraceEnd.Z -= 100.0f;
// trace down and see what we are standing on.
TraceActor = Trace(OutHitLocation, OutHitNormal, TraceEnd, TraceStart, TRUE, TraceExtent, HitInfo, TRACEFLAG_Bullet|TRACEFLAG_Blocking|TRACEFLAG_SkipMovers);
if( TraceActor != None && HitInfo.PhysMaterial != None && HitInfo.PhysMaterial.ImpactSound != None )
{
// Play the sound from the hit physical material if it exists
PlaySound( HitInfo.PhysMaterial.ImpactSound );
}
else if (FootstepSounds.Length > 0)
{
// Play a random footstep sound if we couldnt find a physical material to get a sound from.
FootstepSoundIndex = Rand( FootstepSounds.Length );
PlaySound( FootstepSounds[ FootstepSoundIndex ] );
}
// Queue up the next footstep
SetNextFootstepDistance();
}
}
else
{
// We stopped walking so reset time until next footstep
SetNextFootstepDistance();
}
Super.PlayerTick(DeltaTime);
}
exec function SetFootstepsToStone();
exec function SetFootstepsToSnow();
defaultproperties
{
InputClass=class'GameFramework.MobilePlayerInput'
AutoRotationAccelRate=10000.0
AutoRotationBrakeDecelRate=10000.0
MaxAutoRotationVelocity=300000
BreathAutoRotationAccelRate=250.0
BreathAutoRotationBrakeDecelRate=1.0
MaxBreathAutoRotationVelocity=75
TimeBetweenCameraBreathChanges = 2.0
RangeBasedYawAccelStrength=8.0
RangeBasedAccelMaxDistance=512.0
}