I am using 5.0.1 using C++
I’m trying to combine the Mutltiplayer tut
with the respawn tut
Both work fine on their own, but when I put it into multiplayer mode the player does not respawn.
Thanks in advance.
code
ThirdPersonMPGameMode.cpp
Summary
// Copyright Epic Games, Inc. All Rights Reserved.
#include “ThirdPersonMPGameMode.h”
#include “ThirdPersonMPCharacter.h”
#include “UObject/ConstructorHelpers.h”
AThirdPersonMPGameMode::AThirdPersonMPGameMode()
{
// set default pawn class to our Blueprinted character
static ConstructorHelpers::FClassFinder PlayerPawnBPClass(TEXT("/Game/ThirdPerson/Blueprints/BP_ThirdPersonCharacter"));
if (PlayerPawnBPClass.Class != NULL)
{
DefaultPawnClass = PlayerPawnBPClass.Class;
}
}
void AThirdPersonMPGameMode::BeginPlay()
{
Super::BeginPlay();
//Bind our Player died delegate to the Gamemode's PlayerDied function.
if (!OnPlayerDied.IsBound())
{
OnPlayerDied.AddDynamic(this, &AThirdPersonMPGameMode::PlayerDied);
}
}
void AThirdPersonMPGameMode::RestartPlayer(AController* NewPlayer)
{
Super::RestartPlayer(NewPlayer);
}
void AThirdPersonMPGameMode::PlayerDied(ACharacter* Character)
{
//Get a reference to our Character’s Player Controller
AController* CharacterController = Character->GetController();
Super::RestartPlayer(CharacterController);
}
ThirdPersonMPGameMode.h
Summary
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include “CoreMinimal.h”
#include “GameFramework/GameModeBase.h”
#include “ThirdPersonMPGameMode.generated.h”
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnPlayerDiedSignature, ACharacter*, Character);
UCLASS(minimalapi)
class AThirdPersonMPGameMode : public AGameModeBase
{
GENERATED_BODY()
public:
AThirdPersonMPGameMode();
const FOnPlayerDiedSignature& GetOnPlayerDied() const { return OnPlayerDied; }
//Tries to Spawn the player's pawn.
virtual void RestartPlayer(AController* NewPlayer) override;
protected:
virtual void BeginPlay() override;
//Called when Player character has died.
UFUNCTION()
virtual void PlayerDied(ACharacter* Character);
//Signature to bind delegate.
UPROPERTY()
FOnPlayerDiedSignature OnPlayerDied;
};
ThirdPersonMPCharacter.cpp
Summary
// Copyright Epic Games, Inc. All Rights Reserved.
#include “ThirdPersonMPCharacter.h”
#include “Camera/CameraComponent.h”
#include “Components/CapsuleComponent.h”
#include “Components/InputComponent.h”
#include “GameFramework/CharacterMovementComponent.h”
#include “GameFramework/Controller.h”
#include “GameFramework/SpringArmComponent.h”
#include “Net/UnrealNetwork.h”
#include “Engine/Engine.h”
#include “ThirdPersonMPProjectile.h”
#include “ThirdPersonMPGameMode.h”
//////////////////////////////////////////////////////////////////////////
// AThirdPersonMPCharacter
AThirdPersonMPCharacter::AThirdPersonMPCharacter()
{
// Set size for collision capsule
GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);
// set our turn rate for input
TurnRateGamepad = 50.f;
// Don't rotate when the controller rotates. Let that just affect the camera.
bUseControllerRotationPitch = false;
bUseControllerRotationYaw = false;
bUseControllerRotationRoll = false;
// Configure character movement
GetCharacterMovement()->bOrientRotationToMovement = true; // Character moves in the direction of input...
GetCharacterMovement()->RotationRate = FRotator(0.0f, 500.0f, 0.0f); // ...at this rotation rate
// Note: For faster iteration times these variables, and many more, can be tweaked in the Character Blueprint
// instead of recompiling to adjust them
GetCharacterMovement()->JumpZVelocity = 700.f;
GetCharacterMovement()->AirControl = 0.35f;
GetCharacterMovement()->MaxWalkSpeed = 500.f;
GetCharacterMovement()->MinAnalogWalkSpeed = 20.f;
GetCharacterMovement()->BrakingDecelerationWalking = 2000.f;
// Create a camera boom (pulls in towards the player if there is a collision)
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
CameraBoom->SetupAttachment(RootComponent);
CameraBoom->TargetArmLength = 400.0f; // The camera follows at this distance behind the character
CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller
// Create a follow camera
FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation
FollowCamera->bUsePawnControlRotation = false; // Camera does not rotate relative to arm
// Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character)
// are set in the derived blueprint asset named ThirdPersonCharacter (to avoid direct content references in C++)
//Initialize the player’s Health
MaxHealth = 100.0f;
CurrentHealth = MaxHealth;
//Initialize projectile class
ProjectileClass = AThirdPersonMPProjectile::StaticClass();
//Initialize fire rate
FireRate = 0.25f;
//we are currently not firing
bIsFiringWeapon = false;
}
void AThirdPersonMPCharacter::StartFire()
{
if (!bIsFiringWeapon)
{
bIsFiringWeapon = true;
UWorld* World = GetWorld();
World->GetTimerManager().SetTimer(FiringTimer, this, &AThirdPersonMPCharacter::StopFire, FireRate, false);
HandleFire();
}
}
void AThirdPersonMPCharacter::StopFire()
{
bIsFiringWeapon = false;
}
void AThirdPersonMPCharacter::HandleFire_Implementation()
{
FVector spawnLocation = GetActorLocation() + (GetControlRotation().Vector() * 100.0f) + (GetActorUpVector() * 50.0f);
FRotator spawnRotation = GetControlRotation();
FActorSpawnParameters spawnParameters;
spawnParameters.Instigator = GetInstigator();
spawnParameters.Owner = this;
AThirdPersonMPProjectile* spawnedProjectile = GetWorld()->SpawnActor<AThirdPersonMPProjectile>(spawnLocation, spawnRotation, spawnParameters);
}
//////////////////////////////////////////////////////////////////////////
// Replicated Properties
void AThirdPersonMPCharacter::GetLifetimeReplicatedProps(TArray & OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
//Replicate current health.
DOREPLIFETIME(AThirdPersonMPCharacter, CurrentHealth);
}
void AThirdPersonMPCharacter::OnHealthUpdate()
{
//Client-specific functionality
if (IsLocallyControlled())
{
FString healthMessage = FString::Printf(TEXT(“You now have %f health remaining.”), CurrentHealth);
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, healthMessage);
if (CurrentHealth <= 0)
{
FString deathMessage = FString::Printf(TEXT("You have been killed."));
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, deathMessage);
//now we respawn
}
}
//Server-specific functionality
if (GetLocalRole() == ROLE_Authority)
{
FString healthMessage = FString::Printf(TEXT("%s now has %f health remaining."), *GetFName().ToString(), CurrentHealth);
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, healthMessage);
}
//Functions that occur on all machines.
/*
Any special functionality that should occur as a result of damage or death should be placed here.
*/
}
void AThirdPersonMPCharacter::OnRep_CurrentHealth()
{
OnHealthUpdate();
}
void AThirdPersonMPCharacter::SetCurrentHealth(float healthValue)
{
if (GetLocalRole() == ROLE_Authority)
{
CurrentHealth = FMath::Clamp(healthValue, 0.f, MaxHealth);
OnHealthUpdate();
}
}
float AThirdPersonMPCharacter::TakeDamage(float DamageTaken, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
float damageApplied = CurrentHealth - DamageTaken;
SetCurrentHealth(damageApplied);
return damageApplied;
}
//////////////////////////////////////////////////////////////////////////
// Input
void AThirdPersonMPCharacter::SetupPlayerInputComponent(class UInputComponent* 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("Move Forward / Backward", this, &AThirdPersonMPCharacter::MoveForward);
PlayerInputComponent->BindAxis("Move Right / Left", this, &AThirdPersonMPCharacter::MoveRight);
// We have 2 versions of the rotation bindings to handle different kinds of devices differently
// "turn" handles devices that provide an absolute delta, such as a mouse.
// "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick
PlayerInputComponent->BindAxis("Turn Right / Left Mouse", this, &APawn::AddControllerYawInput);
PlayerInputComponent->BindAxis("Turn Right / Left Gamepad", this, &AThirdPersonMPCharacter::TurnAtRate);
PlayerInputComponent->BindAxis("Look Up / Down Mouse", this, &APawn::AddControllerPitchInput);
PlayerInputComponent->BindAxis("Look Up / Down Gamepad", this, &AThirdPersonMPCharacter::LookUpAtRate);
// handle touch devices
PlayerInputComponent->BindTouch(IE_Pressed, this, &AThirdPersonMPCharacter::TouchStarted);
PlayerInputComponent->BindTouch(IE_Released, this, &AThirdPersonMPCharacter::TouchStopped);
// Handle firing projectiles
PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &AThirdPersonMPCharacter::StartFire);
//Sets up an input key action to call Restart Player.
PlayerInputComponent->BindAction("Restart", IE_Pressed, this, &AThirdPersonMPCharacter::CallRestartPlayer);
}
void AThirdPersonMPCharacter::TouchStarted(ETouchIndex::Type FingerIndex, FVector Location)
{
Jump();
}
void AThirdPersonMPCharacter::TouchStopped(ETouchIndex::Type FingerIndex, FVector Location)
{
StopJumping();
}
void AThirdPersonMPCharacter::TurnAtRate(float Rate)
{
// calculate delta for this frame from the rate information
AddControllerYawInput(Rate * TurnRateGamepad * GetWorld()->GetDeltaSeconds());
}
void AThirdPersonMPCharacter::LookUpAtRate(float Rate)
{
// calculate delta for this frame from the rate information
AddControllerPitchInput(Rate * TurnRateGamepad * GetWorld()->GetDeltaSeconds());
}
void AThirdPersonMPCharacter::MoveForward(float Value)
{
if ((Controller != nullptr) && (Value != 0.0f))
{
// find out which way is forward
const FRotator Rotation = Controller->GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);
// get forward vector
const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
AddMovementInput(Direction, Value);
}
}
void AThirdPersonMPCharacter::MoveRight(float Value)
{
if ( (Controller != nullptr) && (Value != 0.0f) )
{
// find out which way is right
const FRotator Rotation = Controller->GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);
// get right vector
const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
// add movement in that direction
AddMovementInput(Direction, Value);
}
}
void AThirdPersonMPCharacter::Destroyed()
{
Super::Destroyed();
// Example to bind to OnPlayerDied event in GameMode.
if (UWorld* World = GetWorld())
{
if (AThirdPersonMPGameMode* GameMode = Cast<AThirdPersonMPGameMode>(World->GetAuthGameMode()))
{
GameMode->GetOnPlayerDied().Broadcast(this);
//now we respawn
CallRestartPlayer();
}
}
}
void AThirdPersonMPCharacter::CallRestartPlayer()
{
//Get a reference to the Pawn Controller.
AController* CortollerRef = GetController();
//Destroy the Player.
Destroy();
//Get the World and GameMode in the world to invoke its restart player function.
if (UWorld* World = GetWorld())
{
if (AThirdPersonMPGameMode* GameMode = Cast<AThirdPersonMPGameMode>(World->GetAuthGameMode()))
{
GameMode->RestartPlayer(CortollerRef);
}
}
}
ThirdPersonMPCharacter.h
Summary
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include “CoreMinimal.h”
#include “GameFramework/Character.h”
#include “ThirdPersonMPCharacter.generated.h”
UCLASS(config=Game)
class AThirdPersonMPCharacter : public ACharacter
{
GENERATED_BODY()
/** Camera boom positioning the camera behind the character */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
class USpringArmComponent* CameraBoom;
/** Follow camera */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
class UCameraComponent* FollowCamera;
/** Property replication */
void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
public:
AThirdPersonMPCharacter();
/** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Input)
float TurnRateGamepad;
/** Getter for Max Health.*/
UFUNCTION(BlueprintPure, Category = "Health")
FORCEINLINE float GetMaxHealth() const { return MaxHealth; }
/** Getter for Current Health.*/
UFUNCTION(BlueprintPure, Category = "Health")
FORCEINLINE float GetCurrentHealth() const { return CurrentHealth; }
/** Setter for Current Health. Clamps the value between 0 and MaxHealth and calls OnHealthUpdate. Should only be called on the server.*/
UFUNCTION(BlueprintCallable, Category = "Health")
void SetCurrentHealth(float healthValue);
/** Event for taking damage. Overridden from APawn.*/
UFUNCTION(BlueprintCallable, Category = "Health")
float TakeDamage(float DamageTaken, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser) override;
protected:
//Called when our Actor is destroyed during Gameplay.
virtual void Destroyed();
//Call Gamemode class to Restart Player Character.
void CallRestartPlayer();
/** Called for forwards/backward input */
void MoveForward(float Value);
/** Called for side to side input */
void MoveRight(float Value);
/**
* Called via input to turn at a given rate.
* @param Rate This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
*/
void TurnAtRate(float Rate);
/**
* Called via input to turn look up/down at a given rate.
* @param Rate This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
*/
void LookUpAtRate(float Rate);
/** Handler for when a touch input begins. */
void TouchStarted(ETouchIndex::Type FingerIndex, FVector Location);
/** Handler for when a touch input stops. */
void TouchStopped(ETouchIndex::Type FingerIndex, FVector Location);
/** The player's maximum health. This is the highest that their health can be, and the value that their health starts at when spawned.*/
UPROPERTY(EditDefaultsOnly, Category = "Health")
float MaxHealth;
/** The player's current health. When reduced to 0, they are considered dead.*/
UPROPERTY(ReplicatedUsing = OnRep_CurrentHealth)
float CurrentHealth;
/** RepNotify for changes made to current health.*/
UFUNCTION()
void OnRep_CurrentHealth();
/** Response to health being updated. Called on the server immediately after modification, and on clients in response to a RepNotify*/
void OnHealthUpdate();
UPROPERTY(EditDefaultsOnly, Category = "Gameplay|Projectile")
TSubclassOf<class AThirdPersonMPProjectile> ProjectileClass;
/** Delay between shots in seconds. Used to control fire rate for our test projectile, but also to prevent an overflow of server functions from binding SpawnProjectile directly to input.*/
UPROPERTY(EditDefaultsOnly, Category = "Gameplay")
float FireRate;
/** If true, we are in the process of firing projectiles. */
bool bIsFiringWeapon;
/** Function for beginning weapon fire.*/
UFUNCTION(BlueprintCallable, Category = "Gameplay")
void StartFire();
/** Function for ending weapon fire. Once this is called, the player can use StartFire again.*/
UFUNCTION(BlueprintCallable, Category = "Gameplay")
void StopFire();
/** Server function for spawning projectiles.*/
UFUNCTION(Server, Reliable)
void HandleFire();
/** A timer handle used for providing the fire rate delay in-between spawns.*/
FTimerHandle FiringTimer;
protected:
// APawn interface
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
// End of APawn interface
public:
/** Returns CameraBoom subobject /
FORCEINLINE class USpringArmComponent GetCameraBoom() const { return CameraBoom; }
/* Returns FollowCamera subobject */
FORCEINLINE class UCameraComponent GetFollowCamera() const { return FollowCamera; }
};
This text will be hidden