Here is my character code :
// Fill out your copyright notice in the Description page of Project Settings.
#include “TOUnderFire.h”
#include “TOCharacter.h”
#include “UnrealNetwork.h”
#include “Player/BasePlayerState.h”
// Sets default values
ATOCharacter::ATOCharacter(const FObjectInitializer & ObjectInitializer)
{
// Set size for collision capsule
GetCapsuleComponent()->InitCapsuleSize(55.f, 96.0f);
// set our turn rates for input
BaseTurnRate = 45.f;
BaseLookUpRate = 45.f;
// Create a CameraComponent
FirstPersonCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
FirstPersonCameraComponent->SetupAttachment(GetCapsuleComponent());
//FirstPersonCameraComponent->RelativeLocation = FVector(-39.56f, 1.75f, 64.f); // Position the camera
FirstPersonCameraComponent->bUsePawnControlRotation = true;
// Create a mesh component that will be used when being viewed from a '1st person' view (when controlling this pawn)
Mesh1P = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("CharacterMesh1P"));
Mesh1P->SetOnlyOwnerSee(true);
Mesh1P->SetupAttachment(GetCapsuleComponent());
Mesh1P->bCastDynamicShadow = false;
Mesh1P->CastShadow = false;
//Mesh1P->RelativeRotation = FRotator(1.9f, -19.19f, -160.f);
//Mesh1P->RelativeLocation = FVector(-0.5f, -4.4f, -155.7f);
/*// Create a gun mesh component
FP_Gun = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("FP_Gun"));
FP_Gun->SetOnlyOwnerSee(true); // only the owning player will see this mesh
FP_Gun->bCastDynamicShadow = false;
FP_Gun->CastShadow = false;
// FP_Gun->SetupAttachment(Mesh1P, TEXT("GripPoint"));
FP_Gun->SetupAttachment(RootComponent);
// Create a gun mesh component for 3rdPersonn
TP_Gun = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("TP_Gun"));
TP_Gun-> SetOnlyOwnerSee(false);// only the others player will see this mesh
TP_Gun->bCastDynamicShadow = true;
TP_Gun->CastShadow = true;
// FP_Gun->SetupAttachment(Mesh1P, TEXT("GripPoint"));
TP_Gun->SetupAttachment(GetMesh());
*/
FP_MuzzleLocation = CreateDefaultSubobject<USceneComponent>(TEXT("MuzzleLocation"));
//FP_MuzzleLocation->SetupAttachment(FP_Gun);
FP_MuzzleLocation->SetRelativeLocation(FVector(0.2f, 48.4f, -10.6f));
HealthMax = 100;
}
void ATOCharacter::PostInitializeComponents()
{
Super::PostInitializeComponents();
if (Role == ROLE_Authority)
{
Health = HealthMax;
SpawnDefaultInventory();
}
// set initial mesh visibility (3rd person view)
/*UpdatePawnMeshes();
// create material instance for setting team colors (3rd person view)
for (int32 iMat = 0; iMat < GetMesh()->GetNumMaterials(); iMat++)
{
MeshMIDs.Add(GetMesh()->CreateAndSetMaterialInstanceDynamic(iMat));
}*/
// play respawn effects
if (GetNetMode() != NM_DedicatedServer)
{
if (RespawnFX)
{
UGameplayStatics::SpawnEmitterAtLocation(this, RespawnFX, GetActorLocation(), GetActorRotation());
}
if (RespawnSound)
{
UGameplayStatics::PlaySoundAtLocation(this, RespawnSound, GetActorLocation());
}
}
}
void ATOCharacter::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
}
void ATOCharacter::Destroyed()
{
Super::Destroyed();
DestroyInventory();
}
void ATOCharacter::BeginPlay()
{
// Call the base class
Super::BeginPlay();
//Attach gun mesh component to Skeleton, doing it here because the skeleton is not yet created in the constructor
//FP_Gun->AttachToComponent(Mesh1P, FAttachmentTransformRules(EAttachmentRule::SnapToTarget, true), TEXT("WeaponSocket"));
Mesh1P->SetHiddenInGame(false, true);
//TP_Gun->AttachToComponent(GetMesh(), FAttachmentTransformRules(EAttachmentRule::SnapToTarget, true), TEXT("WeaponSocket"));
GetMesh()->SetHiddenInGame(false, true);
Reset();
}
//////////////////////////////////////////////////////////////////////////////////////////
//Mov & Inputs
void ATOCharacter::MoveForward(float Value)
{
if (Value != 0.0f)
{
// add movement in that direction
AddMovementInput(GetActorForwardVector(), Value);
}
}
void ATOCharacter::MoveRight(float Value)
{
if (Value != 0.0f)
{
// add movement in that direction
AddMovementInput(GetActorRightVector(), Value);
}
}
void ATOCharacter::TurnAtRate(float Rate)
{
// calculate delta for this frame from the rate information
AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds());
}
void ATOCharacter::LookUpAtRate(float Rate)
{
// calculate delta for this frame from the rate information
AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds());
}
// Called to bind functionality to input
void ATOCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
// set up gameplay key bindings
check(PlayerInputComponent);
PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);
PlayerInputComponent->BindAxis("MoveForward", this, &ATOCharacter::MoveForward);
PlayerInputComponent->BindAxis("MoveRight", this, &ATOCharacter::MoveRight);
PlayerInputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
PlayerInputComponent->BindAxis("TurnRate", this, &ATOCharacter::TurnAtRate);
PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
PlayerInputComponent->BindAxis("LookUpRate", this, &ATOCharacter::LookUpAtRate);
PlayerInputComponent->BindAction("NextWeapon", IE_Pressed, this, &ATOCharacter::OnNextWeapon);
PlayerInputComponent->BindAction("PrevWeapon", IE_Pressed, this, &ATOCharacter::OnPrevWeapon);
}
//////////////////////////////////////////////////////////////////////////////
//
void ATOCharacter::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
// only to local owner: weapon change requests are locally instigated, other clients don't need it
DOREPLIFETIME_CONDITION(ATOCharacter, Inventory, COND_OwnerOnly);
// everyone
DOREPLIFETIME(ATOCharacter, Health);
}
void ATOCharacter::Reset()
{
Health = HealthMax;
DamageInfoArray.Empty();
}
void ATOCharacter::OnRep_CurrentWeapon(AItems* LastWeapon)
{
SetCurrentWeapon(CurrentWeapon, LastWeapon);
}
ETeam_Enum ATOCharacter::GetTeam() const
{
ABasePlayerState * PS = Cast<ABasePlayerState>(PlayerState);
if (PS)
{
return PS->GetTeam();
}
return ETeam_Enum::None;
}
//////////////////////////////////////////////////////////
//Inventory
void ATOCharacter::AddWeapon(AItems* Weapon)
{
if (Weapon && Role == ROLE_Authority)
{
Weapon->OnEnterInventory(this);
Inventory.AddUnique(Weapon);
}
else ServerAddWeapon(Weapon);
}
bool ATOCharacter::ServerAddWeapon_Validate(AItems* Weapon)
{
return true;
}
void ATOCharacter::ServerAddWeapon_Implementation(AItems* Weapon)
{
AddWeapon(Weapon);
}
void ATOCharacter::RemoveWeapon(AItems* Weapon)
{
if (Weapon && Role == ROLE_Authority)
{
Weapon->OnLeaveInventory();
Inventory.RemoveSingle(Weapon);
}
}
void ATOCharacter::SpawnDefaultInventory()
{
if (Role < ROLE_Authority)
{
return;
}
int32 NumWeaponClasses = DefaultInventoryClasses.Num();
for (int32 i = 0; i < NumWeaponClasses; i++)
{
if (DefaultInventoryClasses*)
{
FActorSpawnParameters SpawnInfo;
SpawnInfo.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
AItems* NewWeapon = GetWorld()->SpawnActor<AItems>(DefaultInventoryClasses*, SpawnInfo);
AddWeapon(NewWeapon);
}
}
// equip first weapon in inventory
if (Inventory.Num() > 0)
{
EquipWeapon(Inventory[0]);
}
}
void ATOCharacter::EquipWeapon(AItems* Weapon)
{
if (Weapon)
{
if (Role == ROLE_Authority)
{
SetCurrentWeapon(Weapon, CurrentWeapon);
}
else
{
ServerEquipWeapon(Weapon);
}
}
}
bool ATOCharacter::ServerEquipWeapon_Validate(AItems* Weapon)
{
return true;
}
void ATOCharacter::ServerEquipWeapon_Implementation(AItems* Weapon)
{
EquipWeapon(Weapon);
}
void ATOCharacter::DestroyInventory()
{
if (Role < ROLE_Authority)
{
return;
}
// remove all weapons from inventory and destroy them
for (int32 i = Inventory.Num() - 1; i >= 0; i--)
{
AItems* Weapon = Inventory*;
if (Weapon)
{
RemoveWeapon(Weapon);
Weapon->Destroy();
}
}
}
void ATOCharacter::SetCurrentWeapon(AItems* NewWeapon, AItems* LastWeapon)
{
AItems* LocalLastWeapon = NULL;
if (LastWeapon != NULL)
{
LocalLastWeapon = LastWeapon;
}
else if (NewWeapon != CurrentWeapon)
{
LocalLastWeapon = CurrentWeapon;
}
// unequip previous
if (LocalLastWeapon)
{
LocalLastWeapon->OnUnEquip();
}
CurrentWeapon = NewWeapon;
// equip new one
if (NewWeapon)
{
NewWeapon->SetOwningPawn(this); // Make sure weapon's MyPawn is pointing back to us. During replication, we can't guarantee APawn::CurrentWeapon will rep after AWeapon::MyPawn!
NewWeapon->OnEquip(LastWeapon);
}
}
void ATOCharacter::OnNextWeapon()
{
ABasePlayerController* MyPC = Cast<ABasePlayerController>(Controller);
if (MyPC )
{
if (Inventory.Num() >= 2 && (CurrentWeapon == NULL || CurrentWeapon->GetCurrentState() != EWeaponState::Equipping))
{
const int32 CurrentWeaponIdx = Inventory.IndexOfByKey(CurrentWeapon);
AItems* NextWeapon = Inventory(CurrentWeaponIdx + 1) % Inventory.Num()];
EquipWeapon(NextWeapon);
}
}
}
void ATOCharacter::OnPrevWeapon()
{
ABasePlayerController* MyPC = Cast<ABasePlayerController>(Controller);
if (MyPC )
{
if (Inventory.Num() >= 2 && (CurrentWeapon == NULL || CurrentWeapon->GetCurrentState() != EWeaponState::Equipping))
{
const int32 CurrentWeaponIdx = Inventory.IndexOfByKey(CurrentWeapon);
AItems* PrevWeapon = Inventory(CurrentWeaponIdx - 1 + Inventory.Num()) % Inventory.Num()];
EquipWeapon(PrevWeapon);
}
}
}
void ATOCharacter::CanAddItem_Implementation(class AItems* ItemChecked)
{
}
////////////////////////////////////////////////////
const TArray<FDamageInfo> & ATOCharacter::GetDamageInfoArray() const
{
return DamageInfoArray;
}
FName ATOCharacter::GetWeaponAttachPoint() const
{
return WeaponAttachPoint;
}
USkeletalMeshComponent* ATOCharacter::GetSpecifcPawnMesh(bool WantFirstPerson) const
{
return WantFirstPerson == true ? Mesh1P : GetMesh();
}
USkeletalMeshComponent* ATOCharacter::GetPawnMesh() const
{
return IsFirstPerson() ? Mesh1P : GetMesh();
}
bool ATOCharacter::IsFirstPerson() const
{
return IsAlive() && Controller && Controller->IsLocalPlayerController();
}
bool ATOCharacter::IsAlive() const
{
return Health > 0;
}
FRotator ATOCharacter::GetAimOffsets() const
{
const FVector AimDirWS = GetBaseAimRotation().Vector();
const FVector AimDirLS = ActorToWorld().InverseTransformVectorNoScale(AimDirWS);
const FRotator AimRotLS = AimDirLS.Rotation();
return AimRotLS;
}
And the code of my weapon:
// Fill out your copyright notice in the Description page of Project Settings.
#include “TOUnderFire.h”
#include “Items.h”
#include “UnrealNetwork.h”
#include “Player/TOCharacter.h”
// Sets default values
AItems::AItems(const FObjectInitializer & ObjectInitializer)
: Super(ObjectInitializer)
{
ItemMesh = ObjectInitializer.CreateDefaultSubobject<USkeletalMeshComponent>(this, TEXT(“WeaponMesh1P”));
ItemMesh->MeshComponentUpdateFlag = EMeshComponentUpdateFlag::OnlyTickPoseWhenRendered;
ItemMesh->bReceivesDecals = false;
ItemMesh->CastShadow = false;
ItemMesh->SetCollisionObjectType(ECC_WorldDynamic);
ItemMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
ItemMesh->SetCollisionResponseToAllChannels(ECR_Ignore);
RootComponent = ItemMesh;
ItemMesh3P = ObjectInitializer.CreateDefaultSubobject<USkeletalMeshComponent>(this, TEXT("WeaponMesh3P"));
ItemMesh3P->MeshComponentUpdateFlag = EMeshComponentUpdateFlag::OnlyTickPoseWhenRendered;
ItemMesh3P->bReceivesDecals = false;
ItemMesh3P->CastShadow = true;
ItemMesh3P->SetCollisionObjectType(ECC_WorldDynamic);
ItemMesh3P->SetCollisionEnabled(ECollisionEnabled::NoCollision);
ItemMesh3P->SetCollisionResponseToAllChannels(ECR_Ignore);
//ItemMesh3P->SetCollisionResponseToChannel(COLLISION_WEAPON, ECR_Block);
ItemMesh3P->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block);
//ItemMesh3P->SetCollisionResponseToChannel(COLLISION_PROJECTILE, ECR_Block);
ItemMesh3P->SetupAttachment(ItemMesh);
CanbePickUp = false;
ItemSlot = EItemSlotEnum::None;
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
ItemName = "";
CostToPurchase = 0;
NumMaxItem = 1;
bIsEquipped = false;
bPendingReload = false;
bPendingEquip = false;
CurrentState = EWeaponState::Idle;
}
// Called when the game starts or when spawned
void AItems::BeginPlay()
{
Super::BeginPlay();
}
void AItems::Reset()
{
Super::Reset();
}
// Called every frame
void AItems::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AItems::OnRep_Instigator()
{
Super::OnRep_Instigator();
}
bool AItems::CanBePickedUp() const
{
return !Instigator;
}
bool AItems::CanBeDropped() const
{
return true;
}
void AItems::AttachMeshToPawn()
{
if (MyPawn)
{
// Remove and hide both first and third person meshes
DetachMeshFromPawn();
// OnATTach remplace provisoirement la suite de ce code, pour pouvoir
//l'implementer par blueprint et debugger
OnAttach();
// For locally controller players we attach both weapons and let the bOnlyOwnerSee, bOwnerNoSee flags deal with visibility.
/*FName AttachPoint = MyPawn->GetWeaponAttachPoint();
if (MyPawn->IsLocallyControlled() == true)
{
USkeletalMeshComponent* PawnMesh1p = MyPawn->GetSpecifcPawnMesh(true);
USkeletalMeshComponent* PawnMesh3p = MyPawn->GetSpecifcPawnMesh(false);
ItemMesh->SetHiddenInGame(false);
ItemMesh3P->SetHiddenInGame(false);
ItemMesh->AttachToComponent(PawnMesh1p, FAttachmentTransformRules::KeepRelativeTransform, AttachPoint);
ItemMesh3P->AttachToComponent(PawnMesh3p, FAttachmentTransformRules::KeepRelativeTransform, AttachPoint);
}
else
{
USkeletalMeshComponent* UseWeaponMesh = GetWeaponMesh();
USkeletalMeshComponent* UsePawnMesh = MyPawn->GetPawnMesh();
UseWeaponMesh->AttachToComponent(UsePawnMesh, FAttachmentTransformRules::KeepRelativeTransform, AttachPoint);
UseWeaponMesh->SetHiddenInGame(false);
}*/
}
}
void AItems::OnAttach_Implementation()
{
}
void AItems::DetachMeshFromPawn()
{
ItemMesh->DetachFromComponent(FDetachmentTransformRules::KeepRelativeTransform);
ItemMesh->SetHiddenInGame(true);
ItemMesh3P->DetachFromComponent(FDetachmentTransformRules::KeepRelativeTransform);
ItemMesh3P->SetHiddenInGame(true);
}
USkeletalMeshComponent* AItems::GetWeaponMesh() const
{
return (MyPawn != NULL && MyPawn->IsFirstPerson()) ? ItemMesh : ItemMesh3P;
}
//////////////////////////////////////////////////////////////////////////
// Replication & effects
void AItems::OnRep_MyPawn()
{
if (MyPawn)
{
OnEnterInventory(MyPawn);
}
else
{
OnLeaveInventory();
}
}
void AItems::OnEnterInventory(ATOCharacter* NewOwner)
{
SetOwningPawn(NewOwner);
}
void AItems::OnLeaveInventory()
{
if (Role == ROLE_Authority)
{
SetOwningPawn(NULL);
}
if (IsAttachedToPawn())
{
OnUnEquip();
}
}
bool AItems::IsAttachedToPawn() const
{
return bIsEquipped || bPendingEquip;
}
void AItems::SetOwningPawn(ATOCharacter* NewOwner)
{
if (MyPawn != NewOwner)
{
Instigator = NewOwner;
MyPawn = NewOwner;
// net owner for RPC calls
SetOwner(NewOwner);
}
}
//////////////////////////////////////////////////////////////////////////
// Inventory
void AItems::OnEquip(const AItems* LastWeapon)
{
AttachMeshToPawn();
bPendingEquip = true;
DetermineWeaponState();
// Only play animation if last weapon is valid
if (LastWeapon)
{
float Duration = PlayWeaponAnimation(EquipAnim);
if (Duration <= 0.0f)
{
// failsafe
Duration = 0.5f;
}
EquipStartedTime = GetWorld()->GetTimeSeconds();
EquipDuration = Duration;
GetWorldTimerManager().SetTimer(TimerHandle_OnEquipFinished, this, &AItems::OnEquipFinished, Duration, false);
}
else
{
OnEquipFinished();
}
if (MyPawn && MyPawn->IsLocallyControlled())
{
PlayWeaponSound(EquipSound);
}
}
void AItems::OnEquipFinished()
{
AttachMeshToPawn();
bIsEquipped = true;
bPendingEquip = false;
// Determine the state so that the can reload checks will work
DetermineWeaponState();
}
void AItems::OnUnEquip()
{
DetachMeshFromPawn();
bIsEquipped = false;
/*StopFire();
if (bPendingReload)
{
StopWeaponAnimation(ReloadAnim);
bPendingReload = false;
GetWorldTimerManager().ClearTimer(TimerHandle_StopReload);
GetWorldTimerManager().ClearTimer(TimerHandle_ReloadWeapon);
}
if (bPendingEquip)
{
StopWeaponAnimation(EquipAnim);
bPendingEquip = false;
GetWorldTimerManager().ClearTimer(TimerHandle_OnEquipFinished);
}
DetermineWeaponState();*/
}
void AItems::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(AItems, MyPawn);
}
UAudioComponent* AItems::PlayWeaponSound(USoundCue* Sound)
{
UAudioComponent* AC = NULL;
if (Sound && MyPawn)
{
AC = UGameplayStatics::SpawnSoundAttached(Sound, MyPawn->GetRootComponent());
}
return AC;
}
void AItems::DetermineWeaponState()
{
EWeaponState::Type NewState = EWeaponState::Idle;
if (bIsEquipped)
{
if (bPendingReload)
{
if (CanReload() == false)
{
NewState = CurrentState;
}
else
{
NewState = EWeaponState::Reloading;
}
}
else if ((bPendingReload == false) && (bWantsToFire == true) && (CanFire() == true))
{
NewState = EWeaponState::Firing;
}
}
else if (bPendingEquip)
{
NewState = EWeaponState::Equipping;
}
SetWeaponState(NewState);
}
void AItems::SetWeaponState(EWeaponState::Type NewState)
{
const EWeaponState::Type PrevState = CurrentState;
/*
if (PrevState == EWeaponState::Firing && NewState != EWeaponState::Firing)
{
OnBurstFinished();
}
CurrentState = NewState;
if (PrevState != EWeaponState::Firing && NewState == EWeaponState::Firing)
{
OnBurstStarted();
}*/
}
EWeaponState::Type AItems::GetCurrentState() const
{
return CurrentState;
}
bool AItems::CanFire() const
{
// return IsAlive();
return true;
}
void AItems::OnRep_Reload()
{
/if (bPendingReload)
{
StartReload(true);
}
else
{
StopReload();
}/
}
bool AItems::CanReload() const
{
return true;
}
float AItems::PlayWeaponAnimation(const FWeaponAnim& Animation)
{
float Duration = 0.0f;
if (MyPawn)
{
UAnimMontage* UseAnim = MyPawn->IsFirstPerson() ? Animation.Pawn1P : Animation.Pawn3P;
if (UseAnim)
{
Duration = MyPawn->PlayAnimMontage(UseAnim);
}
}
return Duration;
}
void AItems::MeshAttash_Implementation()
{
}