UT3 Weapons Tutorial - Enforcer - Epic Wiki

# UT3 Weapons Tutorial - Enforcer

# Contents

# UT3 Weapons Tutorial - Enforcer

This tutorial will show you how to create Enforcer from Unreal Tournament 3 using C++ only.

NOTE:

  • UT has just upgraded to UE 4.2.1, this tutorial will be verified for compatibility shortly.

# Requirements

Some existing C++ & Unreal Engine knowledge is needed.

# Features

  • Firing multiple projectiles in a burst
  • Dual weapons

# Notes

  • When overriding a function in subclass always add a definition to the header file as well.
  • Functions with BlueprintNativeEvent attribute generate additional virtual function called "FunctionName_Implementation". Override the _Implementation one instead.
  • Code snippets are located in grey expandable boxes. Click Expand on the right to see the code.
  • Yellow lines in code snippets highlight only the code that needs to be changed.

# Contact

--Neai (talk) 17:49, 30 June 2014 (UTC)

# Enforcer

We'll start by defining what features we want to implement:

# Primary Fire

  1. Standard hitscan

# Secondary Fire

  1. Fire burst of 3 hitscan shots

# Implementation

To implement such projectile weapon we should create subclasses of AUTWeapon, UUTWeaponStateFiring, UUTDamageType and AUTWeaponAttachment.

# Creating Enforcer Classes

Create classes for all the elements of Enforcer:

  1. Weapon
    1. Create subclass of AUTWeapon called AUTWeap_Enforcer
  2. 3rd person weapon attachment
    1. Create subclass of AUTWeaponAttachment called AUTAttachment_Enforcer
  3. Burst firing mode
    1. Create subclass of UUTWeaponStateFiring called UUTWeaponStateFiringBurst
  4. Damage Types
    1. Create subclass of UUTDamageType called UTDmgType_Enforcer
    2. Create subclass of UUTDamageType called UTDmgType_DualEnforcers

# Setting up weapon asset references

We will link all the parts together, add asset references and setup basic properties.

