当前位置: 首页 > news >正文

[UE4]Animation Montage C++相关注意事项

[UE4]Animation Montage C++相关注意事项

https://zhuanlan.zhihu.com/p/47767283

 

C++如何播放Montage动画

假设是在Character内执行,其中MontagePtr为Montage指针:

float DeathAnimDuration = PlayAnimMontage(MontagePtr) / (GetMesh() && GetMesh()->GlobalAnimRateScale > 0 ? GetMesh()->GlobalAnimRateScale : 1);

如果只是播放Animation Sequence,可以使用 PlayAnimation()

if (USkeletalMeshComponent *Mesh = GetMesh())
{
    Mesh->PlayAnimation(AnimSequence, false);
}
注意:PlayAnimation可以直接来播放AnimSequence,但是不能混合动作。比如当播放完攻击动作后,无法自动回到空闲状态,但是通过Montage的Slot可以完成自动切换动作。

其他参考:
How can I play animations strictly from C++?
https://answers.unrealengine.com/questions/292345/how-can-i-play-animations-strictly-from-c.html

C++动态播放Montage(通过AnimSequence创建)

keywords:UE4, C++, AnimSequence, AnimMontage, Slot, 动态创建, 播放动画

首先要在动画蓝图中添加Slot节点,默认的Slot名字为DefaultSlot。这个名字会在C++代码中使用

假设已经获取了要播放的AnimSequence对象指针:AnimSeq

float AnimLength = 0.f;
if (USkeletalMeshComponent *Mesh = MyActor->FindComponentByClass<USkeletalMeshComponent>())
{
    if (UAnimInstance *AnimInst = Mesh->GetAnimInstance())
    {
        if (UAnimMontage* Mtg = AnimInst->PlaySlotAnimationAsDynamicMontage(AnimSeq, TEXT("DefaultSlot"), 0.25f, 0.25f, 1.f, 1))
        {
            AnimLength = Mtg->GetPlayLength();
        }
    }
}
使用 UAnimInstance::PlaySlotAnimationAsDynamicMontage() 播放Montage时,参数 Animation Sequence 中 Notify 仍然对动态生成的 Montage 有效,即:Montage 也会触发同样的Notify。

 

使用PlaySlotAnimationAsDynamicMontage()播放Montage时,如果不是循环播放的Montage,播放完毕后一定要执行 UAnimInstance::Montage_Stop() 停掉当前Montage,否则会干扰蓝图动画的逻辑,导致切换其他Montage时无效。

播放Montage动画时让动作停留在最后一帧

keywords:UE4、Montage、C++、播放速度、播放速率、加速播放、减速播放

三种方式
方式1: 在想要冻结的那一帧内,将SkeletonComponent的GlobalAnimRateScale属性设置为0。
比如想要角色的骨骼定格在第三帧,那么就在动画播放到第三帧的时候将该属性设置为0。

ACharacter::GetMesh()->GlobalAnimRateScale = 0.f;

方式2:

ACharacter::GetMesh()->bNoSkeletonUpdate = true;

方式3:

ACharacter::GetMesh()->bPauseAnims = true;
注意:正常播放完AnimSequence时,只要不是设置为循环播放,播放完以后会自动停留在最后一帧。只有播放Montage时才需要设置以上属性。

C++播放Montage的指定Section

方式1:
通过第三个参数 StartSectionName 指定 Section

float ACharacter::PlayAnimMontage(class UAnimMontage* AnimMontage, float InPlayRate = 1.f, FName StartSectionName = NAME_None);

方式2:
使用 UAnimInstance::Montage_JumpToSection()

if (USkeletalMeshComponent *Mesh = Character->GetMesh())
{
    if (UAnimInstance *AnimInst = Mesh->GetAnimInstance())
    {
        Char->PlayAnimMontage(MontagePtr);
        AnimInst->Montage_JumpToSection(FName("step_03"), MontagePtr);
    }
}
执行 Montage_JumpToSection 时请确保角色动画的正处于Section所属Montage的播放状态,否则 JumpToSection 无效。

Montage Section切换无效的问题(2018-02-11)

keywords: UE4 Montage Section not working

问题现象:
SetNextSection在编辑器中运行正常,但是在打包版本中无效。

解决办法:
将SetNextSection替换为JumpToSection。

参考自:Montage unwanted section switching
https://answers.unrealengine.com/questions/172537/montage-unwanted-section-switching.html

如果Section的时间很短,需要将 Blend In 和 Blend Out 设置为 改小或者设置为 0(默认为0.25),否则 JumpToSection 无效果。

Montage 循环播放

如果用动画蓝图控制动画切换,直接用动画状态机去指定 AnimSequence 即可,不需要其他设置,因为动画蓝图会自动根据状态机去循环播放指定的 AnimSequence 。
如果用C++播放Montage,则需要注意以下细节:

  1. 如果是使用现成的Montage资源,需要将Montage设置为循环播放,方式如下:
    打开Montage编辑窗口后,先鼠标单击位置1,然后鼠标单击位置2(都是鼠标左键单击)

