Imagine que você está criando um jogo que envolve danos a um jogador, inimigo ou objeto. Nesse caso, é bem possível que você se depare com uma situação em que precisará determinar se esses objetos foram atingidos por algo e, se sim, o que os atingiu, onde foi o ponto de impacto e outras informações relacionados ao impacto detectado. O evento OnHit fornece essas informações quando ocorre a colisão, possibilitando que você use esses dados para acionar alterações no jogo. Determina se afetará a vida, destruirá um objeto ou causará outras ações relacionadas à jogabilidade.
Neste tutorial, você usará os eventos OnComponentHit e Function para causar dano a um ator, representados na alteração do material da malha do ator. Os eventos também aplicarão um impulso no local de impacto para empurrar o ator, simulando os efeitos de ser atingido por um projétil e aplicando força no local de impacto.
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(); }