AUTWeap_Enforcer.cpp - Setup asset references

  1. #include "UnrealTournament.h"

  2. #include "UTWeap_Enforcer.h"

  3. #include "UTAttachment_Enforcer.h"

  4. #include "UTDmgType_Enforcer.h"

  5. #include "UTDmgType_DualEnforcer.h"

  6. AUTWeap_Enforcer::AUTWeap_Enforcer(const class FPostConstructInitializeProperties& PCIP)

  7. : Super(PCIP)

  8. {

  9. // Structure to hold one-time initialization
    
  10. struct FConstructorStatics
    
  11. {
    
  12. 	ConstructorHelpers::FObjectFinder<USkeletalMesh\> SkeletalMesh;
    
  13. 	ConstructorHelpers::FObjectFinder<UAnimBlueprintGeneratedClass\> AnimBlueprintGeneratedClass;
    
  14. 	ConstructorHelpers::FObjectFinder<UParticleSystem\> MuzzleFlash;
    
  15. 	ConstructorHelpers::FObjectFinder<USoundCue\> FireSound0;
    
  16. 	ConstructorHelpers::FObjectFinder<USoundCue\> BurstFireSound1;
    
  17. 	ConstructorHelpers::FObjectFinder<UAnimMontage\> FireAnimation0;
    
  18. 	ConstructorHelpers::FObjectFinder<UAnimMontage\> BurstFireAnimation1;
    
  19. 	ConstructorHelpers::FObjectFinder<UAnimMontage\> BringUpAnim;
    
  20. 	ConstructorHelpers::FObjectFinder<UAnimMontage\> PutDownAnim;
    
  21. 	ConstructorHelpers::FObjectFinder<UParticleSystem\> FireEffect0;
    
  22. 	ConstructorHelpers::FObjectFinder<USoundCue\> PickupSound;
    
  23. 	FConstructorStatics()
    
  24. 		: SkeletalMesh(TEXT("SkeletalMesh'/Game/RestrictedAssets/Proto/UT3\_Weapons/WP\_Enforcers/Meshes/SK\_WP\_Enforcers\_1P.SK\_WP\_Enforcers\_1P'"))
    
  25. 		, AnimBlueprintGeneratedClass(TEXT("AnimBlueprintGeneratedClass'/Game/RestrictedAssets/Proto/UT3\_Weapons/WP\_Enforcers/Anims/Enforcer\_AnimBP.Enforcer\_AnimBP\_C'"))
    
  26. 		, MuzzleFlash(TEXT("ParticleSystem'/Game/RestrictedAssets/Proto/UT3\_Weapons/WP\_Enforcers/Effects/P\_WP\_Enforcers\_MuzzleFlash.P\_WP\_Enforcers\_MuzzleFlash'"))
    
  27. 		, FireSound0(TEXT("SoundCue'/Game/RestrictedAssets/Proto/UT3\_Weapons/WP\_Enforcers/Audio/CUE/A\_Weapon\_Enforcer\_Fire\_Cue.A\_Weapon\_Enforcer\_Fire\_Cue'"))
    
  28. 		, BurstFireSound1(TEXT("SoundCue'/Game/RestrictedAssets/Proto/UT3\_Weapons/WP\_Enforcers/Audio/CUE/A\_Weapon\_Enforcer\_AltFire\_Cue.A\_Weapon\_Enforcer\_AltFire\_Cue'"))
    
  29. 		, FireAnimation0(TEXT("AnimMontage'/Game/RestrictedAssets/Proto/UT3\_Weapons/WP\_Enforcers/Anims/Enforcer\_ShootSingle\_Montage.Enforcer\_ShootSingle\_Montage'"))
    
  30. 		, BurstFireAnimation1(TEXT("AnimMontage'/Game/RestrictedAssets/Proto/UT3\_Weapons/WP\_Enforcers/Anims/Enforcer\_ShootSecondary\_Montage.Enforcer\_ShootSecondary\_Montage'"))
    
  31. 		, BringUpAnim(TEXT("AnimMontage'/Game/RestrictedAssets/Proto/UT3\_Weapons/WP\_Enforcers/Anims/Enforcer\_Equip.Enforcer\_Equip'"))
    
  32. 		, PutDownAnim(TEXT("AnimMontage'/Game/RestrictedAssets/Proto/UT3\_Weapons/WP\_Enforcers/Anims/Enforcer\_Putdown.Enforcer\_Putdown'"))
    
  33. 		, FireEffect0(TEXT("ParticleSystem'/Game/RestrictedAssets/Proto/UT3\_Weapons/WP\_Enforcers/Effects/P\_WP\_Enforcers\_Tracer.P\_WP\_Enforcers\_Tracer'"))
    
  34. 		, PickupSound(TEXT("SoundCue'/Game/RestrictedAssets/Proto/UT3\_Pickups/Audio/Weapons/Cue/A\_Pickup\_Weapons\_Enforcer\_Cue.A\_Pickup\_Weapons\_Enforcer\_Cue'"))
    
  35. 	{
    
  36. 	}
    
  37. };
    
  38. static FConstructorStatics ConstructorStatics;
    
  39. Mesh\-\>SkeletalMesh \= ConstructorStatics.SkeletalMesh.Object;
    
  40. Mesh\-\>AnimBlueprintGeneratedClass \= ConstructorStatics.AnimBlueprintGeneratedClass.Object;
    
  41. Mesh\-\>RelativeLocation \= FVector(\-30, 0, \-0);
    
  42. TSubobjectPtr<UParticleSystemComponent\> MuzzleComponent \= PCIP.CreateDefaultSubobject<UParticleSystemComponent\>(this, TEXT("Enforcer-Muzzle"));
    
  43. MuzzleComponent\-\>Template \= ConstructorStatics.MuzzleFlash.Object;
    
  44. MuzzleComponent\-\>AttachTo(Mesh, FName(TEXT("MuzzleFlashSocket")));
    
  45. // Visual
    
  46. MuzzleFlash.SetNumZeroed(2);
    
  47. MuzzleFlash\[0\] \= MuzzleComponent;
    
  48. MuzzleFlash\[1\] \= MuzzleComponent;
    
  49. AttachmentType \= AUTAttachment\_Enforcer::StaticClass();
    
  50. BringUpAnim \= ConstructorStatics.BringUpAnim.Object;
    
  51. PutDownAnim \= ConstructorStatics.PutDownAnim.Object;
    
  52. FireAnimation.SetNumZeroed(1);
    
  53. FireAnimation\[0\] \= ConstructorStatics.FireAnimation0.Object;
    
  54. FireEffect.SetNumZeroed(2);
    
  55. FireEffect\[0\] \= ConstructorStatics.FireEffect0.Object;
    
  56. FireEffect\[1\] \= ConstructorStatics.FireEffect0.Object;
    
  57. // Sounds
    
  58. FireSound.SetNumZeroed(1);
    
  59. FireSound\[0\] \= ConstructorStatics.FireSound0.Object;
    
  60. PickupSound \= ConstructorStatics.PickupSound.Object;
    
  61. }

