在遊戲中,許多音效須要在動畫恰當的時機出現,例如行走、奔跑,就須要剛好在足部落地瞬間播放。數組
而AnimNotify就能很是方便地處理此類問題。併發
AnimNotify,顧名思義就是動畫通知,能在特定的動畫片斷播放到特定進度時「發出消息」。socket
目前咱們的工程有前、後、左、右、左前、右前、左後、右後八向的跑動動畫。ide
先以向前跑爲例,用右鍵添加通知的方式,分別在右腳、左腳落地時添加了lfoot_touchground與rfoot_touchground的兩個自定義通知函數
固然直接添加playsound通知也是能夠的,能很方便地直接設置聲音,但爲了功能的可擴展性咱們仍是使用自定義通知。動畫
然而咱們如何才能獲取這些通知呢?this
if (mesh) { UAnimInstance* anim=mesh->GetAnimInstance(); if (anim) { TArray<const struct FAnimNotifyEvent*> AnimNotifies=anim->NotifyQueue.AnimNotifies; range(i,0,AnimNotifies.Num()) { FString NotifyName=AnimNotifies[i]->NotifyName.ToString(); /*GEngine->A/ddOnScreenDebugMessage (-1, 5.f, FColor::Red, FString::FromInt(i)+" "+ NotifyName);*/ if (NotifyName=="lfoot_touchground") { audio_lfoot->SetSound(sb_walks[0]); audio_lfoot->Play(); } else if (NotifyName == "rfoot_touchground") { audio_rfoot->SetSound(sb_walks[1]); audio_rfoot->Play(); } else { } } } }
沒錯,就是這麼簡單anim->NotifyQueue即爲動畫通知隊列,AnimNotifies就能獲取當前全部通知事件,上述代碼去掉註釋便可打印當前幀全部動畫通知名稱。spa
爲了實現播放音效,咱們還須要綁定在左右腳的AudioComponent,若是當前通知隊列中有對應的通知,就先SetSound設置將要播放的聲音資源後再Play。code
我把全部須要綁定在Chracter的Mesh上的AudioComponent「打包裝入「了一個叫AudioController的類,在Character的構造函數中進行了AudioController的構造,並將AudioController中的各音效組件綁定到對應的socket上。component
AudioController.h文件
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "Components/ActorComponent.h" #include "Components/AudioComponent.h" #include "Components/SkeletalMeshComponent.h" #include "AudioController.generated.h" UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) ) class MYSOUNDANDEFFECTS_API UAudioController : public UActorComponent { GENERATED_BODY() public: // Sets default values for this component's properties UAudioController(); //UAudioController(USkeletalMeshComponent* mesh_); protected: // Called when the game starts virtual void BeginPlay() override; public: // Called every frame virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; UPROPERTY(Category = Audio, VisibleDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) UAudioComponent* audio_lfoot = NULL; UPROPERTY(Category = Audio, EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) FString bonename_lfoot = "Bip01-L-Foot"; UPROPERTY(Category = Audio, VisibleDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) UAudioComponent* audio_rfoot = NULL; UPROPERTY(Category = Audio, EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) FString bonename_rfoot = "Bip01-R-Foot"; USkeletalMeshComponent* mesh = NULL; void my_init(USkeletalMeshComponent* mesh_); UPROPERTY(Category = Audio, EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) TArray<class USoundBase*> sb_walks; };
AudioController.cpp文件
// Fill out your copyright notice in the Description page of Project Settings. #include "MySoundAndEffects.h" #include "Animation/AnimInstance.h" #include "AudioController.h" // Sets default values for this component's properties UAudioController::UAudioController() { // Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features // off to improve performance if you don't need them. PrimaryComponentTick.bCanEverTick = true; // ... audio_lfoot = CreateDefaultSubobject<UAudioComponent>("audio_lfoot"); audio_rfoot = CreateDefaultSubobject<UAudioComponent>("audio_rfoot"); } //UAudioController::UAudioController(USkeletalMeshComponent* mesh_) //{ // // Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features // // off to improve performance if you don't need them. // PrimaryComponentTick.bCanEverTick = true; // // // ... // // // //} void UAudioController::my_init(USkeletalMeshComponent* mesh_) { this->mesh = mesh_; //UAudioController(); audio_lfoot->SetupAttachment(mesh_, FName(*bonename_lfoot)); audio_rfoot->SetupAttachment(mesh_, FName(*bonename_rfoot)); } // Called when the game starts void UAudioController::BeginPlay() { Super::BeginPlay(); // ... } // Called every frame void UAudioController::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); // ... if (mesh) { UAnimInstance* anim=mesh->GetAnimInstance(); if (anim) { TArray<const struct FAnimNotifyEvent*> AnimNotifies=anim->NotifyQueue.AnimNotifies; range(i,0,AnimNotifies.Num()) { FString NotifyName=AnimNotifies[i]->NotifyName.ToString(); /*GEngine->A/ddOnScreenDebugMessage (-1, 5.f, FColor::Red, FString::FromInt(i)+" "+ NotifyName);*/ if (NotifyName=="lfoot_touchground") { audio_lfoot->SetSound(sb_walks[0]); audio_lfoot->Play(); } else if (NotifyName == "rfoot_touchground") { audio_rfoot->SetSound(sb_walks[1]); audio_rfoot->Play(); } else { } } } } else { throw std::exception("mesh not exist!!"); } }
還有character類中audiocontroller的定義和建立:
AAimPraticeHuman::AAimPraticeHuman() { #ifdef AudioController_h audiocontroller = CreateDefaultSubobject<UAudioController>("audiocontroller"); audiocontroller->my_init(GetMesh()); #endif }
UPROPERTY(Category = Audio, VisibleDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
class UAudioController* audiocontroller = NULL;
最後就是音效導入,看似簡單其實有不少細節。
建議直接拖入wav格式文件,若是導入失敗應該是wav文件具體參數的問題。
(我用Audition把一長串的跑步音效分割出了兩聲腳碰地的聲音,直接導入ue4報錯,然而先用格式工廠轉一下就ok了)
固然如今的音效還不能直接用於遊戲腳步,還須要先設置併發和立體效果。
Concurrency項勾選override便可,使用」先遠後舊「的併發中止策略問題也不大。
Attenuation項我新建了一個叫SceneSoundAttenuation藍圖,設置以下:
這些選項看字面都比較好理解,3D Stereo Spread的意思其實就是左右耳間距。
最後別忘了設置character藍圖的sb_walks數組的值,以及左右腳的socketname
大功告成啦!
具體效果。。。反正大家也聽不到。。。
------------------------------------------------
下期預告:美妙的IK(反向動力學)