Unreal Engine C++ The Ultimate Shooter Course (5)
카테고리: Unreal Engine
Chapter 12 Download Footsteps Assets
12-230 Download Footsteps Assets
- finish
12-231 Setup Assets for Footsteps
12-232 Define Physical Surface Types
// shooter.h
#define EPS_Metal EPhysicalSurface::SurfaceType1
#define EPS_Stone EPhysicalSurface::SurfaceType2
#define EPS_Tile EPhysicalSurface::SurfaceType3
#define EPS_Grass EPhysicalSurface::SurfaceType4
#define EPS_Water EPhysicalSurface::SurfaceType5
12-233 Creating Physical Materials
12-234 Footstep Sync Markers
- It has bug so in the meantime, we’re going to have to wait and make do with just our trimmed animations
- If we have an animation notify to play a sound here at jog start, is that going to be played in addition to the animation notify in jog forward That’s an issue
- We can solve this issue by designating one particular animation to be the leader and one particular animation to be a follower
- The leader will have its animation notifies, all triggered, whereas all followers will not have their animation notifies triggered if they’re following a leader
12-235 Custom Anim Notify
- As we see here, that’s because the forward animation is designated to be the leader and the jog left animation is the follower in relation to the jog forward animation
- And so that means we won’t get double footstep and notifies played at the same time
12-236 Adding Notifies to Animations
12-237 Setting Bone Name for Each Notify
12-238 Playing Sounds with Anim Notify
12-239 Line Trace for Physical Surface Type
12-240 The Grass Surface Type
12-241 Get Surface Type
// Shooter.Builds.cs
//..
// Now that we have PhysicsCore, we will be able to have the physical surface type as a function return type
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "UMG", "PhysicsCore" });
//..
12-242 Implement Footsteps Notify
12-243 Jumping and Landing Sounds
12-244 Turning Hips While Running
12-245 Turn Hips While Running Backwards
Chapter 13 Multiple Character Meshes
13-246 Retargeting the Animation Blueprint
13-247 Setting Up TwinBlast Character Blueprint
13-248 Tweaking TwinBlast
13-249 Phase
Chapter 14 The Enemy Class
14-250 Enemy Assets
14-251 The Enemy Class
14-252 Bullet Hit Interface
class SHOOTER_API IBulletHitInterface
{
GENERATED_BODY()
// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
// BlueprintNativeEvent에 대해 나중에 좀 알아봐야함
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
void BulletHit(FHitResult HitResult);
};
class SHOOTER_API AEnemy : public ACharacter, public IBulletHitInterface
{
//..
public:
// IBulletHitInterface의 BulletHit를 구현한거라고 하는데 이게 말이 되는지 모르겠음
virtual void BulletHit_Implementation(FHitResult HitResult) override;
}
14-253 Bullet Hit Interface
void AEnemy::BulletHit_Implementation(FHitResult HitResult)
{
if (ImpactSound)
{
UGameplayStatics::PlaySoundAtLocation(this, ImpactSound, GetActorLocation());
}
if (ImpactParticles)
{
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), ImpactParticles, HitResult.Location, FRotator(0.f), true);
}
}
14-254 Explosive
14-255 Damage
class SHOOTER_API AEnemy : public ACharacter, public IBulletHitInterface
{
//..
// Take damage is a function inherited from the actor class
virtual float TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser) override;
}
void AShooterCharacter::SendBullet()
{
//..
AEnemy* HitEnemy = Cast<AEnemy>(BeamHitResult.Actor.Get());
if (HitEnemy)
{
// If that actor implements take damage, then it's take damage function will be called
UGameplayStatics::ApplyDamage(
BeamHitResult.Actor.Get(),
EquippedWeapon->GetHeadShotDamage(),
GetController(),
this,
UDamageType::StaticClass());
}
//..
}
14-256 Head Shot Damage
void AShooterCharacter::SendBullet()
{
//..
if (BeamHitResult.BoneName.ToString() == HitEnemy->GetHeadBone())
{
// Head shot
UGameplayStatics::ApplyDamage(
BeamHitResult.Actor.Get(),
EquippedWeapon->GetHeadShotDamage(),
GetController(),
this,
UDamageType::StaticClass());
}
//..
}
14-257 Enemy Health Bar
14-258 Hide Health Bar
14-259 Enemy Death Function
float AEnemy::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
if (Health - DamageAmount <= 0.f)
{
Health = 0.f;
Die();
}
else
{
Health -= DamageAmount;
}
return DamageAmount;
}
14-260 Enemy Anim Instance
14-261 EnemyHit Montage
14-262 Play Montage Sections
void AEnemy::PlayHitMontage(FName Section, float PlayRate)
{
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
if (AnimInstance)
{
AnimInstance->Montage_Play(HitMontage, PlayRate);
AnimInstance->Montage_JumpToSection(Section, HitMontage);
}
}
14-263 Hit React Delay
void AEnemy::PlayHitMontage(FName Section, float PlayRate)
{
if (bCanHitReact)
{
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
if (AnimInstance)
{
AnimInstance->Montage_Play(HitMontage, PlayRate);
AnimInstance->Montage_JumpToSection(Section, HitMontage);
}
bCanHitReact = false;
const float HitReactTime{ FMath::FRandRange(HitReactTimeMin, HitReactTimeMax) };
GetWorldTimerManager().SetTimer(
HitReactTimer,
this,
&AEnemy::ResetHitReactTimer,
HitReactTime);
}
}
14-264 Show Hit Numbers
14-265 Store Hit Number Locations
14-266 Remove Hit Number
void AEnemy::StoreHitNumber(UUserWidget* HitNumber, FVector Location)
{
HitNumbers.Add(HitNumber, Location);
FTimerHandle HitNumberTimer;
FTimerDelegate HitNumberDelegate;
HitNumberDelegate.BindUFunction(this, FName("DestroyHitNumber"), HitNumber);
GetWorld()->GetTimerManager().SetTimer(
HitNumberTimer,
HitNumberDelegate,
HitNumberDestroyTime,
false);
}
void AEnemy::DestroyHitNumber(UUserWidget* HitNumber)
{
HitNumbers.Remove(HitNumber);
HitNumber->RemoveFromParent();
}
14-267 Update Hit Number Location
void AEnemy::UpdateHitNumbers()
{
for (auto& HitPair : HitNumbers)
{
UUserWidget* HitNumber{ HitPair.Key };
const FVector Location{ HitPair.Value };
FVector2D ScreenPosition;
UGameplayStatics::ProjectWorldToScreen(
GetWorld()->GetFirstPlayerController(),
Location,
ScreenPosition);
HitNumber->SetPositionInViewport(ScreenPosition);
}
}
댓글남기기