Imaginons que vous créiez un jeu qui implique d'infliger des dégâts à un joueur, un ennemi ou un objet. Vous aurez certainement affaire à des situations dans lesquelles vous devrez déterminer si ces objets ont été touchés par quelque chose et, le cas échéant, ce qui les a touchés, où était le point d'impact et d'autres informations concernant le coup détecté. L'événement OnHit indique ces données lorsque des collisions surviennent ; vous pouvez alors les utiliser pour apporter des changements à votre jeu. Il peut s'agir de diminuer la santé d'un personnage, de détruire un objet ou de déclencher d'autres actions de gameplay.
Dans ce tutoriel, vous utiliserez les événements OnComponentHit et Function pour infliger des dégâts à un acteur dont le matériau du maillage sera modifié en conséquence. Les événements appliqueront également une impulsion au point d'impact pour repousser l'acteur et simuler l'effet de la force du projectile.
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(); }