The amount of homework this time may be a bit larger than the previous ones. Let me sort out the homework list for this time:
- The flying sound of magic bullets and the sound of explosion
- Adds a shiny effect to the player when hit, the same kind as the cube
- Add a health max variable, replace the health node in the widget with the health max node, and set an upper and lower limit for health, the upper limit is health max, and the lower limit is 0
- Set an animation for the damage display widget we just created, and play it when it is hit. At the same time, the damage display cannot be written to death, and it is represented by a variable
- Create a new health potion, which can restore health. After recovering once, it cannot be used again within 10 seconds, and can be used again after 10 seconds. Ignore player interaction when player is full health
- Add a particle effect to the player’s hand (I didn’t understand this, I didn’t write it)
- Add a shake camera effect
There are a total of 7 assignments, and the amount can be said to be very large. . . But still do it one by one.
1. The flying sound and explosion effect of the magic bullet:
I wrote this function into SFatherMagicProjectile
SFatherMagicProjectile.h
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "SFatherMagicProjectile.generated.h" UCLASS() class ACTIONROGUELIKE_API ASFatherMagicProjectile : public AActor {<!-- --> GENERATED_BODY() public: UPROPERTY (Edit Anywhere) class USphereComponent * SphereComp; UPROPERTY (Edit Anywhere) class UProjectileMovementComponent * MovementComp; UPROPERTY (Edit Anywhere) class UParticleSystemComponent * ParticleComp; \t //A sound component UPROPERTY (Edit Anywhere) class UAudioComponent * AudioComp; \t //Explosion UPROPERTY (Edit Anywhere) class USoundBase * Sound; \t public: // Sets default values for this actor's properties ASFatherMagicProjectile(); protected: // Called when the game starts or when spawned virtual void BeginPlay() override; public: // Called every frame virtual void Tick(float DeltaTime) override; UFUNCTION() virtual void OnComponentHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, FHitResult Hit); UFUNCTION() void OnComponentOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & amp; SweepResult); };
SFatherMagicProjectile.cpp
// Fill out your copyright notice in the Description page of Project Settings. #include "SFatherMagicProjectile.h" #include "Components/SphereComponent.h" #include "GameFramework/ProjectileMovementComponent.h" #include "Particles/ParticleSystemComponent.h" #include "SAttributeComponent.h" #include "Components/AudioComponent.h" #include "Kismet/GameplayStatics.h" // Sets default values ASFatherMagicProjectile::ASFatherMagicProjectile() {<!-- --> // 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; FScriptDelegate OnHit; OnHit.BindUFunction(this, STATIC_FUNCTION_FNAME(TEXT("ASFatherMagicProjectile::OnComponentHit"))); FScriptDelegateOnOverlap; OnOverlap.BindUFunction(this, STATIC_FUNCTION_FNAME(TEXT("ASFatherMagicProjectile::OnComponentOverlap"))); SphereComp = CreateDefaultSubobject<USphereComponent>(TEXT("Sphere Comp")); SphereComp->SetCollisionProfileName("Projectile"); SphereComp->SetSphereRadius(10.0f, true); SphereComp->OnComponentHit.Add(OnHit); SphereComp->OnComponentBeginOverlap. Add(OnOverlap); RootComponent = SphereComp; MovementComp = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("Movement Comp")); MovementComp->InitialSpeed = 1000.0f; MovementComp->bRotationFollowsVelocity = true; MovementComp->bInitialVelocityInLocalSpace = true; MovementComp->ProjectileGravityScale = 0.0f; ParticleComp = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("Particle Comp")); ParticleComp->SetupAttachment(SphereComp); AudioComp = CreateDefaultSubobject<UAudioComponent>(TEXT("Audio Comp")); \t } // Called when the game starts or when spawned void ASFatherMagicProjectile::BeginPlay() {<!-- --> Super::BeginPlay(); APawn* Instigator_01 = AActor::GetInstigator(); SphereComp->IgnoreActorWhenMoving(Instigator_01, true); //play flight sound AudioComp->Play(0.0f); \t } // Called every frame void ASFatherMagicProjectile::Tick(float DeltaTime) {<!-- --> Super::Tick(DeltaTime); } void ASFatherMagicProjectile::OnComponentHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, FHitResult Hit) {<!-- --> APawn* Instigator_01 = AActor::GetInstigator(); if (Instigator_01!=OtherActor) {<!-- --> //play the explosion sound UGameplayStatics::PlaySoundAtLocation(GetWorld(),Sound , this->GetActorLocation(), 1.0f, 1.0f); GetWorld()->DestroyActor(this); DrawDebugSphere(GetWorld(), Hit. ImpactPoint, 10.0f, 16, FColor::Red, false, 2.0f, 0U, 1.0f); \t\t } } void ASFatherMagicProjectile::OnComponentOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & amp; SweepResult) {<!-- --> APawn* Instigator_01 = AActor::GetInstigator(); if (OtherActor) {<!-- --> USAttributeComponent* AttributeComp = Cast<USAttributeComponent>(OtherActor->GetComponentByClass(USAttributeComponent::StaticClass())); if (AttributeComp) {<!-- --> if (Instigator_01 != OtherActor) {<!-- --> UGameplayStatics::Play AtLocation(GetWorld(), Sound, this->GetActorLocation(), 1.0f, 1.0f); AttributeComp->ApplyHealthChange(-20.0f); GetWorld()->DestroyActor(this); } } } }
2. Add a shiny effect to the player, the same as the cube
This first has to modify the material of our Gideon
Use the MatLayerBlend_Emissive function, and then connect our MF_HitFlash, and then change the code of the player character
SCharacter.cpp
void ASCharacter::OnHealthChanged(AActor* InstigatorActor, USAttributeComponent* OwningComp, float NewHealth, float Delta) {<!-- --> //This function has been changed. The first point is that only damage will trigger the shining effect, and it does not need to trigger this effect when adding blood if (NewHealth<0.0f) {<!-- --> this->GetMesh()->SetScalarParameterValueOnMaterials("TimeToHit", GetWorld()->TimeSeconds); if (Delta<0.0f) {<!-- --> APlayerController* PC = Cast<APlayerController>(GetController()); DisableInput(PC); } } \t }
3. Add a health max variable, replace the health node in the widget with the health max node, and set an upper and lower limit for health, the upper limit is health max, and the lower limit is 0
This is quite simple, change as follows
SAttributeComponent.cpp
bool USAttributeComponent::ApplyHealthChange(float Delta) {<!-- --> \t //Using the Clamp function, the change of Health is displayed in the first parameter of the Clamp function Health = FMath::Clamp(Health + Delta, 0, HealthMax); OnHealthChanged. Broadcast(nullptr, this, Health, Delta); return true; }
4. Set an animation for the widget we just created to display the damage, and play it when it is hit. At the same time, the damage display cannot be written to death, and it is represented by a variable
Cube blueprint changes
As for how to play the animation, it depends on everyone’s design. There are thousands of people and faces here.
5. Create a new health potion, which can restore health. After recovering once, it cannot be used again within 10 seconds, and can be used again after 10 seconds. Ignore player interaction when player is full health
This has not encountered any major problems. The example of this is our box that can be opened and closed.
SHealBottle.h
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "SGameplayInterface.h" #include "SHealBottle.generated.h" UCLASS() class ACTIONROGUELIKE_API ASHealBottle : public AActor, public ISGameplayInterface {<!-- --> GENERATED_BODY() void Interact_Implementation(APawn* InstigatorPawn) override; UPROPERTY (VisibleAnywhere) class UStaticMeshComponent* MeshComp; private: UFUNCTION() void RefreshBottle(); private: bool CanHeal; \t FTimerHandle Timer; public: // Sets default values for this actor's properties ASHealBottle(); protected: // Called when the game starts or when spawned virtual void BeginPlay() override; public: // Called every frame virtual void Tick(float DeltaTime) override; };
SHealBottle.cpp
// Fill out your copyright notice in the Description page of Project Settings. #include "SHealBottle.h" #include "Components/StaticMeshComponent.h" #include "SAttributeComponent.h" //Implementation of the interface function void ASHealBottle::Interact_Implementation(APawn* InstigatorPawn) {<!-- --> ASCharacter* InstigatorCharacter_01 = Cast<ASCharacter>(InstigatorPawn); USAttributeComponent* attributeComp_01 = InstigatorCharacter_01->AttributeComp; if (attributeComp_01->GetHealth()>=100||!CanHeal) {<!-- --> return; } attributeComp_01->ApplyHealthChange(10.0f); CanHeal = false; MeshComp->SetVisibility(false); //disappear for 10 seconds GetWorldTimerManager().SetTimer(Timer,this, &ASHealBottle::RefreshBottle, 10.0f); } void ASHealBottle::RefreshBottle() {<!-- --> CanHeal = true; MeshComp->SetVisibility(true); } // Sets default values ASHealBottle::ASHealBottle() {<!-- --> // 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; MeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh Comp")); CanHeal = true; } // Called when the game starts or when spawned void ASHealBottle::BeginPlay() {<!-- --> Super::BeginPlay(); \t } // Called every frame void ASHealBottle::Tick(float DeltaTime) {<!-- --> Super::Tick(DeltaTime); }
7. Add an effect of shaking the camera
SCharacter.cpp
void ASCharacter::PrimaryAttack() {<!-- --> \t // get the controller APlayerController* pc = Cast<APlayerController>(GetController()); //Play the vibration of the camera pc->ClientStartCameraShake(CameraShakeComp); GetWorldTimerManager().SetTimer(TimerHandle_PrimaryAttack, this, &ASCharacter::PrimaryAttack_TimeElasped, 0.2f); \t }