zoukankan      html  css  js  c++  java
  • ue4音效、动画结合实例

    在游戏中,许多音效需要在动画恰当的时机出现,例如行走、奔跑,就需要恰好在足部落地瞬间播放。

    而AnimNotify就能非常方便地处理此类问题。

    AnimNotify,顾名思义就是动画通知,能在特定的动画片段播放到特定进度时“发出消息”。

    目前我们的工程有前、后、左、右、左前、右前、左后、右后八向的跑动动画。

    先以向前跑为例,用右键添加通知的方式,分别在右脚、左脚落地时添加了lfoot_touchground与rfoot_touchground的两个自定义通知

    当然直接添加playsound通知也是可以的,能很方便地直接设置声音,但为了功能的可扩展性我们还是使用自定义通知。

    然而我们如何才能获取这些通知呢?

    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就能获取当前所有通知事件,上述代码去掉注释即可打印当前帧所有动画通知名称。

    为了实现播放音效,我们还需要绑定在左右脚的AudioComponent,如果当前通知队列中有对应的通知,就先SetSound设置将要播放的声音资源后再Play。

    我把所有需要绑定在Chracter的Mesh上的AudioComponent“打包装入“了一个叫AudioController的类,在Character的构造函数中进行了AudioController的构造,并将AudioController中的各音效组件绑定到对应的socket上。

    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(反向动力学)

  • 相关阅读:
    带妹入坑,她该怎样提高自己的编程能力?
    性能测试--cpu使用率过高怎么办
    loadrunner Controller 删除available scripts中无用脚本
    loadrunner 立即执行+定时执行设置
    loadrunner11 :脚本日志打印设置及举例说明
    loadrunner录制chrome脚本:页面无响应
    Error -27492: "HttpSendRequest" failed, Windows error code=12152 (invalid server response) and retry。。。
    loadrunner11错误:Error -27776: Server "wsg.cmszmail.ad" shut connection during attempt to negotiate SSL session [MsgId: MERR-27776]解决办法
    loadrunner11 错误:Error -26377: No match found for the requested parameter XXXX. web_custom_request(XXX) highest severity level was "ERROR",....... [MsgId: MMSG-26387]
    loadrunner11 执行bat批处理文件时获取bat文件所在路径 正确方式与采坑说明
  • 原文地址:https://www.cnblogs.com/wzj998/p/7512799.html
Copyright © 2011-2022 走看看