diff --git a/Content/ProofOfConcept/DDICharacter_BP.uasset b/Content/ProofOfConcept/DDICharacter_BP.uasset index f48eabb..c71ca88 100644 Binary files a/Content/ProofOfConcept/DDICharacter_BP.uasset and b/Content/ProofOfConcept/DDICharacter_BP.uasset differ diff --git a/Content/ProofOfConcept/ProjectileBase_BP.uasset b/Content/ProofOfConcept/ProjectileBase_BP.uasset new file mode 100644 index 0000000..ce9a0f7 Binary files /dev/null and b/Content/ProofOfConcept/ProjectileBase_BP.uasset differ diff --git a/Content/Worlds/_GENERATED/Core/ProjectileBase.uasset b/Content/Worlds/_GENERATED/Core/ProjectileBase.uasset new file mode 100644 index 0000000..384d215 Binary files /dev/null and b/Content/Worlds/_GENERATED/Core/ProjectileBase.uasset differ diff --git a/Source/OpenConflict/PlayerCharacter/Components/DDIHealth.cpp b/Source/OpenConflict/PlayerCharacter/Components/DDIHealth.cpp index b9fa2bd..37b08f5 100644 --- a/Source/OpenConflict/PlayerCharacter/Components/DDIHealth.cpp +++ b/Source/OpenConflict/PlayerCharacter/Components/DDIHealth.cpp @@ -9,6 +9,7 @@ UDDIHealth::UDDIHealth() // Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features // off to improve performance if you don't need them. PrimaryComponentTick.bCanEverTick = true; + SetIsReplicatedByDefault(true); MaxHealth = 0; CurrentHealth = 0; ClassName = ClassNames::Scout; @@ -41,7 +42,7 @@ void UDDIHealth::BeginPlay() MaxHealth += seg; CurrentHealth = MaxHealth; - GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Cyan, FString::Printf(TEXT("CurrentHealth: %d"), CurrentHealth)); + GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Emerald, FString::Printf(TEXT("CurrentHealth: %d"), CurrentHealth)); } @@ -81,10 +82,9 @@ void UDDIHealth::Heal() // Called to cause damage void UDDIHealth::TakeDamage(int DamageValue) { - // if (HealTimer.IsValid()) - // HealTimer.Invalidate(); GetWorld()->GetTimerManager().ClearTimer(HealTimer); CurrentHealth -= DamageValue; + GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Cyan, FString::Printf(TEXT("Client Hit\nHealth: %d"), CurrentHealth)); } \ No newline at end of file diff --git a/Source/OpenConflict/PlayerCharacter/Components/DDIHealth.h b/Source/OpenConflict/PlayerCharacter/Components/DDIHealth.h index 00a35f1..8ec3581 100644 --- a/Source/OpenConflict/PlayerCharacter/Components/DDIHealth.h +++ b/Source/OpenConflict/PlayerCharacter/Components/DDIHealth.h @@ -36,13 +36,13 @@ protected: ClassNames ClassName; /*Functions*/ - UFUNCTION(BlueprintAuthorityOnly, BlueprintCallable, Category = "Health") - void TakeDamage(int DamageValue); public: /*Properties*/ /*Functions*/ + UFUNCTION(BlueprintAuthorityOnly, BlueprintCallable, Category = "Health") + void TakeDamage(int DamageValue); /*C++ only declarations*/ private: diff --git a/Source/OpenConflict/PlayerCharacter/Components/HealthSegmentStruct.h b/Source/OpenConflict/PlayerCharacter/Components/HealthSegmentStruct.h index 72fb3f1..5761a30 100644 --- a/Source/OpenConflict/PlayerCharacter/Components/HealthSegmentStruct.h +++ b/Source/OpenConflict/PlayerCharacter/Components/HealthSegmentStruct.h @@ -9,7 +9,7 @@ struct FHealthSegment : public FTableRowBase GENERATED_BODY() UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Health Segments") - ClassNames Class; + ClassNames Class = ClassNames::Basic; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Health Segments") TArray SegmentList; diff --git a/Source/OpenConflict/PlayerCharacter/DDICharacter.cpp b/Source/OpenConflict/PlayerCharacter/DDICharacter.cpp index 7aa05ca..ff03254 100644 --- a/Source/OpenConflict/PlayerCharacter/DDICharacter.cpp +++ b/Source/OpenConflict/PlayerCharacter/DDICharacter.cpp @@ -2,7 +2,10 @@ #include "DDICharacter.h" + +#include "Components/CapsuleComponent.h" #include "GameFramework/SpringArmComponent.h" +#include "OpenConflict/Weapons/Projectiles/ProjectileBase.h" // Sets default values ADDICharacter::ADDICharacter() @@ -17,6 +20,12 @@ ADDICharacter::ADDICharacter() CameraComponent->SetRelativeLocation(FVector(0.0f, 0.0f, 50.0f)); CameraComponent->bUsePawnControlRotation = true; + HealthComponent = CreateDefaultSubobject(TEXT("HealthComponent")); + + GetCapsuleComponent()->SetCollisionProfileName(TEXT("BlockAllDynamic")); + GetCapsuleComponent()->SetGenerateOverlapEvents(true); + GetCapsuleComponent()->SetNotifyRigidBodyCollision(true); + } @@ -24,6 +33,11 @@ ADDICharacter::ADDICharacter() void ADDICharacter::BeginPlay() { Super::BeginPlay(); + + if (GetCapsuleComponent()) + { + GetCapsuleComponent()->OnComponentHit.AddDynamic(this, &ADDICharacter::OnHit); + } } @@ -34,4 +48,69 @@ void ADDICharacter::Tick(float DeltaTime) } +void ADDICharacter::OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit) +{ + Server_CharacterHit(HitComponent, OtherActor, OtherComp, NormalImpulse, Hit); +} +void ADDICharacter::TakeDamage(int Damage) +{ + HealthComponent->TakeDamage(Damage); +} + +bool ADDICharacter::Server_SpawnProjectile_Validate() +{ + return true; +} +void ADDICharacter::Server_SpawnProjectile_Implementation() +{ + FVector Location = GetActorLocation(); + FRotator Rotation = GetActorRotation(); + FVector Dir = GetActorForwardVector(); + + Location += Dir * 200.f; + if (!ProjectileClass) + { + GEngine->AddOnScreenDebugMessage(1, 10.f, FColor::Emerald, "No Projectile Set"); + return; + } + GetWorld()->SpawnActor(ProjectileClass, Location, Rotation); + + + +} + +void ADDICharacter::Client_CharacterHit_Implementation() +{ + TakeDamage(10); + OnDamageTaken(); + +} +bool ADDICharacter::Client_CharacterHit_Validate() +{ + return true; +} +void ADDICharacter::Server_CharacterHit_Implementation(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit) +{ + if (AProjectileBase* Projectile = Cast(OtherActor)) + { + // if (Cast(Projectile->Owner) == this) + GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Emerald, "Damage dealt"); + Client_CharacterHit(); + } +} +bool ADDICharacter::Server_CharacterHit_Validate(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit) +{ + return true; +} + +void ADDICharacter::OnRep_Health() +{ + GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, "Health Replicated"); +} + +void ADDICharacter::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + DOREPLIFETIME(ADDICharacter, HealthComponent); +} \ No newline at end of file diff --git a/Source/OpenConflict/PlayerCharacter/DDICharacter.h b/Source/OpenConflict/PlayerCharacter/DDICharacter.h index 6119fe4..53993d4 100644 --- a/Source/OpenConflict/PlayerCharacter/DDICharacter.h +++ b/Source/OpenConflict/PlayerCharacter/DDICharacter.h @@ -4,7 +4,9 @@ #include "CoreMinimal.h" #include "Camera/CameraComponent.h" +#include "Components/DDIHealth.h" #include "GameFramework/Character.h" +#include "Net/UnrealNetwork.h" #include "DDICharacter.generated.h" @@ -12,20 +14,69 @@ UCLASS() class OPENCONFLICT_API ADDICharacter : public ACharacter { GENERATED_BODY() + /*UPROPERTY and UFUNCTION declarations*/ +private: + /*Properties*/ -public: - // Sets default values for this character's properties - ADDICharacter(); + /*Functions*/ protected: + /*Properties*/ + + /*Functions*/ + UFUNCTION(BlueprintImplementableEvent, Category = "Events") + void OnDamageTaken(); + +public: + /*Properties*/ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Camera") + UCameraComponent* CameraComponent; + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Health", ReplicatedUsing=OnRep_Health) + UDDIHealth* HealthComponent; + + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Projectile") + TSubclassOf ProjectileClass; + + /*Functions*/ + UFUNCTION() + void OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit); + + UFUNCTION() + void TakeDamage(int Damage); + + UFUNCTION(Server, Reliable, WithValidation, BlueprintCallable) + void Server_SpawnProjectile(); + + UFUNCTION(Client, Reliable, WithValidation, BlueprintCallable) + void Client_CharacterHit(); + + UFUNCTION(Server, Reliable, WithValidation, BlueprintCallable) + void Server_CharacterHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit); + + UFUNCTION() + void OnRep_Health(); + + /*C++ only declarations*/ +private: + /*Properties*/ + + /*Functions*/ + +protected: + /*Properties*/ + + /*Functions*/ // Called when the game starts or when spawned virtual void BeginPlay() override; -public: +public: + /*Properties*/ + + /*Functions*/ + // Sets default values for this character's properties + ADDICharacter(); // Called every frame virtual void Tick(float DeltaTime) override; - - UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Camera") - UCameraComponent* CameraComponent; - + + }; diff --git a/Source/OpenConflict/Weapons/Projectiles/ProjectileBase.cpp b/Source/OpenConflict/Weapons/Projectiles/ProjectileBase.cpp new file mode 100644 index 0000000..e794add --- /dev/null +++ b/Source/OpenConflict/Weapons/Projectiles/ProjectileBase.cpp @@ -0,0 +1,52 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "ProjectileBase.h" + +#include "OpenConflict/PlayerCharacter/DDICharacter.h" + +// Sets default values +AProjectileBase::AProjectileBase() +{ + // 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; + bReplicates = true; + bNetLoadOnClient = true; + + InitialLifeSpan = 3.f; + + + collision = CreateDefaultSubobject("Collision"); + RootComponent = collision; + collision->BodyInstance.SetCollisionProfileName(TEXT("BlockAllDynamic")); + + projectileMesh = CreateDefaultSubobject("ProjectileMesh"); + projectileMesh->SetupAttachment(collision); + + projectileMotion = CreateDefaultSubobject("ProjectileMovementComponent"); +} + +// Called when the game starts or when spawned +void AProjectileBase::BeginPlay() +{ + Super::BeginPlay(); + + if (collision) + collision->OnComponentHit.AddDynamic(this, &AProjectileBase::OnHit); + +} + +// Called every frame +void AProjectileBase::Tick(float DeltaTime) +{ + Super::Tick(DeltaTime); + +} + + +void AProjectileBase::OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit) +{ + // if (ADDICharacter* character = Cast(OtherActor)) + Destroy(); + +} \ No newline at end of file diff --git a/Source/OpenConflict/Weapons/Projectiles/ProjectileBase.h b/Source/OpenConflict/Weapons/Projectiles/ProjectileBase.h new file mode 100644 index 0000000..7341cff --- /dev/null +++ b/Source/OpenConflict/Weapons/Projectiles/ProjectileBase.h @@ -0,0 +1,64 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Components/SphereComponent.h" +#include "GameFramework/Actor.h" +#include "GameFramework/ProjectileMovementComponent.h" +#include "ProjectileBase.generated.h" + +UCLASS() +class OPENCONFLICT_API AProjectileBase : public AActor +{ + GENERATED_BODY() + /*UPROPERTY and UFUNCTION declarations*/ +private: + /*Properties*/ + + /*Functions*/ + +protected: + /*Properties*/ + + /*Functions*/ + +public: + /*Properties*/ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Projectile") + UStaticMeshComponent* projectileMesh; + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Projectile") + USphereComponent* collision; + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Projectile") + UProjectileMovementComponent* projectileMotion; + + /*Functions*/ + UFUNCTION() + void OnHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit); + + + /*C++ only declarations*/ +private: + /*Properties*/ + + /*Functions*/ + +protected: + /*Properties*/ + + /*Functions*/ + // Called when the game starts + virtual void BeginPlay() override; + +public: + /*Properties*/ + + /*Functions*/ + + // Called every frame + virtual void Tick(float DeltaTime) override; + + // Sets default values for this actor's properties + AProjectileBase(); + +}; diff --git a/Source/OpenConflict/Weapons/WeaponBase.cpp b/Source/OpenConflict/Weapons/WeaponBase.cpp new file mode 100644 index 0000000..6449d14 --- /dev/null +++ b/Source/OpenConflict/Weapons/WeaponBase.cpp @@ -0,0 +1,27 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "WeaponBase.h" + +// Sets default values +AWeaponBase::AWeaponBase() +{ + // 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; + +} + +// Called when the game starts or when spawned +void AWeaponBase::BeginPlay() +{ + Super::BeginPlay(); + +} + +// Called every frame +void AWeaponBase::Tick(float DeltaTime) +{ + Super::Tick(DeltaTime); + +} + diff --git a/Source/OpenConflict/Weapons/WeaponBase.h b/Source/OpenConflict/Weapons/WeaponBase.h new file mode 100644 index 0000000..962ab25 --- /dev/null +++ b/Source/OpenConflict/Weapons/WeaponBase.h @@ -0,0 +1,26 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "GameFramework/Actor.h" +#include "WeaponBase.generated.h" + +UCLASS() +class OPENCONFLICT_API AWeaponBase : public AActor +{ + GENERATED_BODY() + +public: + // Sets default values for this actor's properties + AWeaponBase(); + +protected: + // Called when the game starts or when spawned + virtual void BeginPlay() override; + +public: + // Called every frame + virtual void Tick(float DeltaTime) override; + +};