AUTAttachment_Enforcer.cpp - Setup asset references

  1. AUTAttachment_Enforcer::AUTAttachment_Enforcer(const class FPostConstructInitializeProperties& PCIP)

  2.  : Super(PCIP)
    
  3. {

  4.  // Structure to hold one-time initialization
    
  5.  struct FConstructorStatics
    
  6.  {
    
  7.  	ConstructorHelpers::FObjectFinder<USkeletalMesh\> SkeletalMesh;
    
  8.  	FConstructorStatics()
    
  9.  		: SkeletalMesh(TEXT("SkeletalMesh'/Game/RestrictedAssets/Proto/UT3\_Weapons/WP\_Enforcers/Meshes/SK\_WP\_Enforcer\_3P\_Mid.SK\_WP\_Enforcer\_3P\_Mid'"))
    
  10. 	{
    
  11. 	}
    
  12. };
    
  13. static FConstructorStatics ConstructorStatics;
    
  14. Mesh\-\>SkeletalMesh \= ConstructorStatics.SkeletalMesh.Object;
    
  15. }

# Weapon firing properties

We're going to use weapon properties from UT3. Set them in constructors:

AUTWeap_Enforcer.cpp - Add weapon firing properties to constructor

  1.  ProjClass.SetNumZeroed(0);
    
  2.  FInstantHitDamageInfo PrimaryFireInfo;
    
  3.  PrimaryFireInfo.Momentum \= 1000 \* UT3\_TO\_UT4\_SCALE;
    
  4.  PrimaryFireInfo.Damage \= 20;
    
  5.  PrimaryFireInfo.DamageType \= UUTDmgType\_Enforcer::StaticClass();
    
  6.  FInstantHitDamageInfo SecondaryFireInfo;
    
  7.  SecondaryFireInfo.Momentum \= 1000 \* UT3\_TO\_UT4\_SCALE;
    
  8. SecondaryFireInfo.Damage \= 20;
    
  9. SecondaryFireInfo.DamageType \= UUTDmgType\_Enforcer::StaticClass();
    
  10. InstantHitInfo.SetNumZeroed(2);
    
  11. InstantHitInfo\[0\] \= PrimaryFireInfo;
    
  12. InstantHitInfo\[1\] \= SecondaryFireInfo;
    
  13. FireInterval.SetNumZeroed(2);
    
  14. FireInterval\[0\] \= 0.5;
    
  15. FireInterval\[1\] \= 1.0;
    
  16. AmmoCost.SetNumZeroed(2);
    
  17. AmmoCost\[0\] \= 1;
    
  18. AmmoCost\[1\] \= 1;
    
  19. Ammo \= 20;
    
  20. MaxAmmo \= 50;
    
  21. FireOffset \= FVector(50, 0, 0);
    
  22. Group \= 4;
    

# Camera Shake

Add camera shake to AUTWeapon. If you already have added this code before, just add default properties for Enforcer.

AUTWeapon.h - Add camera shake properties and function

  1.  /\*\* delay between firing and camera shake being played \*/
    
  2.  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category \= "Weapon")
    
  3.  TArray<float\> CameraShakeDelay;
    
  4.  /\*\* how strong camera shake should be \*/
    
  5.  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category \= "Weapon")
    
  6.  TArray<float\> CameraShakeScale;
    
  7. /\*\* camera shake type \*/
    
  8. UPROPERTY(EditAnywhere, BlueprintReadWrite, Category \= "Weapon")
    
  9. TArray< TSubclassOf<class UCameraShake\> \> CameraShakeType;
    
  10. /\*\* Plays camera shake immediately \*/
    
  11. UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category \= "Weapon")
    
  12. void PlayCameraShake();
    