然后Preview Section 进度条中就多了一个 X ,此时表示Montage为循环播放了

之后再执行 ACharacter::PlayAnimMontage() 就可以自动循环播放指定Montage了。PlayAnimMontage() 只需执行一次即可。

2. 如果动态创建Montage并播放,则需要将LoopCount设置为足够大,比如 9999。这样当前Montage就会循环播放:

AnimInstance->PlaySlotAnimationAsDynamicMontage(AnimSeq, TEXT("DefaultSlot"), 0.25f, 0.25f, 1.f, 9999));
这种方式是否可行:不设置Montage循环播放,而是在Tick中不停检测上一次Montage的累计播放时长,当播完时马上执行下一次播放。答案是不可行!!实际效果是:两次的Montage播放之间会有短暂时间切换到Idle状态动画。

 

停止Montage播放

如果要停止当前正在播放的Montage,则执行StopAnimMontage()

void ACharacter::StopAnimMontage(class UAnimMontage* AnimMontage);
如果希望停止播放Montage时有动画融合效果,记得将Montage的Blend Out Time设置为大于0,比如默认值 0.25 。

Montage 切换时没有融合的问题

原因:
Montage 的参数Blend In被设置为了0。

解决办法:
将Montage 的参数Blend In(Blend Option -> Blend In -> Blend Time)改成大于0,比如默认值0.25。

 

=========================

baidu     PlaySlotAnimationAsDynamicMontage

 

 

 

 

 

相关文章:

  • UE4 Montage 资源制作
  • UE4.12-用Montage选择性播放动画片段
  • AndroidStudio3.6的卸载安装,Gradle持续下载/Gradle Build失败等问题
  • unity shader 变种(多重编译 multi_compile)
  • Unity3d爬坑篇(2)之Assetbundle、Shader和Keyword
  • Unity AssetBundle Shader
  • Shader变体使用策略
  • AndroidStudio Gradle Plugin 下载失败
  • [原创]安卓U3D逆向从Assembly-CSharp到il2cpp
  • Unity Android il2cpp
  • Unity 找到原因了,如果你在Update里Instantiate一个prefab,上面的脚本会在这个update后执行start,然后执行lateupdate,这帧的update会被跳过
  • Unity -- Error
  • Unity iOS 删除 UIWebView
  • Jenkins 自己使用
  • Jenkins Pipeline语法(中)
  • Effective Java 笔记(一)
  • electron原来这么简单----打包你的react、VUE桌面应用程序
  • es6--symbol
  • git 常用命令
  • javascript 哈希表
  • JS基础篇--通过JS生成由字母与数字组合的随机字符串
  • Promise面试题,控制异步流程
  • PV统计优化设计
  • SQLServer之创建数据库快照
  • vue+element后台管理系统,从后端获取路由表,并正常渲染
  • 回顾 Swift 多平台移植进度 #2
  • 前端每日实战:61# 视频演示如何用纯 CSS 创作一只咖啡壶
  • 世界上最简单的无等待算法(getAndIncrement)
  • 它承受着该等级不该有的简单, leetcode 564 寻找最近的回文数
  • ​LeetCode解法汇总2696. 删除子串后的字符串最小长度
  • ​LeetCode解法汇总2808. 使循环数组所有元素相等的最少秒数
  • ​业务双活的数据切换思路设计(下)
  • # Swust 12th acm 邀请赛# [ E ] 01 String [题解]
  • #13 yum、编译安装与sed命令的使用
  • #LLM入门|Prompt#3.3_存储_Memory
  • $.extend({},旧的,新的);合并对象,后面的覆盖前面的
  • (1)SpringCloud 整合Python
  • (11)工业界推荐系统-小红书推荐场景及内部实践【粗排三塔模型】
  • (2)nginx 安装、启停
  • (22)C#传智:复习,多态虚方法抽象类接口,静态类,String与StringBuilder,集合泛型List与Dictionary,文件类,结构与类的区别
  • (9)目标检测_SSD的原理
  • (AngularJS)Angular 控制器之间通信初探
  • (Forward) Music Player: From UI Proposal to Code
  • (Redis使用系列) Springboot 使用redis实现接口幂等性拦截 十一
  • (超简单)使用vuepress搭建自己的博客并部署到github pages上
  • (二)基于wpr_simulation 的Ros机器人运动控制,gazebo仿真
  • (附源码)spring boot智能服药提醒app 毕业设计 102151
  • (经验分享)作为一名普通本科计算机专业学生,我大学四年到底走了多少弯路
  • (十八)devops持续集成开发——使用docker安装部署jenkins流水线服务
  • (五)Python 垃圾回收机制
  • (一)Mocha源码阅读: 项目结构及命令行启动
  • (转) Android中ViewStub组件使用
  • (转)Android中使用ormlite实现持久化(一)--HelloOrmLite
  • .Family_物联网
  • .Net Core与存储过程(一)