Stellen Sie sich vor, Sie erschaffen ein Spiel, in dem ein Spieler, ein Gegner oder ein Objekt auf irgendeine Art Schaden erleiden muss. Dann kann es ein, dass Sie bestimmen müssen, ob diese Objekte von etwas getroffen wurden, und wenn ja, wovon sie getroffen wurden, wo der Einschlagpunkt war, oder Sie andere Informationen über den festgestellten Treffer erhalten möchten. Das OnHit-Event liefert diese Informationen, wenn es zur die Kollision kommt, und Sie können mit diesen Daten Änderungen in Ihrem Spiel auslösen. Egal, ob es dabei um Gesundheit geht, ein Objekt zerstört wird oder andere mit dem Gameplay in Zusammenhang stehende Aktionen ausgelöst werden.
In diesem Tutorial nutzen Sie die OnComponentHit und Funktion Events, um Schaden auf einen Actor anzuwenden, der durch Änderungen am Mesh-Material des Actors repräsentiert wird. Die Events wenden am Einschlagpunkt auch einen Impuls an, um den Actor wegzustoßen und simulieren so die Effekte eines Projektiltreffers und der Einwirkung einer Kraft an der getroffenen Stelle.
Project Setup
Begin by creating a new Games > First Person > C++ Project named OnHit.
Creating the Mesh Material
Navigate to the Content Browser, and find the LevelPrototyping/Materials folder.
Select MI_SolidBlue, then duplicate (CTRL+ D) and rename the newly duplicated asset MI_Solid_Red.
Double-click to open the asset, then select and edit the Base Color to the color red.
Save the Asset.
Creating the Cube Actor
In the Editor, click Add(+) > New C++ Class, then choose Actor as your parent class and name your class Cube.
Declare the following class defaults in your
cube.hfileC++UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) class UStaticMeshComponent* CubeMesh; UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) UMaterialInstance* CubeMaterial; UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) UMaterialInstance* DamagedCubeMaterial; FTimerHandle DamageTimer;Next, in your
cube.cppfile, declare the following class libraries.C++#include "Kismet/GameplayStatics.h" #include "OnHitProjectile.h"Navigate to the cube constructor and implement the following functionality.
C++ACube::ACube() { CubeMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("CubeMesh")); DamagedCubeMaterial = CreateDefaultSubobject<UMaterialInstance>(TEXT("DamageMaterial")); CubeMaterial = CreateDefaultSubobject<UMaterialInstance>(TEXT("CubeMaterial")); CubeMesh->SetSimulatePhysics(true); }
Implementing the Damage functionality
Now that you created a cube, you need to implement a function that sets the mesh's material when it receives damage, then after a delay resets the mesh back to its original material.
Declare the following code in your
cube.hfile.C++void OnTakeDamage(); void ResetDamage();Navigate to the
cube.cppfile and implement the following for theACube::BeginPlayfunction.C++void ACube::BeginPlay() { CubeMesh->OnComponentHit.AddDynamic(this, &ACube::OnComponentHit); }Implement the
ACube::OnTakeDamagefunction.C++void ACube::OnTakeDamage() { CubeMesh->SetMaterial(0, DamagedCubeMaterial); GetWorld()->GetTimerManager().SetTimer(DamageTimer, this, &ACube::ResetDamage, 1.5f, false); }Next, implement the
ACube::ResetDamagefunction.C++void ACube::ResetDamage() { CubeMesh->SetMaterial(0,CubeMaterial); }Finally, navigate to the
ACube::OnComponentHitfunction and implement the following code.C++void ACube::OnComponentHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit) { if (AOnHitProjectile* HitActor = Cast<AOnHitProjectile>(OtherActor)) { UGameplayStatics::ApplyDamage(this, 20.0f, nullptr, OtherActor, UDamageType::StaticClass()); OnTakeDamage(); } }Compile your code.
In the editor, navigate to C++ Classes > Cube then right-click on the Cube Actor and select Create Blueprint class based on Cube.
From the Components tab, select the Cube Mesh, then navigate to Details > Static Mesh and select the SM_ChamferCube asset.
In the class defaults of the BP_Cube, set the Cube Material to the MI_Solid_Blue asset, and the Damaged Cube Material to the MI_Solid_Red asset.
Compile and Save.
CubeActor.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Cube.generated.h"
UCLASS()
class ONHIT_API ACube : public AActor
{
GENERATED_BODY()
CubeActor.cpp
#include "Cube.h"
#include "Kismet/GameplayStatics.h"
#include "OnHitProjectile.h"
// Sets default values
ACube::ACube()
{
// 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;
Setting up the Level
Drag the BP_Cube into the level from the Content Browser.
Navigate to the Outliner > Simulated Cubes, select all SM_ChauferCubes then right-click and select Replace Selected Actors with > BP_Cube.
Click Play to play in the editor and use the left-mouse button to fire a projectile at the cube.
When you play in the editor, you will see that when you hit the cube with the projectile fired it causes the cube to take damage and change its mesh material, and applies an impulse at the location where it was hit causing it to move opposite the direction of the projectile.
The amount of force applied is defined inside the
OnHitProjectile.cppfile which uses the OnHit function to determine when the projectile actually hits something.C++void AOnHitCPPProjectile::OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit) { // Only add impulse and destroy projectile if we hit a physics if ((OtherActor != nullptr) && (OtherActor != this) && (OtherComp != nullptr) && OtherComp->IsSimulatingPhysics()) { OtherComp->AddImpulseAtLocation(GetVelocity() * 100.0f, GetActorLocation()); Destroy(); }