AUTWeapon.cpp - Add PlayCameraShake() implementation

  1. void AUTWeapon::PlayCameraShake_Implementation()

  2. {

  3.  if (UTOwner !\= NULL)
    
  4.  {
    
  5.  	AUTPlayerController\* PC \= Cast<AUTPlayerController\>(UTOwner\-\>Controller);
    
  6.  	if (PC !\= NULL)
    
  7.  	{
    
  8.  		// Play camera shake
    
  9.  		if (CameraShakeType.IsValidIndex(CurrentFireMode) && CameraShakeType\[CurrentFireMode\] !\= NULL && CameraShakeScale.IsValidIndex(CurrentFireMode))
    
  10. 		{
    
  11. 			PC\-\>ClientPlayCameraShake(CameraShakeType\[CurrentFireMode\], CameraShakeScale\[CurrentFireMode\]);
    
  12. 		}
    
  13. 	}
    
  14. }
    
  15. }

AUTWeapon.cpp - Override PlayFiringEffects() so it calls our PlayCameraShake() function

  1. void AUTWeapon::PlayFiringEffects()

  2. {

  3.  Super::PlayFiringEffects();
    
  4.  // Play camera shake after optional delay
    
  5.  if (CameraShakeDelay.IsValidIndex(CurrentFireMode) && CameraShakeDelay\[CurrentFireMode\] \> 0)
    
  6.  {
    
  7.  	GetWorldTimerManager().SetTimer(this, &AUTWeapon::PlayCameraShake, CameraShakeDelay\[CurrentFireMode\], false);
    
  8.  }
    
  9. else
    
  10. {
    
  11. 	PlayCameraShake();
    
  12. }
    
  13. }

AUTWeap_Enforcer.cpp - Add CameraShake assets & default properties to constructor

  1.  struct FConstructorStatics
    
  2.  {
    
  3.  	//...
    
  4.  	ConstructorHelpers::FClassFinder<UCameraShake\> CameraShakeType0;
    
  5.  	ConstructorHelpers::FClassFinder<UCameraShake\> CameraShakeType1;
    
  6.  	FConstructorStatics()
    
  7.  		//...
    
  8.  		, CameraShakeType0(TEXT("BlueprintGeneratedClass'/Game/RestrictedAssets/Blueprints/WIP/Nick/CameraAnims/Camerashake2.Camerashake2\_C'"))
    
  9.  		, CameraShakeType1(TEXT("BlueprintGeneratedClass'/Game/RestrictedAssets/Blueprints/WIP/Nick/CameraAnims/Camerashake2.Camerashake2\_C'"))
    
  10. 	{
    
  11. 	}
    
  12. };
    
  13. //...
    
  14. CameraShakeType.SetNumZeroed(2);
    
  15. CameraShakeType\[0\] \= ConstructorStatics.CameraShakeType0.Class;
    
  16. CameraShakeType\[1\] \= ConstructorStatics.CameraShakeType1.Class;
    
  17. CameraShakeDelay.SetNumZeroed(2);
    
  18. CameraShakeDelay\[0\] \= 0.f;
    
  19. CameraShakeDelay\[1\] \= 0.f;
    
  20. CameraShakeScale.SetNumZeroed(2);
    
  21. CameraShakeScale\[0\] \= 1.f;
    
  22. CameraShakeScale\[1\] \= 1.f;
    

# Adding custom weapon firing state

In the Enforcer's constructor we will disable creation of default weapon firing states and create our own ones instead.

AUTWeap_Enforcer.cpp - Create our own weapon firing states

  1. AUTWeap_Enforcer::AUTWeap_Enforcer(const class FPostConstructInitializeProperties& PCIP)

  2. : Super(PCIP

  3. .DoNotCreateDefaultSubobject(TEXT("FiringState0"))

  4. .DoNotCreateDefaultSubobject(TEXT("FiringState1"))

  5. )

  6. {

  7.  //...
    
  8.  if (!GCompilingBlueprint)
    
  9. {
    
  10. 	UUTWeaponStateFiring\* PrimaryState \= PCIP.CreateDefaultSubobject<UUTWeaponStateFiring, UUTWeaponStateFiring\>(this, FName(TEXT("Enforcer-WeaponState0")), false, false, false);
    
  11. 	if (PrimaryState)
    
  12. 	{
    
  13. 		FiringState.Add(PrimaryState);
    
  14. 		FiringStateType.Add(PrimaryState\-\>StaticClass());
    
  15. 	}
    
  16. 	UUTWeaponStateFiringBurst\* AlternateState \= PCIP.CreateDefaultSubobject<UUTWeaponStateFiringBurst, UUTWeaponStateFiringBurst\>(this, FName(TEXT("Enforcer-WeaponState1")), false, false, false);
    
  17. 	if (AlternateState)
    
  18. 	{
    
  19. 		FiringState.Add(AlternateState);
    
  20. 		FiringStateType.Add(AlternateState\-\>StaticClass());
    
  21. 	}
    
  22. }
    
  23. }

