[Document]翻Projectile Weapon的时候发现的一些可能有用的东西
Firing Mode Definition
/************************************************************************************ * Firing Mode Definition ***********************************************************************************/ /** * This enum defines the firing type for the weapon. * EWFT_InstantHit - The weapon traces a shot to determine a hit and immediately causes an effect * EWFT_Projectile - The weapon spawns a new projectile pointed at the crosshair * EWFT_Custom - Requires a custom fire sequence */ enum EWeaponFireType { EWFT_InstantHit, EWFT_Projectile, EWFT_Custom, EWFT_None };
The Class of Projectile to spawn
/** The Class of Projectile to spawn */ var Array< class<Projectile> > WeaponProjectiles;
Returns the type of projectile to spawn
/** * Returns the type of projectile to spawn. We use a function so subclasses can * override it if needed (case in point, homing rockets). */ function class<Projectile> GetProjectileClass() { return (CurrentFireMode < WeaponProjectiles.length) ? WeaponProjectiles[CurrentFireMode] : None; }
Perform all logic associated with firing a shot
/** * FireAmmunition: Perform all logic associated with firing a shot * - Fires ammunition (instant hit or spawn projectile) * - Consumes ammunition * - Plays any associated effects (fire sound and whatnot) * * Network: LocalPlayer and Server */ simulated function FireAmmunition() { // Use ammunition to fire ConsumeAmmo( CurrentFireMode ); // Handle the different fire types switch( WeaponFireTypes[CurrentFireMode] ) { case EWFT_InstantHit: InstantFire(); break; case EWFT_Projectile: ProjectileFire(); break; case EWFT_Custom: CustomFire(); break; } NotifyWeaponFired( CurrentFireMode ); }
Fires a projectile.
/** * Fires a projectile. * Spawns the projectile, but also increment the flash count for remote client effects. * Network: Local Player and Server */ simulated function Projectile ProjectileFire() { local vector StartTrace, EndTrace, RealStartLoc, AimDir; local ImpactInfo TestImpact; local Projectile SpawnedProjectile; // tell remote clients that we fired, to trigger effects IncrementFlashCount(); if( Role == ROLE_Authority ) { // This is where we would start an instant trace. (what CalcWeaponFire uses) StartTrace = Instigator.GetWeaponStartTraceLocation(); AimDir = Vector(GetAdjustedAim( StartTrace )); // this is the location where the projectile is spawned. RealStartLoc = GetPhysicalFireStartLoc(AimDir); if( StartTrace != RealStartLoc ) { // if projectile is spawned at different location of crosshair, // then simulate an instant trace where crosshair is aiming at, Get hit info. EndTrace = StartTrace + AimDir * GetTraceRange(); TestImpact = CalcWeaponFire( StartTrace, EndTrace ); // Then we realign projectile aim direction to match where the crosshair did hit. AimDir = Normal(TestImpact.HitLocation - RealStartLoc); } // Spawn projectile SpawnedProjectile = Spawn(GetProjectileClass(), Self,, RealStartLoc); if( SpawnedProjectile != None && !SpawnedProjectile.bDeleteMe ) { SpawnedProjectile.Init( AimDir ); } // Return it up the line return SpawnedProjectile; } return None; }
returns the world location for spawning the projectile
/** * This function returns the world location for spawning the projectile, pulled in to the Pawn's collision along the AimDir direction. */ simulated native event vector GetPhysicalFireStartLoc(optional vector AimDir);
This is the default Firing State
/********************************************************************************************* * state WeaponFiring * This is the default Firing State. It's performed on both the client and the server. *********************************************************************************************/ simulated state WeaponFiring { ignores AllowSprinting; simulated function BeginState(Name PrevStateName) { local KFPerk InstigatorPerk; InstigatorPerk = GetPerk(); if( InstigatorPerk != none ) { SetZedTimeResist( InstigatorPerk.GetZedTimeModifier(self) ); } if ( bLoopingFireAnim.Length > 0 || bLoopingFireSnd.Length > 0 ) { StartLoopingFireEffects(CurrentFireMode); } super.BeginState(PrevStateName); } simulated event Tick(float DeltaTime) { Global.Tick(DeltaTime); // Stop the looping fire sound if we're in zed time and want to play single fire sounds if( bPlayingLoopingFireSnd && ShouldForceSingleFireSound() ) { StopLoopingFireSound(CurrentFireMode); } } /** * Timer event, call is set up in Weapon::TimeWeaponFiring(). * The weapon is given a chance to evaluate if another shot should be fired. * This event defines the weapon's rate of fire. */ simulated function RefireCheckTimer() { local KFPerk InstigatorPerk; InstigatorPerk = GetPerk(); if( InstigatorPerk != none ) { SetZedTimeResist( InstigatorPerk.GetZedTimeModifier(self) ); } super.RefireCheckTimer(); } simulated function EndState(Name NextStateName) { super.EndState(NextStateName); ClearZedTimeResist(); // Simulate weapon firing effects on the local client if( WorldInfo.NetMode == NM_Client ) { Instigator.WeaponStoppedFiring(self, false); } if ( bPlayingLoopingFireAnim || bPlayingLoopingFireAnim ) { StopLoopingFireEffects(CurrentFireMode); } } /** Override to continue any looping fire anims */ simulated event OnAnimEnd(AnimNodeSequence SeqNode, float PlayedTime, float ExcessTime) { local name WeaponFireAnimName; if ( WorldInfo.NetMode != NM_DedicatedServer ) { // If loop start or another event such as IronSights transition ended, restart looping fire anim. if ( bPlayingLoopingFireAnim ) { WeaponFireAnimName = GetLoopingFireAnim(CurrentFireMode); if ( WeaponFireAnimName != '' ) { PlayAnimation(WeaponFireAnimName, MySkelMesh.GetAnimLength(WeaponFireAnimName), true, 0.f); } } } } /** don't allow for a pickup to switch the weapon */ simulated function bool DenyClientWeaponSet() { return true; } /** Gets the current animation rate, scaled or not */ simulated function float GetThirdPersonAnimRate() { local KFPerk CurrentPerk; local float ScaledRate; ScaledRate = 1.0f; CurrentPerk = GetPerk(); if( CurrentPerk != none ) { CurrentPerk.ModifyRateOfFire( ScaledRate, self ); } return 1.f / ScaledRate; } }
Adjusts weapon aiming direction
/** * Adjusts weapon aiming direction. * Gives controller a chance to modify the aiming of the pawn. For example aim error, auto aiming, adhesion, AI help... * Requested by weapon prior to firing. * * Completely overrides super to support free-aim hip shots going where the muzzle is pointed (modified block is marked) * * @param W, weapon about to fire * @param StartFireLoc, world location of weapon fire start trace, or projectile spawn loc. * @param BaseAimRot, original aiming rotation without any modifications. */ function Rotator GetAdjustedAimFor( Weapon W, vector StartFireLoc ) { local vector FireDir, HitLocation, HitNormal; local actor BestTarget, HitActor; local float bestAim, bestDist; local bool bNoAimCorrection, bInstantHit; local rotator BaseAimRot; bInstantHit = ( W == None || W.bInstantHit ); BaseAimRot = (Pawn != None) ? Pawn.GetBaseAimRotation() : Rotation; if( W != none ) { // Add in the weapon buffer rotation for recoil/sway BaseAimRot += WeaponBufferRotation; } // Clients are done after WeaponBufferRotation unless aim correction is on if( Role < ROLE_Authority && !AimingHelp(bInstantHit) ) { return BaseAimRot; } FireDir = vector(BaseAimRot); HitActor = Trace(HitLocation, HitNormal, StartFireLoc + W.GetTraceRange() * FireDir, StartFireLoc, true); if ( (HitActor != None) && HitActor.bProjTarget ) { BestTarget = HitActor; bNoAimCorrection = true; BestDist = VSize(BestTarget.Location - Pawn.Location); } else { // adjust aim based on FOV bestAim = 0.90; if ( AimingHelp(bInstantHit) ) { bestAim = AimHelpDot(bInstantHit); } else if ( bInstantHit ) bestAim = 1.0; BestTarget = PickAimAtTarget(bestAim, bestDist, FireDir, StartFireLoc, W.WeaponRange); if ( BestTarget == None ) { return BaseAimRot; } } ShotTarget = Pawn(BestTarget); if ( !AimingHelp(bInstantHit) ) { return BaseAimRot; } if ( !bNoAimCorrection && W != None ) { ProcessAimCorrection(ShotTarget, KFWeapon(W), StartFireLoc, BaseAimRot); } return BaseAimRot; }
Specific & Simplified