870 lines
26 KiB
Ucode
870 lines
26 KiB
Ucode
|
//=============================================================================
|
||
|
// SVehicle
|
||
|
// Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.
|
||
|
//=============================================================================
|
||
|
|
||
|
class SVehicle extends Vehicle
|
||
|
native(Physics)
|
||
|
nativereplication
|
||
|
abstract;
|
||
|
|
||
|
|
||
|
`if(`isdefined(WITH_PHYSX))
|
||
|
/** The main vehicle class pointer */
|
||
|
var native const pointer PVehicle{class PxVehicleDrive};
|
||
|
/** Its vehicle manager pointer */
|
||
|
var native const pointer MyVehicleManager{class FPhysXVehicleManager};
|
||
|
`endif
|
||
|
cpptext
|
||
|
{
|
||
|
// UObject interface
|
||
|
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent);
|
||
|
|
||
|
// Actor interface.
|
||
|
virtual void physRigidBody(FLOAT DeltaTime);
|
||
|
virtual void TickSimulated( FLOAT DeltaSeconds );
|
||
|
virtual void TickAuthoritative( FLOAT DeltaSeconds );
|
||
|
virtual void setPhysics(BYTE NewPhysics, AActor *NewFloor, FVector NewFloorV);
|
||
|
virtual void PostNetReceiveLocation();
|
||
|
INT* GetOptimizedRepList( BYTE* InDefault, FPropertyRetirement* Retire, INT* Ptr, UPackageMap* Map, UActorChannel* Channel );
|
||
|
|
||
|
// SVehicle interface.
|
||
|
virtual void VehiclePackRBState();
|
||
|
virtual void VehicleUnpackRBState();
|
||
|
virtual FVector GetDampingForce(const FVector& InForce);
|
||
|
|
||
|
#if WITH_NOVODEX
|
||
|
|
||
|
virtual void OnRigidBodyCollision(const FRigidBodyCollisionInfo& MyInfo, const FRigidBodyCollisionInfo& OtherInfo, const FCollisionImpactData& RigidCollisionData);
|
||
|
virtual void ModifyNxActorDesc(NxActorDesc& ActorDesc,UPrimitiveComponent* PrimComp, const class NxGroupsMask& GroupsMask, UINT MatIndex);
|
||
|
virtual void PostInitRigidBody(NxActor* nActor, NxActorDesc& ActorDesc, UPrimitiveComponent* PrimComp);
|
||
|
virtual void PreTermRigidBody(NxActor* nActor);
|
||
|
virtual void TermRBPhys(FRBPhysScene* Scene);
|
||
|
#endif
|
||
|
|
||
|
#if WITH_PHYSX
|
||
|
virtual void OnRigidBodyCollision(const FRigidBodyCollisionInfo& MyInfo, const FRigidBodyCollisionInfo& OtherInfo, const FCollisionImpactData& RigidCollisionData);
|
||
|
virtual void PostInitRigidBody(PxActor* nActor, UPrimitiveComponent* PrimComp);
|
||
|
virtual void TermRBPhys(FRBPhysScene* Scene);
|
||
|
|
||
|
/** Create vehicle util function. */
|
||
|
void CreateVehicleUtil();
|
||
|
|
||
|
void DrawWheelsDebug(BOOL bDrawForcePoints);
|
||
|
|
||
|
/** process vehicle control inputs */
|
||
|
void ProcessVehicleInputs(FLOAT DeltaTime);
|
||
|
#endif
|
||
|
|
||
|
virtual void UpdateVehicle(ASVehicle* Vehicle, FLOAT DeltaTime) {}
|
||
|
|
||
|
/** Set any params on wheel particle effect */
|
||
|
virtual void SetWheelEffectParams(USVehicleWheel* VW, FLOAT SlipVel);
|
||
|
}
|
||
|
|
||
|
|
||
|
/** Chassis mass */
|
||
|
var(Vehicle) float ChassisMass;
|
||
|
|
||
|
/** If this vehicle is a tank */
|
||
|
var(Vehicle) BOOL bIsTank;
|
||
|
|
||
|
/** Enable debug rendering for this vehicle */
|
||
|
var(Vehicle) bool bEnableDebugRendering;
|
||
|
|
||
|
/** Current debug graph channels for wheel and engine */
|
||
|
var INT DebugRenderActiveGraphChannelWheel;
|
||
|
var INT DebugRenderActiveGraphChannelEngine;
|
||
|
|
||
|
/** Whether the vehicle is in reverse mode */
|
||
|
var bool bInReverseMode;
|
||
|
|
||
|
/** Object containing the actual vehicle simulation paramters and code. Allows you to 'plug' different vehicle types in. */
|
||
|
var() noclear const SVehicleSimBase SimObj;
|
||
|
|
||
|
/** Data for each wheel. Very important to list in this order FrontLeft, FrontRight, RearLeft, RearRight. */
|
||
|
var() editinline export array<SVehicleWheel> Wheels;
|
||
|
|
||
|
/** Center of mass location of the vehicle, in local space. */
|
||
|
var() vector COMOffset;
|
||
|
|
||
|
/** Inertia Tensor Multipler - allows you to scale the components of the pre-calculated inertia tensor */
|
||
|
var() vector InertiaTensorMultiplier;
|
||
|
|
||
|
/** Use the stay-upright world constraint */
|
||
|
var(UprightConstraint) bool bStayUpright;
|
||
|
|
||
|
/** Angle at which the vehicle will resist rolling */
|
||
|
var(UprightConstraint) float StayUprightRollResistAngle;
|
||
|
|
||
|
/** Angle at which the vehicle will resist pitching */
|
||
|
var(UprightConstraint) float StayUprightPitchResistAngle;
|
||
|
|
||
|
/** Amount of spring past the limit angles */
|
||
|
var(UprightConstraint) float StayUprightStiffness;
|
||
|
|
||
|
/** Amount of dampening past the limit angles */
|
||
|
var(UprightConstraint) float StayUprightDamping;
|
||
|
|
||
|
var editinline export RB_StayUprightSetup StayUprightConstraintSetup;
|
||
|
var editinline export RB_ConstraintInstance StayUprightConstraintInstance;
|
||
|
|
||
|
var bool bUseSuspensionAxis;
|
||
|
|
||
|
/** set this flag to cause wheel shape parameters to be updated. Cleared after update occurs. */
|
||
|
var bool bUpdateWheelShapes;
|
||
|
|
||
|
/** Percent the Suspension must want to move in one go for the heavy shift function to be called*/
|
||
|
var float HeavySuspensionShiftPercent;
|
||
|
|
||
|
/** Vehicle total speed will be capped to this value */
|
||
|
var() float MaxSpeed;
|
||
|
|
||
|
/** Vehicle angular velocity will be capped to this value */
|
||
|
var() float MaxAngularVelocity;
|
||
|
|
||
|
/** OUTPUT: True if _any_ SVehicleWheel is currently touching the ground (ignores contacts with chassis etc) */
|
||
|
var const bool bVehicleOnGround;
|
||
|
|
||
|
/** OUTPUT: Time that bVehicleOnGround has been false for. */
|
||
|
var const float TimeOffGround;
|
||
|
|
||
|
/** OUTPUT: True if _any_ SVehicleWheel is currently touching water */
|
||
|
var const bool bVehicleOnWater;
|
||
|
|
||
|
/** OUTPUT: True if vehicle is mostly upside down. */
|
||
|
var const bool bIsInverted;
|
||
|
|
||
|
/** OUTPUT: True if there are any contacts between the chassis of the vehicle and the ground. */
|
||
|
var const bool bChassisTouchingGround;
|
||
|
|
||
|
/** OUTPUT: True if there were any contacts between the chassis of the vehicle and the ground last tick */
|
||
|
var const bool bWasChassisTouchingGroundLastTick;
|
||
|
|
||
|
/** @name Vehicle uprighting */
|
||
|
//@{
|
||
|
|
||
|
/** true if vehicle can be uprighted by player */
|
||
|
var bool bCanFlip;
|
||
|
/** Scales the lifting force applied to the vehicle during uprighting. */
|
||
|
var(Uprighting) float UprightLiftStrength;
|
||
|
/** Scales the torque applied to the vehicle during uprighting. */
|
||
|
var(Uprighting) float UprightTorqueStrength;
|
||
|
/** Time in seconds to apply uprighting force/torque. */
|
||
|
var(Uprighting) float UprightTime;
|
||
|
|
||
|
/** Changes the direction the car gets flipped (used to prevent flipping car onto player */
|
||
|
var bool bFlipRight;
|
||
|
/** Internal variable. True while uprighting forces are being applied. */
|
||
|
var bool bIsUprighting;
|
||
|
|
||
|
/** Internal variable. Marks the time that uprighting began. */
|
||
|
var float UprightStartTime;
|
||
|
//@}
|
||
|
|
||
|
/** @name Sounds */
|
||
|
//@{
|
||
|
/** Ambient engine-running sound. Pitch modulated based on RPMS. */
|
||
|
var(Sounds) editconst const AudioComponent EngineSound;
|
||
|
|
||
|
/** Volume-modulated wheel squeeling. */
|
||
|
var(Sounds) editconst const AudioComponent SquealSound;
|
||
|
|
||
|
/** Played when the vehicle slams into things. */
|
||
|
var(Sounds) SoundCue CollisionSound;
|
||
|
|
||
|
/** Engine startup sound played upon entering the vehicle. */
|
||
|
var(Sounds) SoundCue EnterVehicleSound;
|
||
|
|
||
|
/** Engine switch-off sound played upon exiting the vhicle. */
|
||
|
var(Sounds) SoundCue ExitVehicleSound;
|
||
|
|
||
|
/** Minimum time passed between the triggering collision sounds; generally set to longest collision sound. */
|
||
|
var(Sounds) float CollisionIntervalSecs;
|
||
|
|
||
|
/** Slip velocity cuttoff below which no wheel squealing is heard. */
|
||
|
var(Sounds) const float SquealThreshold;
|
||
|
|
||
|
/** Lateral Slip velocity cut off below which no wheel squealing is heard */
|
||
|
var(Sounds) const float SquealLatThreshold;
|
||
|
|
||
|
/** multiplier for volume level of Lateral squeals relative to straight slip squeals. */
|
||
|
var(Sounds) const float LatAngleVolumeMult;
|
||
|
|
||
|
/** Time delay between the engine startup sound and the engine idling sound. */
|
||
|
var(Sounds) const float EngineStartOffsetSecs;
|
||
|
/** Time delay between the engine shutdown sound and the deactivation of the engine idling sound. */
|
||
|
var(Sounds) const float EngineStopOffsetSecs;
|
||
|
|
||
|
/** Internal variable; prevents collision sounds from being triggered too frequently. */
|
||
|
var float LastCollisionSoundTime;
|
||
|
//@}
|
||
|
|
||
|
// Internal
|
||
|
var float OutputBrake;
|
||
|
var float OutputGas;
|
||
|
var float OutputSteering;
|
||
|
var float OutputRise;
|
||
|
var bool bOutputHandbrake;
|
||
|
var bool bHoldingDownHandbrake;
|
||
|
|
||
|
var float ForwardVel;
|
||
|
var int NumPoweredWheels;
|
||
|
|
||
|
// camera
|
||
|
var() vector BaseOffset;
|
||
|
var() float CamDist;
|
||
|
|
||
|
var int DriverViewPitch; // The driver's view pitch
|
||
|
var int DriverViewYaw; // The driver's view yaw
|
||
|
|
||
|
// replication
|
||
|
|
||
|
struct native VehicleState
|
||
|
{
|
||
|
var RigidBodyState RBState;
|
||
|
|
||
|
var byte ServerBrake;
|
||
|
var byte ServerGas;
|
||
|
var byte ServerSteering;
|
||
|
var byte ServerRise;
|
||
|
var bool bServerHandbrake;
|
||
|
var int ServerView; // Pitch and Yaw - 16 bits each
|
||
|
};
|
||
|
|
||
|
var native const VehicleState VState;
|
||
|
var native const float AngErrorAccumulator;
|
||
|
|
||
|
/** Hacky - used to scale hurtradius applied impulses */
|
||
|
var float RadialImpulseScaling;
|
||
|
|
||
|
replication
|
||
|
{
|
||
|
if (Physics == PHYS_RigidBody)
|
||
|
VState, MaxSpeed;
|
||
|
}
|
||
|
|
||
|
// Physics interface
|
||
|
native function AddForce(Vector Force);
|
||
|
native function AddImpulse(Vector Impulse);
|
||
|
native function AddTorque(Vector Torque);
|
||
|
native function bool IsSleeping();
|
||
|
|
||
|
`if(`isdefined(WITH_PHYSX))
|
||
|
/** Actual draw call for vehicle debug rendering */
|
||
|
// native function to be called from C++
|
||
|
|
||
|
native function DrawGraphsAndPrintTireSurfaceTypes(HUD HUD, FLOAT YL, FLOAT YPos);
|
||
|
`endif
|
||
|
|
||
|
/** turns on or off a wheel's collision
|
||
|
* @param WheelNum the index of the wheel in the Wheels array to change
|
||
|
* @param bCollision whether to turn collision on or off
|
||
|
*/
|
||
|
native final function SetWheelCollision(int WheelNum, bool bCollision);
|
||
|
|
||
|
/**
|
||
|
* Called when gameplay begins. Used to make sure the engine sound audio component
|
||
|
* has the right properties set to ensure it gets restarted if it has been cut out
|
||
|
* due to the audio code running out of HW channels to play the sound in.
|
||
|
*/
|
||
|
simulated event PostBeginPlay()
|
||
|
{
|
||
|
Super.PostBeginPlay();
|
||
|
if( EngineSound != None )
|
||
|
{
|
||
|
EngineSound.bShouldRemainActiveIfDropped = TRUE;
|
||
|
}
|
||
|
if (CollisionSound != None && CollisionIntervalSecs <= 0.0)
|
||
|
{
|
||
|
CollisionIntervalSecs = CollisionSound.GetCueDuration() / WorldInfo.TimeDilation;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** Store pointer to each wheel's SkelControlWheel. */
|
||
|
simulated event PostInitAnimTree(SkeletalMeshComponent SkelComp)
|
||
|
{
|
||
|
local int WheelIndex;
|
||
|
local SVehicleWheel Wheel;
|
||
|
|
||
|
Super.PostInitAnimTree(SkelComp);
|
||
|
|
||
|
if (SkelComp == Mesh)
|
||
|
{
|
||
|
for(WheelIndex = 0; WheelIndex<Wheels.length; WheelIndex++)
|
||
|
{
|
||
|
Wheel = Wheels[WheelIndex];
|
||
|
Wheel.WheelControl = SkelControlWheel( Mesh.FindSkelControl(Wheel.SkelControlName) );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
simulated event Destroyed()
|
||
|
{
|
||
|
Super.Destroyed();
|
||
|
StopVehicleSounds();
|
||
|
}
|
||
|
|
||
|
/** TurnOff()
|
||
|
Freeze pawn - stop sounds, animations, physics, weapon firing
|
||
|
*/
|
||
|
simulated function TurnOff()
|
||
|
{
|
||
|
Super.TurnOff();
|
||
|
StopVehicleSounds();
|
||
|
}
|
||
|
|
||
|
simulated function StopVehicleSounds()
|
||
|
{
|
||
|
if ( EngineSound != None )
|
||
|
{
|
||
|
EngineSound.Stop();
|
||
|
}
|
||
|
|
||
|
if ( SquealSound != None )
|
||
|
{
|
||
|
SquealSound.Stop();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Take Radius Damage
|
||
|
* by default scales damage based on distance from HurtOrigin to Actor's location.
|
||
|
* This can be overriden by the actor receiving the damage for special conditions (see KAsset.uc).
|
||
|
*
|
||
|
* @param InstigatedBy, instigator of the damage
|
||
|
* @param Base Damage
|
||
|
* @param Damage Radius (from Origin)
|
||
|
* @param DamageType class
|
||
|
* @param Momentum (float)
|
||
|
* @param HurtOrigin, origin of the damage radius.
|
||
|
* @param bFullDamage, if true, damage not scaled based on distance HurtOrigin
|
||
|
* @param DamageCauser the Actor that directly caused the damage (i.e. the Projectile that exploded, the Weapon that fired, etc)
|
||
|
*/
|
||
|
simulated function TakeRadiusDamage
|
||
|
(
|
||
|
Controller InstigatedBy,
|
||
|
float BaseDamage,
|
||
|
float DamageRadius,
|
||
|
class<DamageType> DamageType,
|
||
|
float Momentum,
|
||
|
vector HurtOrigin,
|
||
|
bool bFullDamage,
|
||
|
Actor DamageCauser,
|
||
|
optional float DamageFalloffExponent=1.f
|
||
|
)
|
||
|
{
|
||
|
local vector HitLocation, Dir, NewDir;
|
||
|
local float Dist, DamageScale;
|
||
|
local TraceHitInfo HitInfo;
|
||
|
|
||
|
if ( Role < ROLE_Authority )
|
||
|
return;
|
||
|
|
||
|
// calculate actual hit position on mesh, rather than approximating with cylinder
|
||
|
HitLocation = Location;
|
||
|
Dir = Location - HurtOrigin;
|
||
|
|
||
|
CheckHitInfo( HitInfo, Mesh, Dir, HitLocation );
|
||
|
NewDir = HitLocation - HurtOrigin;
|
||
|
Dist = VSize(NewDir);
|
||
|
|
||
|
if ( bFullDamage )
|
||
|
{
|
||
|
DamageScale = 1.f;
|
||
|
}
|
||
|
else if ( dist > DamageRadius )
|
||
|
return;
|
||
|
else
|
||
|
{
|
||
|
DamageScale = FMax(0,1 - Dist/DamageRadius);
|
||
|
DamageScale = DamageScale ** DamageFalloffExponent;
|
||
|
}
|
||
|
|
||
|
RadialImpulseScaling = DamageScale;
|
||
|
|
||
|
TakeDamage
|
||
|
(
|
||
|
BaseDamage * DamageScale,
|
||
|
InstigatedBy,
|
||
|
HitLocation,
|
||
|
(DamageScale * Momentum * Normal(dir)),
|
||
|
DamageType,
|
||
|
HitInfo,
|
||
|
DamageCauser
|
||
|
);
|
||
|
RadialImpulseScaling = 1.0;
|
||
|
if (Health > 0)
|
||
|
{
|
||
|
DriverRadiusDamage(BaseDamage, DamageRadius, InstigatedBy, DamageType, Momentum, HurtOrigin, DamageCauser);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Utility for switching the vehicle from a single body to an articulated ragdoll-like one given a new mesh and physics asset.
|
||
|
* ActorMove is an extra translation applied to Actor during the transition, which can be useful to avoid ragdoll mesh penetrating into the ground.
|
||
|
*/
|
||
|
native function InitVehicleRagdoll( SkeletalMesh RagdollMesh, PhysicsAsset RagdollPhysAsset, vector ActorMove, bool bClearAnimTree );
|
||
|
|
||
|
function AddVelocity( vector NewVelocity, vector HitLocation,class<DamageType> DamageType, optional TraceHitInfo HitInfo )
|
||
|
{
|
||
|
if (!IsZero(NewVelocity))
|
||
|
{
|
||
|
NewVelocity = RadialImpulseScaling * MomentumMult * DamageType.Default.VehicleMomentumScaling * DamageType.Default.KDamageImpulse * Normal(NewVelocity);
|
||
|
if (!bIgnoreForces && !IsZero(NewVelocity))
|
||
|
{
|
||
|
if (Location.Z > WorldInfo.StallZ)
|
||
|
{
|
||
|
NewVelocity.Z = FMin(NewVelocity.Z, 0);
|
||
|
}
|
||
|
if (InGodMode())
|
||
|
{
|
||
|
NewVelocity *= 0.25;
|
||
|
}
|
||
|
Mesh.AddImpulse(NewVelocity, HitLocation);
|
||
|
}
|
||
|
}
|
||
|
RadialImpulseScaling = 1.0;
|
||
|
}
|
||
|
|
||
|
function bool Died(Controller Killer, class<DamageType> DamageType, vector HitLocation)
|
||
|
{
|
||
|
if ( Super.Died(Killer, DamageType, HitLocation) )
|
||
|
{
|
||
|
bDriving = false;
|
||
|
AddVelocity(TearOffMomentum, HitLocation, DamageType);
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Calculate camera view point, when viewing this actor.
|
||
|
*
|
||
|
* @param fDeltaTime delta time seconds since last update
|
||
|
* @param out_CamLoc Camera Location
|
||
|
* @param out_CamRot Camera Rotation
|
||
|
* @param out_FOV Field of View
|
||
|
*
|
||
|
* @return true if Pawn should provide the camera point of view.
|
||
|
*/
|
||
|
simulated function bool CalcCamera( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
|
||
|
{
|
||
|
local vector Pos, HitLocation, HitNormal;
|
||
|
|
||
|
// Simple third person view implementation
|
||
|
GetActorEyesViewPoint( out_CamLoc, out_CamRot );
|
||
|
|
||
|
out_CamLoc += BaseOffset;
|
||
|
Pos = out_CamLoc - Vector(out_CamRot) * CamDist;
|
||
|
if( Trace(HitLocation, HitNormal, Pos, out_CamLoc, false, vect(0,0,0)) != None )
|
||
|
{
|
||
|
out_CamLoc = HitLocation + HitNormal*2;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
out_CamLoc = Pos;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
simulated function name GetDefaultCameraMode( PlayerController RequestedBy )
|
||
|
{
|
||
|
return 'Default';
|
||
|
}
|
||
|
|
||
|
function bool TryToDrive(Pawn P)
|
||
|
{
|
||
|
// Does the vehicle need to be uprighted?
|
||
|
if ( bIsInverted && !bVehicleOnGround && VSize(Velocity) <= 0.1f )
|
||
|
{
|
||
|
if ( bCanFlip )
|
||
|
{
|
||
|
bIsUprighting = true;
|
||
|
UprightStartTime = WorldInfo.TimeSeconds;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return Super.TryToDrive(P);
|
||
|
}
|
||
|
|
||
|
/** HasWheelsOnGround()
|
||
|
returns true if any of vehicles wheels are currently in contact with the ground (wheel has bWheelOnGround==true)
|
||
|
*/
|
||
|
simulated native function bool HasWheelsOnGround();
|
||
|
|
||
|
/** turns on the engine sound */
|
||
|
simulated function StartEngineSound()
|
||
|
{
|
||
|
if (EngineSound != None)
|
||
|
{
|
||
|
EngineSound.Play();
|
||
|
}
|
||
|
ClearTimer('StartEngineSound');
|
||
|
ClearTimer('StopEngineSound');
|
||
|
}
|
||
|
|
||
|
/** starts a timer of EngineStartOffsetSecs duration to turn on the engine sound */
|
||
|
simulated function StartEngineSoundTimed()
|
||
|
{
|
||
|
if (EngineStartOffsetSecs > 0.f)
|
||
|
{
|
||
|
ClearTimer('StopEngineSound');
|
||
|
SetTimer( EngineStartOffsetSecs, false, nameof(StartEngineSound) );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
StartEngineSound();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** turns off the engine sound */
|
||
|
simulated function StopEngineSound()
|
||
|
{
|
||
|
if (EngineSound != None)
|
||
|
{
|
||
|
EngineSound.Stop();
|
||
|
}
|
||
|
ClearTimer('StartEngineSound');
|
||
|
ClearTimer('StopEngineSound');
|
||
|
}
|
||
|
|
||
|
/** starts a timer of EngineStopOffsetSecs duration to turn off the engine sound */
|
||
|
simulated function StopEngineSoundTimed()
|
||
|
{
|
||
|
if (EngineStopOffsetSecs > 0.f)
|
||
|
{
|
||
|
ClearTimer('StartEngineSound');
|
||
|
SetTimer( EngineStopOffsetSecs, false, nameof(StopEngineSound) );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
StopEngineSound();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
simulated function VehiclePlayEnterSound()
|
||
|
{
|
||
|
// For efficiency we're removing this fix and replacing the sounds with cues instead of components.
|
||
|
// Deactivate any engine stopping sounds that were happening.
|
||
|
|
||
|
// Trigger the engine starting sound.
|
||
|
if (EnterVehicleSound != None)
|
||
|
{
|
||
|
PlaySound(EnterVehicleSound);
|
||
|
}
|
||
|
StartEngineSoundTimed();
|
||
|
|
||
|
}
|
||
|
|
||
|
simulated function VehiclePlayExitSound()
|
||
|
{
|
||
|
// For efficiency we're removing this fix and replacing the sounds with cues instead of components.
|
||
|
// Deactivate any engine starting sounds that were happening.
|
||
|
|
||
|
// Trigger the engine stopping sound.
|
||
|
if (ExitVehicleSound != None)
|
||
|
{
|
||
|
PlaySound(ExitVehicleSound);
|
||
|
}
|
||
|
StopEngineSoundTimed();
|
||
|
}
|
||
|
|
||
|
simulated function DrivingStatusChanged()
|
||
|
{
|
||
|
// turn parking friction on or off
|
||
|
bUpdateWheelShapes = true;
|
||
|
|
||
|
if ( bDriving )
|
||
|
{
|
||
|
VehiclePlayEnterSound();
|
||
|
}
|
||
|
else if ( Health > 0 )
|
||
|
{
|
||
|
VehiclePlayExitSound();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
simulated event RigidBodyCollision( PrimitiveComponent HitComponent, PrimitiveComponent OtherComponent,
|
||
|
const out CollisionImpactData RigidCollisionData, int ContactIndex )
|
||
|
{
|
||
|
if( CollisionSound != None && WorldInfo.TimeSeconds - LastCollisionSoundTime > CollisionIntervalSecs )
|
||
|
{
|
||
|
PlaySound(CollisionSound, true);
|
||
|
LastCollisionSoundTime = WorldInfo.TimeSeconds;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** called when the suspension moves a large amount, passes the delta*/
|
||
|
simulated event SuspensionHeavyShift(float Delta);
|
||
|
|
||
|
function PostTeleport(Teleporter OutTeleporter)
|
||
|
{
|
||
|
Mesh.SetRBPosition(Location);
|
||
|
}
|
||
|
|
||
|
simulated function DisplayDebug(HUD HUD, out float out_YL, out float out_YPos)
|
||
|
{
|
||
|
local Array<String> DebugInfo;
|
||
|
local int i;
|
||
|
|
||
|
super.DisplayDebug(HUD, out_YL, out_YPOS);
|
||
|
|
||
|
GetSVehicleDebug( DebugInfo );
|
||
|
|
||
|
Hud.Canvas.SetDrawColor(0,255,0);
|
||
|
for (i=0;i<DebugInfo.Length;i++)
|
||
|
{
|
||
|
Hud.Canvas.DrawText( " " @ DebugInfo[i] );
|
||
|
out_YPos += out_YL;
|
||
|
Hud.Canvas.SetPos(4, out_YPos);
|
||
|
}
|
||
|
|
||
|
// Uncomment to see detailed per-wheel debug info
|
||
|
//PX3_TODO REMOVE?
|
||
|
// LOC_MOD
|
||
|
DisplayWheelsDebug(HUD, out_YL);
|
||
|
|
||
|
`if(`isdefined(WITH_PHYSX))
|
||
|
// Draw telemetry data
|
||
|
if(bEnableDebugRendering)
|
||
|
{
|
||
|
DrawGraphsAndPrintTireSurfaceTypes(HUD, out_YL, out_YPos);
|
||
|
}
|
||
|
`endif
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Special debug information for the wheels that is displayed at each wheel's location
|
||
|
*/
|
||
|
simulated function DisplayWheelsDebug(HUD HUD, float YL)
|
||
|
{
|
||
|
local int i, j;
|
||
|
local vector WorldLoc, ScreenLoc, X, Y, Z, EndPoint, ScreenEndPoint;
|
||
|
local Color SaveColor;
|
||
|
local float LastForceValue;
|
||
|
local float GraphScale;
|
||
|
local float ForceValue;
|
||
|
local vector ForceValueLoc;
|
||
|
|
||
|
if (SimObj == None)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
GraphScale = 100.0f;
|
||
|
SaveColor = HUD.Canvas.DrawColor;
|
||
|
|
||
|
for (i=0; i<Wheels.Length; i++)
|
||
|
{
|
||
|
GetAxes(Rotation, X, Y, Z);
|
||
|
WorldLoc = Location + (Wheels[i].WheelPosition >> Rotation);
|
||
|
ScreenLoc = HUD.Canvas.Project(WorldLoc);
|
||
|
|
||
|
if( ScreenLoc.X >= 0 && ScreenLoc.X < HUD.Canvas.ClipX && ScreenLoc.Y >= 0 && ScreenLoc.Y < HUD.Canvas.ClipY )
|
||
|
{
|
||
|
// Draw Text
|
||
|
HUD.Canvas.DrawColor = MakeColor(255,255,0,255);
|
||
|
HUD.Canvas.SetPos(ScreenLoc.X, ScreenLoc.Y);
|
||
|
HUD.Canvas.DrawText("Force "$Wheels[i].ContactForce);
|
||
|
HUD.Canvas.SetPos(ScreenLoc.X, ScreenLoc.Y - (1 * YL));
|
||
|
HUD.Canvas.DrawText("SR "$Wheels[i].LongSlipRatio);
|
||
|
HUD.Canvas.SetPos(ScreenLoc.X, ScreenLoc.Y - (2 * YL));
|
||
|
HUD.Canvas.DrawText("SA "$Wheels[i].LatSlipAngle * RadToDeg$" ("$Wheels[i].LatSlipAngle$")");
|
||
|
HUD.Canvas.SetPos(ScreenLoc.X, ScreenLoc.Y - (3 * YL));
|
||
|
HUD.Canvas.DrawText("Torque "$Wheels[i].MotorTorque);
|
||
|
HUD.Canvas.SetPos(ScreenLoc.X, ScreenLoc.Y - (4 * YL));
|
||
|
HUD.Canvas.DrawText("SpinVel "$Wheels[i].SpinVel);
|
||
|
|
||
|
// Draw Lines
|
||
|
HUD.Canvas.DrawColor = HUD.RedColor;
|
||
|
EndPoint = WorldLoc + (Wheels[i].LongImpulse * 100 * Wheels[i].LongDirection) - (Wheels[i].WheelRadius * Z);
|
||
|
ScreenEndPoint = HUD.Canvas.Project(EndPoint);
|
||
|
DrawDebugLine(WorldLoc - (Wheels[i].WheelRadius * Z), EndPoint, 255, 0, 0);
|
||
|
HUD.Canvas.SetPos(ScreenEndPoint.X, ScreenEndPoint.Y);
|
||
|
HUD.Canvas.DrawText(Wheels[i].LongImpulse);
|
||
|
|
||
|
HUD.Canvas.DrawColor = HUD.GreenColor;
|
||
|
EndPoint = WorldLoc + (Wheels[i].LatImpulse * 100 * Wheels[i].LatDirection) - (Wheels[i].WheelRadius * Z);
|
||
|
ScreenEndPoint = HUD.Canvas.Project(EndPoint);
|
||
|
DrawDebugLine(WorldLoc - (Wheels[i].WheelRadius * Z), EndPoint, 0, 255, 0);
|
||
|
HUD.Canvas.SetPos(ScreenEndPoint.X, ScreenEndPoint.Y);
|
||
|
HUD.Canvas.DrawText(Wheels[i].LatImpulse);
|
||
|
HUD.Canvas.SetPos(ScreenLoc.X, ScreenLoc.Y + YL);
|
||
|
HUD.Canvas.DrawText(Wheels[i].LatImpulse);
|
||
|
|
||
|
// Draw Axes
|
||
|
HUD.Canvas.DrawColor = MakeColor(255,255,255,255);
|
||
|
HUD.Draw2DLine(ScreenLoc.X, ScreenLoc.Y, ScreenLoc.X + GraphScale, ScreenLoc.Y, MakeColor(0,0,255,255));
|
||
|
HUD.Canvas.SetPos(ScreenLoc.X + GraphScale, ScreenLoc.Y);
|
||
|
HUD.Canvas.DrawText(PI * 0.5f);
|
||
|
HUD.Draw2DLine(ScreenLoc.X, ScreenLoc.Y, ScreenLoc.X, ScreenLoc.Y - GraphScale, MakeColor(0,0,255,255));
|
||
|
HUD.Canvas.SetPos(ScreenLoc.X, ScreenLoc.Y - GraphScale);
|
||
|
HUD.Canvas.DrawText(SimObj.WheelLatExtremumValue);
|
||
|
|
||
|
// Draw Graph
|
||
|
LastForceValue = 0.0f;
|
||
|
for (j=0; j<=GraphScale; j++)
|
||
|
{
|
||
|
ForceValue = HermiteEval(j * ((PI * 0.5f) / GraphScale));
|
||
|
ForceValue = (ForceValue / SimObj.WheelLatExtremumValue) * GraphScale;
|
||
|
HUD.Draw2DLine(ScreenLoc.X + (j - 1), ScreenLoc.Y - LastForceValue, ScreenLoc.X + j, ScreenLoc.Y - ForceValue, MakeColor(0,255,0,255));
|
||
|
LastForceValue = ForceValue;
|
||
|
}
|
||
|
|
||
|
// Draw Force Value
|
||
|
ForceValue = HermiteEval(Abs(Wheels[i].LatSlipAngle));
|
||
|
ForceValueLoc.X = ScreenLoc.X + (Abs(Wheels[i].LatSlipAngle) / (PI * 0.5f)) * GraphScale;
|
||
|
ForceValueLoc.Y = ScreenLoc.Y - (ForceValue / SimObj.WheelLatExtremumValue) * GraphScale;
|
||
|
HUD.Draw2DLine(ForceValueLoc.X - 5, ForceValueLoc.Y, ForceValueLoc.X + 5, ForceValueLoc.Y, MakeColor(255,0,0,255));
|
||
|
HUD.Draw2DLine(ForceValueLoc.X, ForceValueLoc.Y - 5, ForceValueLoc.X, ForceValueLoc.Y + 5, MakeColor(255,0,0,255));
|
||
|
HUD.Canvas.SetPos(ScreenLoc.X, ForceValueLoc.Y);
|
||
|
HUD.Canvas.DrawText(ForceValue);
|
||
|
HUD.Canvas.SetPos(ForceValueLoc.X, ScreenLoc.Y + YL);
|
||
|
HUD.Canvas.DrawText(Wheels[i].LatSlipAngle);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HUD.Canvas.DrawColor = SaveColor;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Hermite spline evaluation for use with the slip curve debug display
|
||
|
*/
|
||
|
simulated function float HermiteEval(float Slip)
|
||
|
{
|
||
|
local float LatExtremumSlip;
|
||
|
local float LatExtremumValue;
|
||
|
local float LatAsymptoteSlip;
|
||
|
local float LatAsymptoteValue;
|
||
|
local float SlipSquared, SlipCubed;
|
||
|
local float C0, C1, C3;
|
||
|
|
||
|
LatExtremumSlip = SimObj.WheelLatExtremumSlip;
|
||
|
LatExtremumValue = SimObj.WheelLatExtremumValue;
|
||
|
LatAsymptoteSlip = SimObj.WheelLatAsymptoteSlip;
|
||
|
LatAsymptoteValue = SimObj.WheelLatAsymptoteValue;
|
||
|
|
||
|
if (Slip < LatExtremumSlip)
|
||
|
{
|
||
|
Slip /= LatExtremumSlip;
|
||
|
SlipSquared = Slip * Slip;
|
||
|
SlipCubed = SlipSquared * Slip;
|
||
|
C3 = -2.0f * SlipCubed + 3.0f * SlipSquared;
|
||
|
C1 = SlipCubed - 2.0f * SlipSquared + Slip;
|
||
|
return ((C1 + C3) * LatExtremumValue);
|
||
|
}
|
||
|
else if (Slip > LatAsymptoteSlip)
|
||
|
{
|
||
|
return (LatAsymptoteValue);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Slip /= (LatAsymptoteSlip - LatExtremumSlip);
|
||
|
Slip -= LatExtremumSlip;
|
||
|
SlipSquared = Slip * Slip;
|
||
|
SlipCubed = SlipSquared * Slip;
|
||
|
C3 = -2.0f * SlipCubed + 3.0f * SlipSquared;
|
||
|
C0 = 2.0f * SlipCubed - 3.0f * SlipSquared + 1.0f;
|
||
|
return (C0 * LatExtremumValue + C3 * LatAsymptoteValue);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Retrieves important SVehicle debug information as an array of strings. That can then be dumped or displayed on HUD.
|
||
|
*/
|
||
|
simulated function GetSVehicleDebug( out Array<String> DebugInfo )
|
||
|
{
|
||
|
DebugInfo[DebugInfo.Length] = "----Vehicle----: ";
|
||
|
DebugInfo[DebugInfo.Length] = "Speed: "$VSize(Velocity)$" Unreal -- "$VSize(Velocity) * 0.0426125$" MPH";
|
||
|
if (Wheels.length > 0)
|
||
|
{
|
||
|
DebugInfo[DebugInfo.Length] = "MotorTorque: "$Wheels[0].MotorTorque;
|
||
|
}
|
||
|
DebugInfo[DebugInfo.Length] = "Throttle: "$OutputGas;
|
||
|
DebugInfo[DebugInfo.Length] = "Brake: "$OutputBrake;
|
||
|
}
|
||
|
|
||
|
defaultproperties
|
||
|
{
|
||
|
TickGroup=TG_PostAsyncWork
|
||
|
|
||
|
Begin Object Class=SkeletalMeshComponent Name=SVehicleMesh
|
||
|
RBChannel=RBCC_Vehicle
|
||
|
RBCollideWithChannels=(Default=TRUE,BlockingVolume=TRUE,GameplayPhysics=TRUE,EffectPhysics=TRUE,Vehicle=TRUE)
|
||
|
BlockActors=true
|
||
|
BlockZeroExtent=true
|
||
|
BlockRigidBody=true
|
||
|
BlockNonzeroExtent=true
|
||
|
CollideActors=true
|
||
|
bForceDiscardRootMotion=true
|
||
|
bUseSingleBodyPhysics=1
|
||
|
bNotifyRigidBodyCollision=true
|
||
|
ScriptRigidBodyCollisionThreshold=250.0
|
||
|
End Object
|
||
|
CollisionComponent=SVehicleMesh
|
||
|
Mesh=SVehicleMesh
|
||
|
Components.Add(SVehicleMesh)
|
||
|
|
||
|
BaseOffset=(Z=128)
|
||
|
CamDist=512
|
||
|
|
||
|
Physics=PHYS_RigidBody
|
||
|
bEdShouldSnap=true
|
||
|
bStatic=false
|
||
|
bCollideActors=true
|
||
|
bCollideWorld=true
|
||
|
bProjTarget=true
|
||
|
bBlockActors=true
|
||
|
bWorldGeometry=false
|
||
|
bCanBeBaseForPawns=true
|
||
|
bAlwaysRelevant=false
|
||
|
RemoteRole=ROLE_SimulatedProxy
|
||
|
bNetInitialRotation=true
|
||
|
bBlocksTeleport=TRUE
|
||
|
|
||
|
// Stay-upright constraint
|
||
|
Begin Object Class=RB_StayUprightSetup Name=MyStayUprightSetup
|
||
|
End Object
|
||
|
StayUprightConstraintSetup=MyStayUprightSetup
|
||
|
|
||
|
Begin Object Class=RB_ConstraintInstance Name=MyStayUprightConstraintInstance
|
||
|
End Object
|
||
|
StayUprightConstraintInstance=MyStayUprightConstraintInstance
|
||
|
|
||
|
// Absolute max physics speed
|
||
|
MaxSpeed=2500
|
||
|
|
||
|
// Absolute max physics angular velocity (Unreal angular units)
|
||
|
MaxAngularVelocity=75000.0
|
||
|
|
||
|
// Inertia Tensor
|
||
|
InertiaTensorMultiplier=(x=1.0,y=1.0,z=1.0)
|
||
|
|
||
|
// Initialize uprighting parameters.
|
||
|
bCanFlip=true
|
||
|
UprightLiftStrength = 225.0;
|
||
|
UprightTorqueStrength = 50.0;
|
||
|
UprightTime = 1.5;
|
||
|
bIsUprighting = false;
|
||
|
|
||
|
// Initialize sound members.
|
||
|
SquealThreshold = 250.0;
|
||
|
SquealLatThreshold=250.0f;
|
||
|
LatAngleVolumeMult=1.0f;
|
||
|
EngineStartOffsetSecs = 2.0;
|
||
|
EngineStopOffsetSecs = 1.0;
|
||
|
HeavySuspensionShiftPercent=0.5f;
|
||
|
|
||
|
RadialImpulseScaling=1.0
|
||
|
|
||
|
bInReverseMode=false
|
||
|
bEnableDebugRendering=true
|
||
|
|
||
|
ChassisMass=1500
|
||
|
|
||
|
bIsTank=FALSE
|
||
|
}
|