# Implementing burst firing state

Weapon firing works as follows (simplified):

  1. When user holds fire and weapon can fire, weapon goes to WeaponStateFiring state, WeaponStateFiring::BeginState() is called
  2. WeaponStateFiring::BeginState() fires a shot and starts a RefireCheckTimer. Weapon can't fire again nor be switched away until this timer finishes.
  3. When RefireCheckTimer times out, weapon checks its state. Firing ends when:
    1. There is a pending weapon change
    2. User no longer presses fire
    3. There is no more ammo
  4. Otherwise weapon fires again and timer is restarted.

To create a burst firing mode, we're going to count the shots and modify RefireCheckTimer so it will automatically fire again until burst completes.

UUTWeaponFiringStateBurst.h - Add burst count variables

  1.  int32 BurstRounds;
    
  2.  int32 BurstRoundsFired;
    

UUTWeaponFiringStateBurst.cpp - Add default values for burst count variables in constructor

  1. UUTWeaponStateFiringBurst::UUTWeaponStateFiringBurst(const class FPostConstructInitializeProperties& PCIP)

  2.  : Super(PCIP)
    
  3. {

  4.  BurstRounds \= 3;
    
  5.  BurstRoundsFired \= 0;
    
  6. }

UUTWeaponFiringStateBurst.cpp - Override FireShot() to increment burst rounds counter

  1. void UUTWeaponStateFiringBurst::FireShot()

  2. {

  3.  Super::FireShot();
    
  4.  // Increment number of burst rounds fired
    
  5.  ++BurstRoundsFired;
    
  6. }

UUTWeaponFiringStateBurst.cpp - Override RefireCheckTimer() so it will automatically fire remaining burst rounds as long as there is ammo.

  1. void UUTWeaponStateFiringBurst::RefireCheckTimer()

  2. {

  3.  UE\_LOG(LogTemp, Warning, TEXT("%s : BurstRoundsFired:%d"), TEXT(\_\_FUNCTION\_\_), BurstRoundsFired);
    
  4.  if (BurstRoundsFired < BurstRounds)
    
  5.  {
    
  6.  	if (!GetOuterAUTWeapon()\-\>HasAmmo(GetOuterAUTWeapon()\-\>GetCurrentFireMode()))
    
  7.  	{
    
  8.  		GetOuterAUTWeapon()\-\>GotoActiveState();
    
  9.  	}
    
  10. 	else
    
  11. 	{
    
  12. 		FireShot();
    
  13. 	}
    
  14. }
    
  15. else
    
  16. {
    
  17. 	BurstRoundsFired \= 0;
    
  18. 	Super::RefireCheckTimer();
    
  19. }
    
  20. }

Notice that when burst is finished we reset the burst counter.

UUTWeaponFiringStateBurst.cpp - Override BeginState() to reset burst counter whenever weapon goes to firing state

  1. void UUTWeaponStateFiringBurst::BeginState(const UUTWeaponState* PrevState)

  2. {

  3.  BurstRoundsFired \= 0;
    
  4.  Super::BeginState(PrevState);
    
  5. }

# Using faster FireInterval for burst firing

So far the burst works but we want to have a fast refire time for burst shots and longer delay between bursts.

UUTWeaponFiringStateBurst.h - Add BurstRefireRate variable

  1.  float BurstRefireRate;
    

UUTWeaponFiringStateBurst.cpp - Set default value for BurstRefireRate in constructor

  1.  BurstRefireRate \= 0.15;
    

