想象一下你正在创建一款游戏,游戏中涉及对玩家、敌人或物体施加某种类型的伤害。 在这种情况下,你很可能遇到这样的情形:你需要确定这些物体是否被击中,如果是,是什么击中了它们,击中点在哪里,或者有关检测到的攻击的其他信息。 OnHit事件(OnHit Event)会在发生碰撞时提供此信息,然后你可以利用数据来推动游戏中的变化。 无论是要影响生命值、摧毁对象,还是导致其他Gameplay相关的操作。
在本教程中,你将使用OnComponentHit和Function事件对Actor施加伤害,而伤害效果将通过更改Actor的网格体材质来呈现。 事件还将在击中位置施加推力推动Actor,模拟被发射物击中的效果,并在击中位置施加作用力。
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(); }