Hello. I want to create a multiplayer shooter game. The goal is to deal 25 points shooting in the target. I am a newbie in multiplayer game creation so please help me. I have been dealing with this for a long time and am already confused. Points are scored incorrectly and sometimes the clients are reset to zero.
TestingWorkProjectile.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "TestingWorkProjectile.generated.h"
UCLASS(config=Game)
class ATestingWorkProjectile : public AActor
{
GENERATED_BODY()
/** Sphere collision component */
UPROPERTY(VisibleDefaultsOnly, Category=Projectile)
class USphereComponent* CollisionComp;
UPROPERTY(Replicated, EditAnywhere, Category = Projectile)
FVector ProjectileLocation;
/** Projectile movement component */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Movement, meta = (AllowPrivateAccess = "true"))
class UProjectileMovementComponent* ProjectileMovement;
virtual void BeginPlay() override;
virtual void Tick(float DeltaTime) override;
public:
ATestingWorkProjectile();
/** called when projectile hits something */
UFUNCTION()
void OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);
/** Returns CollisionComp subobject **/
FORCEINLINE class USphereComponent* GetCollisionComp() const { return CollisionComp; }
/** Returns ProjectileMovement subobject **/
FORCEINLINE class UProjectileMovementComponent* GetProjectileMovement() const { return ProjectileMovement; }
UPROPERTY()
bool Once;
//int k;
UPROPERTY(Replicated, EditAnywhere, Category = Projectile)
FString ProjectileOwnerName;
UPROPERTY(Replicated, EditAnywhere, Category = Projectile)
FString OtherName;
};
TestingWorkProjectile.cpp
#include "TestingWorkProjectile.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "Components/SphereComponent.h"
#include "TestingWorkCharacter.h"
#include "Kismet/GameplayStatics.h"
#include "Net/UnrealNetwork.h"
ATestingWorkProjectile::ATestingWorkProjectile()
{
// Use a sphere as a simple collision representation
CollisionComp = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComp"));
CollisionComp->InitSphereRadius(5.0f);
CollisionComp->BodyInstance.SetCollisionProfileName("Projectile");
CollisionComp->OnComponentHit.AddDynamic(this, &ATestingWorkProjectile::OnHit); // set up a notification for when this component hits something blocking
// Players can't walk on it
CollisionComp->SetWalkableSlopeOverride(FWalkableSlopeOverride(WalkableSlope_Unwalkable, 0.f));
CollisionComp->CanCharacterStepUpOn = ECB_No;
// Set as root component
RootComponent = CollisionComp;
// Use a ProjectileMovementComponent to govern this projectile's movement
ProjectileMovement = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("ProjectileComp"));
ProjectileMovement->UpdatedComponent = CollisionComp;
ProjectileMovement->InitialSpeed = 3000.f;
ProjectileMovement->MaxSpeed = 3000.f;
ProjectileMovement->bRotationFollowsVelocity = true;
ProjectileMovement->bShouldBounce = true;
// Die after 3 seconds by default
InitialLifeSpan = 3.0f;
SetReplicates(true);
SetReplicateMovement(true);
Once = false;
}
void ATestingWorkProjectile::BeginPlay()
{
Super::BeginPlay();
//UE_LOG(LogTemp, Warning, TEXT("HELLO"));
/*if (Role == ROLE_Authority)
{
//FString ProjectileName = GetName();
//FString ProjectileOwnerName = GetOwner()->GetName();
//UE_LOG(LogTemp, Warning, TEXT("%s"), *ProjectileName);
//UE_LOG(LogTemp, Warning, TEXT("%s"), *ProjectileOwnerName);
if (!Once)
{
ProjectileLocation = GetActorLocation();
Once = true;
}
}*/
//UE_LOG(LogTemp, Warning, TEXT("%s"), *ProjectileLocation);
}
void ATestingWorkProjectile::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void ATestingWorkProjectile::OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
if (Role < ROLE_Authority)
{
ProjectileOwnerName = GetOwner()->GetName();
OtherName = OtherActor->GetName();
UE_LOG(LogTemp, Warning, TEXT("%s"), *OtherName);
int i = 0;
ATestingWorkCharacter* MyCharacter = Cast<ATestingWorkCharacter>(UGameplayStatics::GetPlayerCharacter(this, i));
while (MyCharacter != nullptr)
{
FString ProjectileOwnerName1 = "BP_FPC_C_";
ProjectileOwnerName1 += FString::FromInt(i);
UE_LOG(LogTemp, Warning, TEXT("%s"), *ProjectileOwnerName1);
UE_LOG(LogTemp, Warning, TEXT("%s"), *ProjectileOwnerName);
UE_LOG(LogTemp, Warning, TEXT("%s"), *OtherName);
if (ProjectileOwnerName == ProjectileOwnerName1)
{
UE_LOG(LogTemp, Warning, TEXT("HIT1"));
if (OtherActor->GetName() == "TargetActor_1")
{
UE_LOG(LogTemp, Warning, TEXT("HIT"));
MyCharacter->UpdateCurrentScore(0.5f);
}
if (OtherActor->GetName() == "FastTargetActor_1")
{
UE_LOG(LogTemp, Warning, TEXT("HIT"));
MyCharacter->UpdateCurrentScore(5.f);
}
}
i++;
MyCharacter = Cast<ATestingWorkCharacter>(UGameplayStatics::GetPlayerCharacter(this, i));
}
}
if (OtherActor->GetName() == "MyDoorActor40")
{
if(Role == ROLE_Authority)
OtherActor->Destroy();
}
/*for (FConstPawnIterator It = GetWorld()->GetPawnIterator(); It; It++)
{
APawn* Pawn = It->Get();
if (Pawn)
{
if (OtherActor->GetName() == "TargetActor_1")
Pawn->UpdateCu
else
}
}*/
// Only add impulse and destroy projectile if we hit a physics
if ((OtherActor != NULL) && (OtherActor != this) && (OtherComp != NULL) && OtherComp->IsSimulatingPhysics())
{
OtherComp->AddImpulseAtLocation(GetVelocity() * 100.0f, GetActorLocation());
if(Role == ROLE_Authority)
Destroy();
}
}
void ATestingWorkProjectile::GetLifetimeReplicatedProps(TArray <FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(ATestingWorkProjectile, ProjectileLocation);
}
TestingWorkCharacter.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "TestingWorkCharacter.generated.h"
class UInputComponent;
UCLASS(config=Game)
class ATestingWorkCharacter : public ACharacter
{
GENERATED_BODY()
/** Pawn mesh: 1st person view (arms; seen only by self) */
UPROPERTY(VisibleAnywhere, Category=Mesh)
class USkeletalMeshComponent* Mesh1P;
/** Gun mesh: 1st person view (seen only by self) */
UPROPERTY(VisibleAnywhere, Category = Mesh)
class USkeletalMeshComponent* FP_Gun;
/** Location on gun mesh where projectiles should spawn. */
UPROPERTY(VisibleAnywhere, Category = Mesh)
class USceneComponent* FP_MuzzleLocation;
/** Gun mesh: VR view (attached to the VR controller directly, no arm, just the actual gun) */
UPROPERTY(VisibleDefaultsOnly, Category = Mesh)
class USkeletalMeshComponent* VR_Gun;
/** Location on VR gun mesh where projectiles should spawn. */
UPROPERTY(VisibleDefaultsOnly, Category = Mesh)
class USceneComponent* VR_MuzzleLocation;
/** First person camera */
UPROPERTY(VisibleAnywhere, Category = Camera, meta = (AllowPrivateAccess = "true"))
class UCameraComponent* FirstPersonCameraComponent;
/** Motion controller (right hand) */
UPROPERTY(VisibleAnywhere, meta = (AllowPrivateAccess = "true"))
class UMotionControllerComponent* R_MotionController;
/** Motion controller (left hand) */
UPROPERTY(VisibleAnywhere, meta = (AllowPrivateAccess = "true"))
class UMotionControllerComponent* L_MotionController;
public:
ATestingWorkCharacter();
virtual void Tick(float DeltaTime) override;
UFUNCTION(BlueprintPure, Category = "Score")
float GetInitialScore();
UFUNCTION(BlueprintPure, Category = "Score")
float GetCurrentScore();
UFUNCTION(Category = "Score")
void UpdateCurrentScoreClient(float Score);
UFUNCTION(NetMulticast, Reliable, WithValidation, BlueprintCallable, Category = "Score")
void UpdateCurrentScore(float Score);
UFUNCTION(NetMulticast, Reliable, WithValidation, BlueprintCallable, Category = "Score")
void ComputeOtherScore();
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Score")
float CurrentScore;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Score")
bool Score25;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Score")
FString OtherScore;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Projectile")
FString OwnerName;
UPROPERTY(EditAnywhere)
class AMyDoor* MyDoor;
private:
UPROPERTY(Replicated, EditAnywhere, Category = "Score")
float InitialScore;
protected:
virtual void BeginPlay();
public:
/** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
float BaseTurnRate;
/** Base look up/down rate, in deg/sec. Other scaling may affect final rate. */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
float BaseLookUpRate;
/** Gun muzzle's offset from the characters location */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Gameplay)
FVector GunOffset;
/** Projectile class to spawn */
UPROPERTY(EditDefaultsOnly, Category=Projectile)
TSubclassOf<class ATestingWorkProjectile> ProjectileClass;
/** Sound to play each time we fire */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Gameplay)
class USoundBase* FireSound;
/** AnimMontage to play each time we fire */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
class UAnimMontage* FireAnimation;
/** Whether to use motion controller location for aiming. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
uint32 bUsingMotionControllers : 1;
protected:
/** Fires a projectile. */
void OnFire();
UFUNCTION(Server, Reliable, WithValidation)
void ServerFire();
/** Resets HMD orientation and position in VR. */
void OnResetVR();
/** Handles moving forward/backward */
void MoveForward(float Val);
/** Handles stafing movement, left and right */
void MoveRight(float Val);
/**
* 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);
struct TouchData
{
TouchData() { bIsPressed = false;Location=FVector::ZeroVector;}
bool bIsPressed;
ETouchIndex::Type FingerIndex;
FVector Location;
bool bMoved;
};
void BeginTouch(const ETouchIndex::Type FingerIndex, const FVector Location);
void EndTouch(const ETouchIndex::Type FingerIndex, const FVector Location);
void TouchUpdate(const ETouchIndex::Type FingerIndex, const FVector Location);
TouchData TouchItem;
protected:
// APawn interface
virtual void SetupPlayerInputComponent(UInputComponent* InputComponent) override;
// End of APawn interface
/*
* Configures input for touchscreen devices if there is a valid touch interface for doing so
*
* @param InputComponent The input component pointer to bind controls to
* @returns true if touch controls were enabled.
*/
bool EnableTouchscreenMovement(UInputComponent* InputComponent);
public:
/** Returns Mesh1P subobject **/
FORCEINLINE class USkeletalMeshComponent* GetMesh1P() const { return Mesh1P; }
/** Returns FirstPersonCameraComponent subobject **/
FORCEINLINE class UCameraComponent* GetFirstPersonCameraComponent() const { return FirstPersonCameraComponent; }
};
TestingWorkCharacter.cpp
#include "TestingWorkCharacter.h"
#include "TestingWorkProjectile.h"
#include "Animation/AnimInstance.h"
#include "Camera/CameraComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
#include "GameFramework/InputSettings.h"
#include "HeadMountedDisplayFunctionLibrary.h"
#include "Kismet/GameplayStatics.h"
#include "MotionControllerComponent.h"
#include "XRMotionControllerBase.h" // for FXRMotionControllerBase::RightHandSourceId
#include "Net/UnrealNetwork.h"
#include "MyDoor.h"
#include "MyDoorActor.h"
#include "Containers/UnrealString.h"
DEFINE_LOG_CATEGORY_STATIC(LogFPChar, Warning, All);
//////////////////////////////////////////////////////////////////////////
// ATestingWorkCharacter
ATestingWorkCharacter::ATestingWorkCharacter()
{
// 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(FirstPersonCameraComponent);
Mesh1P->bCastDynamicShadow = false;
Mesh1P->CastShadow = false;
Mesh1P->RelativeRotation = FRotator(1.9f, -19.19f, 5.2f);
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);
FP_MuzzleLocation = CreateDefaultSubobject<USceneComponent>(TEXT("MuzzleLocation"));
FP_MuzzleLocation->SetupAttachment(FP_Gun);
FP_MuzzleLocation->SetRelativeLocation(FVector(0.2f, 48.4f, -10.6f));
// Default offset from the character location for projectiles to spawn
GunOffset = FVector(100.0f, 0.0f, 10.0f);
// Note: The ProjectileClass and the skeletal mesh/anim blueprints for Mesh1P, FP_Gun, and VR_Gun
// are set in the derived blueprint asset named MyCharacter to avoid direct content references in C++.
// Create VR Controllers.
R_MotionController = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("R_MotionController"));
R_MotionController->MotionSource = FXRMotionControllerBase::RightHandSourceId;
R_MotionController->SetupAttachment(RootComponent);
L_MotionController = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("L_MotionController"));
L_MotionController->SetupAttachment(RootComponent);
// Create a gun and attach it to the right-hand VR controller.
// Create a gun mesh component
VR_Gun = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("VR_Gun"));
VR_Gun->SetOnlyOwnerSee(true); // only the owning player will see this mesh
VR_Gun->bCastDynamicShadow = false;
VR_Gun->CastShadow = false;
VR_Gun->SetupAttachment(R_MotionController);
VR_Gun->SetRelativeRotation(FRotator(0.0f, -90.0f, 0.0f));
VR_MuzzleLocation = CreateDefaultSubobject<USceneComponent>(TEXT("VR_MuzzleLocation"));
VR_MuzzleLocation->SetupAttachment(VR_Gun);
VR_MuzzleLocation->SetRelativeLocation(FVector(0.000004, 53.999992, 10.000000));
VR_MuzzleLocation->SetRelativeRotation(FRotator(0.0f, 90.0f, 0.0f)); // Counteract the rotation of the VR gun model.
InitialScore = 0;
CurrentScore = InitialScore;
Score25 = false;
SetReplicates(true);
SetReplicateMovement(true);
//OtherScore = "";
// Uncomment the following line to turn motion controllers on by default:
//bUsingMotionControllers = true;
}
float ATestingWorkCharacter::GetInitialScore()
{
return InitialScore;
}
float ATestingWorkCharacter::GetCurrentScore()
{
return CurrentScore;
}
void ATestingWorkCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (Role == ROLE_Authority)
OtherScore = "";
if (!IsLocallyControlled())
{
FRotator NewRot = FirstPersonCameraComponent->RelativeRotation;
NewRot.Pitch = RemoteViewPitch * 360.f / 255.f;
FirstPersonCameraComponent->SetRelativeRotation(NewRot);
}
ComputeOtherScore();
//UpdateCurrentScore(DeltaTime * 0.1f );
}
void ATestingWorkCharacter::ComputeOtherScore_Implementation()
{
int k = 0;
ATestingWorkCharacter* MyCharacter = Cast<ATestingWorkCharacter>(UGameplayStatics::GetPlayerCharacter(this, k));
while (MyCharacter != nullptr)
{
//FString Loc1 = GetActorLocation().ToString();
//FString Loc2 = MyCharacter->GetActorLocation().ToString();
//UE_LOG(LogTemp, Warning, TEXT("%s %s"), *Loc1, *Loc2);
if(GetActorLocation() != MyCharacter->GetActorLocation())
//if (!(abs(GetActorLocation().X - MyCharacter->GetActorLocation().X) <= 5.f) && !(abs(GetActorLocation().Y - MyCharacter->GetActorLocation().Y) <= 5.f) && !(abs(GetActorLocation().Z - MyCharacter->GetActorLocation().Z) <= 5.f))
{
if (Role == ROLE_Authority)
OtherScore += FString::SanitizeFloat(MyCharacter->CurrentScore) + " ";
//OtherScore += "123";
}
k++;
MyCharacter = Cast<ATestingWorkCharacter>(UGameplayStatics::GetPlayerCharacter(this, k));
}
}
bool ATestingWorkCharacter::ComputeOtherScore_Validate()
{
return true;
}
void ATestingWorkCharacter::UpdateCurrentScore_Implementation(float Score)
{
if (Role == ROLE_Authority)
CurrentScore = CurrentScore + Score;
if (CurrentScore >= 25 && !Score25)
{
Score25 = true;
//MyDoor->OpenDoor();
}
}
void ATestingWorkCharacter::UpdateCurrentScoreClient(float Score)
{
}
bool ATestingWorkCharacter::UpdateCurrentScore_Validate(float Score)
{
return true;
}
void ATestingWorkCharacter::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("GripPoint"));
// Show or hide the two versions of the gun based on whether or not we're using motion controllers.
if (bUsingMotionControllers)
{
VR_Gun->SetHiddenInGame(false, true);
Mesh1P->SetHiddenInGame(true, true);
}
else
{
VR_Gun->SetHiddenInGame(true, true);
Mesh1P->SetHiddenInGame(false, true);
}
//MyDoorActor->PlayTimeline();
FString ActorLocation = GetActorLocation().ToString();
UE_LOG(LogTemp, Warning, TEXT("%s"), *ActorLocation);
}
//////////////////////////////////////////////////////////////////////////
// Input
void ATestingWorkCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
// set up gameplay key bindings
check(PlayerInputComponent);
// Bind jump events
PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);
// Bind fire event
PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &ATestingWorkCharacter::OnFire);
// Enable touchscreen input
EnableTouchscreenMovement(PlayerInputComponent);
PlayerInputComponent->BindAction("ResetVR", IE_Pressed, this, &ATestingWorkCharacter::OnResetVR);
// Bind movement events
PlayerInputComponent->BindAxis("MoveForward", this, &ATestingWorkCharacter::MoveForward);
PlayerInputComponent->BindAxis("MoveRight", this, &ATestingWorkCharacter::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", this, &APawn::AddControllerYawInput);
PlayerInputComponent->BindAxis("TurnRate", this, &ATestingWorkCharacter::TurnAtRate);
PlayerInputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
PlayerInputComponent->BindAxis("LookUpRate", this, &ATestingWorkCharacter::LookUpAtRate);
}
void ATestingWorkCharacter::OnFire()
{
// try and fire a projectile
ServerFire();
// try and play the sound if specified
if (FireSound != NULL)
{
UGameplayStatics::PlaySoundAtLocation(this, FireSound, GetActorLocation());
}
// try and play a firing animation if specified
if (FireAnimation != NULL)
{
// Get the animation object for the arms mesh
UAnimInstance* AnimInstance = FP_Gun->GetAnimInstance();
if (AnimInstance != NULL)
{
AnimInstance->Montage_Play(FireAnimation, 1.f);
}
}
}
void ATestingWorkCharacter::ServerFire_Implementation()
{
/*if (ProjectileClass != NULL)
{
UWorld* const World = GetWorld();
if (World != NULL)
{
if (bUsingMotionControllers)
{
const FRotator SpawnRotation = VR_MuzzleLocation->GetComponentRotation();
const FVector SpawnLocation = VR_MuzzleLocation->GetComponentLocation();
World->SpawnActor<ATestingWorkProjectile>(ProjectileClass, SpawnLocation, SpawnRotation);
}
else
{
FRotator MuzzleRotation = GetActorRotation();
const FVector MuzzleLocation = FP_Gun->GetSocketLocation("Muzzle");
// MuzzleOffset is in camera space, so transform it to world space before offsetting from the character location to find the final muzzle position
//const FVector SpawnLocation = ((FP_MuzzleLocation != nullptr) ? FP_MuzzleLocation->GetComponentLocation() : GetActorLocation()) + SpawnRotation.RotateVector(GunOffset);
MuzzleRotation.Pitch = RemoteViewPitch;
//Set Spawn Collision Handling Override
FActorSpawnParameters ActorSpawnParams;
ActorSpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButDontSpawnIfColliding;
// spawn the projectile at the muzzle
World->SpawnActor<ATestingWorkProjectile>(ProjectileClass, MuzzleLocation, MuzzleRotation, ActorSpawnParams);
}
}
}*/
// try and fire a projectile
if (ProjectileClass != NULL)
{
UWorld* const World = GetWorld();
if (World != NULL)
{
if (bUsingMotionControllers)
{
const FRotator SpawnRotation = VR_MuzzleLocation->GetComponentRotation();
const FVector SpawnLocation = VR_MuzzleLocation->GetComponentLocation();
World->SpawnActor<ATestingWorkProjectile>(ProjectileClass, SpawnLocation, SpawnRotation);
//ProjectileStartLocation = SpawnLocation;
}
else
{
const FRotator SpawnRotation = GetControlRotation();
// MuzzleOffset is in camera space, so transform it to world space before offsetting from the character location to find the final muzzle position
const FVector SpawnLocation = ((FP_MuzzleLocation != nullptr) ? FP_MuzzleLocation->GetComponentLocation() : GetActorLocation()) + SpawnRotation.RotateVector(GunOffset);
//Set Spawn Collision Handling Override
FActorSpawnParameters ActorSpawnParams;
int i = 0;
ATestingWorkCharacter* MyCharacter = Cast<ATestingWorkCharacter>(UGameplayStatics::GetPlayerCharacter(this, i));
while (MyCharacter != nullptr)
{
if (MyCharacter->GetActorLocation() == GetActorLocation())
{
if(Role == ROLE_Authority)
ActorSpawnParams.Owner = MyCharacter;
OwnerName = MyCharacter->GetName();
}
i++;
MyCharacter = Cast<ATestingWorkCharacter>(UGameplayStatics::GetPlayerCharacter(this, i));
}
ActorSpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButDontSpawnIfColliding;
// spawn the projectile at the muzzle
World->SpawnActor<ATestingWorkProjectile>(ProjectileClass, SpawnLocation, SpawnRotation, ActorSpawnParams);
}
}
}
}
bool ATestingWorkCharacter::ServerFire_Validate()
{
return true;
}
void ATestingWorkCharacter::OnResetVR()
{
UHeadMountedDisplayFunctionLibrary::ResetOrientationAndPosition();
}
void ATestingWorkCharacter::BeginTouch(const ETouchIndex::Type FingerIndex, const FVector Location)
{
if (TouchItem.bIsPressed == true)
{
return;
}
if ((FingerIndex == TouchItem.FingerIndex) && (TouchItem.bMoved == false))
{
OnFire();
}
TouchItem.bIsPressed = true;
TouchItem.FingerIndex = FingerIndex;
TouchItem.Location = Location;
TouchItem.bMoved = false;
}
void ATestingWorkCharacter::EndTouch(const ETouchIndex::Type FingerIndex, const FVector Location)
{
if (TouchItem.bIsPressed == false)
{
return;
}
TouchItem.bIsPressed = false;
}
//Commenting this section out to be consistent with FPS BP template.
//This allows the user to turn without using the right virtual joystick
//void ATestingWorkCharacter::TouchUpdate(const ETouchIndex::Type FingerIndex, const FVector Location)
//{
// if ((TouchItem.bIsPressed == true) && (TouchItem.FingerIndex == FingerIndex))
// {
// if (TouchItem.bIsPressed)
// {
// if (GetWorld() != nullptr)
// {
// UGameViewportClient* ViewportClient = GetWorld()->GetGameViewport();
// if (ViewportClient != nullptr)
// {
// FVector MoveDelta = Location - TouchItem.Location;
// FVector2D ScreenSize;
// ViewportClient->GetViewportSize(ScreenSize);
// FVector2D ScaledDelta = FVector2D(MoveDelta.X, MoveDelta.Y) / ScreenSize;
// if (FMath::Abs(ScaledDelta.X) >= 4.0 / ScreenSize.X)
// {
// TouchItem.bMoved = true;
// float Value = ScaledDelta.X * BaseTurnRate;
// AddControllerYawInput(Value);
// }
// if (FMath::Abs(ScaledDelta.Y) >= 4.0 / ScreenSize.Y)
// {
// TouchItem.bMoved = true;
// float Value = ScaledDelta.Y * BaseTurnRate;
// AddControllerPitchInput(Value);
// }
// TouchItem.Location = Location;
// }
// TouchItem.Location = Location;
// }
// }
// }
//}
void ATestingWorkCharacter::MoveForward(float Value)
{
if (Value != 0.0f)
{
// add movement in that direction
AddMovementInput(GetActorForwardVector(), Value);
}
}
void ATestingWorkCharacter::MoveRight(float Value)
{
if (Value != 0.0f)
{
// add movement in that direction
AddMovementInput(GetActorRightVector(), Value);
}
}
void ATestingWorkCharacter::TurnAtRate(float Rate)
{
// calculate delta for this frame from the rate information
AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds());
}
void ATestingWorkCharacter::LookUpAtRate(float Rate)
{
// calculate delta for this frame from the rate information
AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds());
}
bool ATestingWorkCharacter::EnableTouchscreenMovement(class UInputComponent* PlayerInputComponent)
{
if (FPlatformMisc::SupportsTouchInput() || GetDefault<UInputSettings>()->bUseMouseForTouch)
{
PlayerInputComponent->BindTouch(EInputEvent::IE_Pressed, this, &ATestingWorkCharacter::BeginTouch);
PlayerInputComponent->BindTouch(EInputEvent::IE_Released, this, &ATestingWorkCharacter::EndTouch);
//Commenting this out to be more consistent with FPS BP template.
//PlayerInputComponent->BindTouch(EInputEvent::IE_Repeat, this, &ATestingWorkCharacter::TouchUpdate);
return true;
}
return false;
}
void ATestingWorkCharacter::GetLifetimeReplicatedProps(TArray <FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
//DOREPLIFETIME(ATestingWorkCharacter, CurrentScore);
//DOREPLIFETIME(ATestingWorkCharacter, Score25);
//DOREPLIFETIME(ATestingWorkCharacter, OtherScore);
//DOREPLIFETIME(ATestingWorkCharacter, OwnerName);
}