UUTWeaponFiringStateBurst.cpp - Override UpdateTiming() to use custom shorter refire time if next shot is a part of burst

  1. void UUTWeaponStateFiringBurst::UpdateTiming()

  2. {

  3.  // TODO: we should really restart the timer at the percentage it currently is, but FTimerManager has no facility to do this
    
  4.  // If the next round will be a part of this burst, change fire rate to burst rate, otherwise reset it to default.
    
  5.  float NextRefireRate \= (BurstRoundsFired < BurstRounds)
    
  6.  	? BurstRefireRate
    
  7.  	: GetOuterAUTWeapon()\-\>GetRefireTime(GetOuterAUTWeapon()\-\>GetCurrentFireMode());
    
  8.  GetOuterAUTWeapon()\-\>GetWorldTimerManager().SetTimer(this, &UUTWeaponStateFiring::RefireCheckTimer, NextRefireRate, true);
    
  9. }

UUTWeaponFiringStateBurst.cpp - Modify FireShot() to update refire timer after each shot

  1. void UUTWeaponStateFiringBurst::FireShot()

  2. {

  3.  Super::FireShot();
    
  4.  // Increment number of burst rounds fired
    
  5.  ++BurstRoundsFired;
    
  6.  // Burst fire uses different firing rate, update according to current state
    
  7.  UpdateTiming();
    
  8. }

# Customizing the burst properties per-weapon

Should we want to create a blueprint of this weapon to tweak the properties, we need to setup the properties in AUTWeap_Enforer. Weapon state objects are not supported by editor property GUI yet.

AUTWeap_Enforcer.h - Add properties to Enforcer

  1.  /\*\* Number of rounds to fire in a burst \*/
    
  2.  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category \= "Enforcer")
    
  3.  int32 BurstRounds;
    
  4.  /\*\* Time between each round in a burst \*/
    
  5.  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category \= "Enforcer")
    
  6.  float BurstRefireRate;
    

AUTWeap_Enforcer.cpp - Set default properties in Enforcer constructor

  1. AUTWeap_Enforcer::AUTWeap_Enforcer(const class FPostConstructInitializeProperties& PCIP)

  2. : Super(PCIP

  3. .DoNotCreateDefaultSubobject(TEXT("FiringState0"))

  4. .DoNotCreateDefaultSubobject(TEXT("FiringState1"))

  5. )

  6. {

  7.  //...
    
  8.  BurstRounds \= 3;
    
  9. BurstRefireRate \= 0.15;
    
  10. if (!GCompilingBlueprint)
    
  11. {
    
  12. 	UUTWeaponStateFiring\* PrimaryState \= PCIP.CreateDefaultSubobject<UUTWeaponStateFiring, UUTWeaponStateFiring\>(this, FName(TEXT("Enforcer-WeaponState0")), false, false, false);
    
  13. 	if (PrimaryState)
    
  14. 	{
    
  15. 		FiringState.Add(PrimaryState);
    
  16. 		FiringStateType.Add(PrimaryState\-\>StaticClass());
    
  17. 	}
    
  18. 	UUTWeaponStateFiringBurst\* AlternateState \= PCIP.CreateDefaultSubobject<UUTWeaponStateFiringBurst, UUTWeaponStateFiringBurst\>(this, FName(TEXT("Enforcer-WeaponState1")), false, false, false);
    
  19. 	if (AlternateState)
    
  20. 	{
    
  21. 		AlternateState\-\>BurstRounds \= BurstRounds;
    
  22. 		AlternateState\-\>BurstRefireRate \= BurstRefireRate;
    
  23. 		FiringState.Add(AlternateState);
    
  24. 		FiringStateType.Add(AlternateState\-\>StaticClass());
    
  25. 	}
    
  26. }
    
  27. }

# Burst animations & sounds

We have an animation & firing sound that covers entire burst. Lets add a function that will play animation & sound when weapon first starts firing, and when it refires after completed firing sequence.

AUTWeapon.h - Add properties & functions

  1.  /\*\* AnimMontage to play when weapon initially starts firing \*/
    
  2.  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category \= "Weapon")
    
  3.  TArray<UAnimMontage\*\> StartedFireAnimation;
    
  4.  /\*\* AnimMontage to play when weapon completes firing sequence and starts firing another one \*/
    
  5.  UPROPERTY(EditAnywhere, BlueprintReadWrite, Category \= "Weapon")
    
  6.  TArray<UAnimMontage\*\> ContinuedFireAnimation;
    
  7.  /\*\* Sound to play when weapon initially starts firing \*/
    
  8. UPROPERTY(EditAnywhere, BlueprintReadWrite, Category \= "Weapon")
    
  9. TArray<USoundBase\*\> StartedFireSound;
    
  10. /\*\* Sound to play when weapon completes firing sequence and starts firing another one \*/
    
  11. UPROPERTY(EditAnywhere, BlueprintReadWrite, Category \= "Weapon")
    
  12. TArray<USoundBase\*\> ContinuedFireSound;
    
  13. /\*\* Called when weapon initially starts firing \*/
    
  14. UFUNCTION(BlueprintCallable, Category \= "Weapon")
    
  15. virtual void PlayStartedFiringEffects();
    
  16. /\*\* Called when weapon completes firing sequence and starts firing another one \*/
    
  17. UFUNCTION(BlueprintCallable, Category \= "Weapon")
    
  18. virtual void PlayContinuedFiringEffects();
    

AUTWeapon.cpp - Add PlayStartedFiringEffects() & PlayContinuedFiringEffects() implementation

  1. void AUTWeapon::PlayStartedFiringEffects()

  2. {

  3.  if (GetNetMode() !\= NM\_DedicatedServer && UTOwner !\= NULL)
    
  4.  {
    
  5.  	// try and play the sound if specified
    
  6.  	if (StartedFireSound.IsValidIndex(CurrentFireMode) && StartedFireSound\[CurrentFireMode\] !\= NULL)
    
  7.  	{
    
  8.  		UUTGameplayStatics::UTPlaySound(GetWorld(), StartedFireSound\[CurrentFireMode\], UTOwner, SRT\_AllButOwner);
    
  9.  	}
    
  10. 	// Play animation
    
  11. 	if (StartedFireAnimation.IsValidIndex(CurrentFireMode) && StartedFireAnimation\[CurrentFireMode\] !\= NULL)
    
  12. 	{
    
  13. 		UAnimInstance\* AnimInstance \= Mesh\-\>GetAnimInstance();
    
  14. 		if (AnimInstance !\= NULL)
    
  15. 		{
    
  16. 			AnimInstance\-\>Montage\_Play(StartedFireAnimation\[CurrentFireMode\], 1.f);
    
  17. 		}
    
  18. 	}
    
  19. }
    
  20. }

  21. void AUTWeapon::PlayContinuedFiringEffects()

  22. {

  23. if (GetNetMode() !\= NM\_DedicatedServer && UTOwner !\= NULL)
    
  24. {
    
  25. 	// try and play the sound if specified
    
  26. 	if (ContinuedFireSound.IsValidIndex(CurrentFireMode) && ContinuedFireSound\[CurrentFireMode\] !\= NULL)
    
  27. 	{
    
  28. 		UUTGameplayStatics::UTPlaySound(GetWorld(), ContinuedFireSound\[CurrentFireMode\], UTOwner, SRT\_AllButOwner);
    
  29. 	}
    
  30. 	// Play animation
    
  31. 	if (ContinuedFireAnimation.IsValidIndex(CurrentFireMode) && ContinuedFireAnimation\[CurrentFireMode\] !\= NULL)
    
  32. 	{
    
  33. 		UAnimInstance\* AnimInstance \= Mesh\-\>GetAnimInstance();
    
  34. 		if (AnimInstance !\= NULL)
    
  35. 		{
    
  36. 			AnimInstance\-\>Montage\_Play(ContinuedFireAnimation\[CurrentFireMode\], 1.f);
    
  37. 		}
    
  38. 	}
    
  39. }
    
  40. }

AUTWeapon.cpp - Modify OnStartedFiring_Implementation() & OnContinuedFiring_Implementation() to make them call our functions

  1. void AUTWeapon::OnStartedFiring_Implementation()

  2. {

  3.  PlayStartedFiringEffects();
    
  4. }

  5. void AUTWeapon::OnContinuedFiring_Implementation()

  6. {

  7.  PlayContinuedFiringEffects();
    
  8. }

# Dual weapons

TODO

# Source Code

Retrieved from "https://wiki.unrealengine.com/index.php?title=UT3_Weapons_Tutorial_-_Enforcer&oldid=10611"

Categories: