Spine深入学习 —— 动画

SkeletonAnimation

继承于SkeletonRenderer

播放动画

spTrackEntry* SkeletonAnimation::setAnimation (int trackIndex, const std::string& name, bool loop) {spAnimation* animation = spSkeletonData_findAnimation(_skeleton->data, name.c_str());if (!animation) {log("Spine: Animation not found: %s", name.c_str());return 0;}return spAnimationState_setAnimation(_state, trackIndex, animation, loop);
}

首先根据name去寻找动画,spAnimation对象主体是spTimeline,也就是Spine的时间线。

spTrackEntry* spAnimationState_setAnimation (spAnimationState* self, int trackIndex, spAnimation* animation, int/*bool*/loop) {spTrackEntry* entry;_spAnimationState* internal = SUB_CAST(_spAnimationState, self);int interrupt = 1;spTrackEntry* current = _spAnimationState_expandToIndex(self, trackIndex);if (current) {if (current->nextTrackLast == -1) {/* Don't mix from an entry that was never applied. */self->tracks[trackIndex] = current->mixingFrom;_spEventQueue_interrupt(internal->queue, current);_spEventQueue_end(internal->queue, current);_spAnimationState_disposeNext(self, current);current = current->mixingFrom;interrupt = 0;} else_spAnimationState_disposeNext(self, current);}entry = _spAnimationState_trackEntry(self, trackIndex, animation, loop, current);_spAnimationState_setCurrent(self, trackIndex, entry, interrupt);_spEventQueue_drain(internal->queue);return entry;
}

AnimationState

按时间顺序应用动画, 队列待播放的后续动画, 在动画间混合(淡入淡出), 以及在各动画之上相互堆叠应用多个动画(动画分层).

这是Spine提供的两种动画之一————动画状态。

在几乎所有情况下, 都建议使用动画状态API而非时间轴API. 与底层的时间轴API相比, 动画状态API会让诸如在某段时间内应用动画、排队动画、mix动画、以及同时应用多个动画等任务变得更加容易. 动画状态API内部使用的也是时间轴API, 因此可以将其看作是时间轴API的封装器.

AnimationState建立在时间轴API上,可处理多数播放需求,向后播放除外。如需反向播放,可直接使用时间轴API,或使用框选缩放来复制和反向播放动画。

通道(Track)

Track可分层应用动画,每个track存储了一个动画和播放参数。Track编号从零累加(track索引在内部是一个数组索引)。在将AnimationState应用到一个骨架后,track动画会从最低的track号开始依序应用。

播放

spAnimationState_setAnimation的本质就是播放track动画,将使用指定的动画取代该track中的当前动画和任何已排队的动画。如果在前一动画和当前动画之间定义了混合动画时间,则当前动画将在混合动画时间上混出,让动画过渡更流畅。

会返回一个spTrackEntry对象,可以多种方式自定义播放。

默认动画将继续应用直至另一动画播放或track清空。要在一个具体时间后停止动画,可设置spTrackEntry trackEnd时间。

排队播放
spTrackEntry* spAnimationState_addAnimation (spAnimationState* self, int trackIndex, spAnimation* animation, int/*bool*/loop,float delay) {spTrackEntry* entry;_spAnimationState* internal = SUB_CAST(_spAnimationState, self);spTrackEntry* last = _spAnimationState_expandToIndex(self, trackIndex);if (last) {while (last->next)last = last->next;}entry = _spAnimationState_trackEntry(self, trackIndex, animation, loop, last);if (!last) {_spAnimationState_setCurrent(self, trackIndex, entry, 1);_spEventQueue_drain(internal->queue);} else {last->next = entry;if (delay <= 0) {float duration = last->animationEnd - last->animationStart;if (duration != 0)delay += duration * (1 + (int)(last->trackTime / duration)) - spAnimationStateData_getMix(self->data, last->animation, animation);elsedelay = 0;}}entry->delay = delay;return entry;
}

spAnimationState_addAnimation安排该动画在此track当前动画或最后排队的动画后播放。如果此track空了,则等于调用setAnimation

返回 spTrackEntry对象。

空动画

如果清空了一个track,动画将停止应用。要混入或混出一个动画,可指定一个空动画,即没有时间轴的动画。空动画作为一个占位符,可设置混合时间。

spTrackEntry* spAnimationState_addEmptyAnimation(spAnimationState* self, int trackIndex, float mixDuration, float delay) {spTrackEntry* entry;if (delay <= 0) delay -= mixDuration;entry = spAnimationState_addAnimation(self, trackIndex, SP_EMPTY_ANIMATION, 0, delay);entry->mixDuration = mixDuration;entry->trackEnd = mixDuration;return entry;
}

要从装配姿势混入一个动画,可设置一个空动画,然后设置混合时间:

state.setEmptyAnimation(track, 0);
TrackEntry entry = state.addAnimation(track, "run", true, 0);
entry.mixDuration = 1.5;

要混出一个动画到装配姿势,可设置或排队一个指定了混合时间的空动画:

state.setAnimation(track, "run", true, 0);
state.addEmptyAnimation(track, 1.5, 0);

当动画到达TrackEntry trackEnd时间时,该动画设置的关键帧属性将设置装配姿势,并清空track。可根据需要使用setEmptyAnimation或addEmptyAnimation将骨架混回到装配姿势,而非让其即刻发生。

spTrackEntry

lua本身没有导出

设置或排队动画的方法返回一个TrackEntry,可用于进一步自定义播放。

struct spTrackEntry {spAnimation* animation;spTrackEntry* next;spTrackEntry* mixingFrom;spAnimationStateListener listener;int trackIndex;int /*boolean*/ loop;float eventThreshold, attachmentThreshold, drawOrderThreshold;float animationStart, animationEnd, animationLast, nextAnimationLast;float delay, trackTime, trackLast, nextTrackLast, trackEnd, timeScale;float alpha, mixTime, mixDuration, interruptAlpha, totalAlpha;spIntArray* timelineData;spTrackEntryArray* timelineDipMix;float* timelinesRotation;int timelinesRotationCount;void* rendererObject;void* userData;#ifdef __cplusplusspTrackEntry() :animation(0),next(0), mixingFrom(0),listener(0),trackIndex(0),loop(0),eventThreshold(0), attachmentThreshold(0), drawOrderThreshold(0),animationStart(0), animationEnd(0), animationLast(0), nextAnimationLast(0),delay(0), trackTime(0), trackLast(0), nextTrackLast(0), trackEnd(0), timeScale(0),alpha(0), mixTime(0), mixDuration(0), interruptAlpha(0), totalAlpha(0),timelineData(0),timelineDipMix(0),timelinesRotation(0),timelinesRotationCount(0) {}
#endif
};

在里面有一个spAnimationStateListener对象,表示监听事件。

void _spEventQueue_drain (_spEventQueue* self) {int i;if (self->drainDisabled) return;self->drainDisabled = 1;for (i = 0; i < self->objectsCount; i += 2) {spEventType type = (spEventType)self->objects[i].type;spTrackEntry* entry = self->objects[i+1].entry;spEvent* event;switch (type) {case SP_ANIMATION_START:case SP_ANIMATION_INTERRUPT:case SP_ANIMATION_COMPLETE:if (entry->listener) entry->listener(SUPER(self->state), type, entry, 0);if (self->state->super.listener) self->state->super.listener(SUPER(self->state), type, entry, 0);break;case SP_ANIMATION_END:if (entry->listener) entry->listener(SUPER(self->state), type, entry, 0);if (self->state->super.listener) self->state->super.listener(SUPER(self->state), type, entry, 0);/* Fall through. */case SP_ANIMATION_DISPOSE:if (entry->listener) entry->listener(SUPER(self->state), SP_ANIMATION_DISPOSE, entry, 0);if (self->state->super.listener) self->state->super.listener(SUPER(self->state), SP_ANIMATION_DISPOSE, entry, 0);_spAnimationState_disposeTrackEntry(entry);break;case SP_ANIMATION_EVENT:event = self->objects[i+2].event;if (entry->listener) entry->listener(SUPER(self->state), type, entry, event);if (self->state->super.listener) self->state->super.listener(SUPER(self->state), type, entry, event);i++;break;}}_spEventQueue_clear(self);self->drainDisabled = 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/179894.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker-compose替代者

Process Compose 是一个简单而灵活的调度程序和编排器&#xff0c;用于管理非容器化应用程序。 它深受docker-compose的启发&#xff0c;但不需要容器。不必处理 docker 文件、卷定义、网络和 docker 注册表 配置语法尝试遵循 docker-compose 规范&#xff0c;进行了一些小的…

【python】——组合数据类型(单选练习题)

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…

达索系统3DEXPERIENCE WORKS 2024 结构仿真功能增强

simulia结构仿真是什么&#xff1f; 不仅能对结构进行力学、热学、声学等多学科计算&#xff0c;辅助于设计方案的优化&#xff1b;还能采用数字化技术模拟产品性能&#xff0c;大幅节约试验和样机迭代成本。达索系统3DEXPERIENCE WORKS 2024 结构仿真为企业提供随需应变、精准…

centos7-docker安装与使用

文章目录 一、docker简介1.1docker应用场景1.2docker的优点1.2.1快速&#xff0c;一致地交付应用程序1.2.2响应式部署和扩展1.2.3在同一硬件上运行更多工作负载 1.2docker的架构 二、docker的安装2.1新系统的环境搭建2.1.1更换yum源 2.2安装docker与卸载2.2.1yum安装docker2.2.…

看懂YOLOv7混淆矩阵的含义,正确计算召回率、精确率、误检率、漏检率

文章目录 1、准确率、精确率、召回率、误报率、漏报率概念及公式1.1 准确率 Accuracy1.2 精确率 Precision1.3 召回率 Recall1.4 F1-Score1.5 误检率 false rate1.6 漏检率 miss rate 2、YOLOv7混淆矩阵分析 1、准确率、精确率、召回率、误报率、漏报率概念及公式 重点参考博文…

唯创知音WT588F02A-16S录音语音芯片在宠物喂食器中的应用:小芯片,大功能

在现代社会中&#xff0c;宠物已经成为人们生活中的一部分&#xff0c;而宠物喂食器作为宠物养护的重要工具&#xff0c;也越来越受到人们的关注。为了满足人们对宠物喂食器的多样化需求&#xff0c;唯创知音的WT588F02A-16S录音芯片在其中发挥着重要作用。 唯创知音的WT588F0…

.net7.0中把exe和dll分开打包

之前写过 C#把dll分别放在指定的文件夹_wpf core dll 放文件夹-CSDN博客 C#把dll打包到exe_c# 打包exe_故里2130的博客-CSDN博客 这都是老技术了&#xff0c;可以进行参考。 现在的.netcore系列有单独支持把exe和dll分开打包的功能了&#xff0c;当然也支持.net7.0和.net8.…

戴西软件成功收购美国知名 CAE 软件公司 ETA 的VPG汽车仿真软件

戴西&#xff08;上海&#xff09;软件有限公司&#xff08;以下简称“戴西”&#xff09;荣幸宣布成功收购全球著名CAE软件开发商ETA公司&#xff08;Engineering Technology Associates, Inc.&#xff09;旗下的汽车碰撞安全仿真软件VPG及相关技术成果&#xff08;Virtual Pr…

Python与设计模式--备忘录模式

23种计模式之 前言 &#xff08;5&#xff09;单例模式、工厂模式、简单工厂模式、抽象工厂模式、建造者模式、原型模式、(7)代理模式、装饰器模式、适配器模式、门面模式、组合模式、享元模式、桥梁模式、&#xff08;11&#xff09;策略模式、责任链模式、命令模式、中介者模…

Phpstudy v8.0/8.1小皮升级Apache至最新,同时升级openssl版本httpd-2.4.58 apache 2.4.58

1.apache官网下载最新版本的apache 2.4.58 2.phpstudy下apache停止运行&#xff0c;把原来的Apache文件夹备份一份 复制图中的文件替换apache目录下文件 3.phpstudy中开启apache

PyTorch:模型加载方法详解

PyTorch模型加载方法汇总 随着深度学习的快速发展&#xff0c;PyTorch作为一种流行的深度学习框架&#xff0c;其模型加载方法也备受关注。本文将介绍常用的PyTorch模型加载方法&#xff0c;并汇总不同方法的关键点&#xff0c;帮助读者更好地理解和应用。 一、PyTorch模型加载…

Ps:子路径的上下排列以及对齐与分布

不论是一个形状图层&#xff08;或图层的矢量蒙版&#xff09;上的多个形状还是同一路径层上多个路径&#xff0c;只要对应“路径”面板的一个路径层&#xff0c;可以将这些路径称为该路径层的“子路径”&#xff0c;也称为“组件”。 当一个路径层上有两个以上的子路径时&…

Python与设计模式--中介者模式

23种计模式之 前言 &#xff08;5&#xff09;单例模式、工厂模式、简单工厂模式、抽象工厂模式、建造者模式、原型模式、(7)代理模式、装饰器模式、适配器模式、门面模式、组合模式、享元模式、桥梁模式、&#xff08;11&#xff09;策略模式、责任链模式、命令模式、中介者模…

uniapp微信小程序中阻止事件冒泡

开发场景&#xff1a;列表中展示地块的数据信息&#xff0c;用户可以点击列表进入地块的详情界面&#xff0c;也可以点击列表中的星星按钮进行收藏 遇到的问题&#xff1a;每次点击星星的时候&#xff0c;都会触发父级的点击事件&#xff0c;从而进入到详情界面 原本的代码&am…

docker镜像管理命令

镜像管理命令 docker build : 命令用于使用 Dockerfile 创建镜像 docker build [OPTIONS] PATH | URL | - OPTIONS说明&#xff1a; --add-host :向hosts文件中添加自定义 host:ip 映射 --build-arg[] :设置镜像创建时的变量&#xff1b; --cache-from :指定镜像用作当前构建…

STK Components 二次开发- 卫星地面站

前期卫星地面站创建已经说过&#xff0c;本次说一下卫星和地面站可见性时卫星名称和轨迹线变色问题。 1.创建卫星 // Get the current TLE for the given satellite identifier. var tleList TwoLineElementSetHelper.GetTles(m_satelliteIdentifier, JulianDate.Now);// Us…

MFC容器中使用标准库容器,内存违规

问题描述 CArray中元素不管是直接或间接使用标准库容器&#xff0c;会引发内存违规。与CArray内部实现有关。测试代码如下&#xff1a; struct tagData {std::vector<int> m_Values; }; CArray<tagData, tagData> mIntVecArray; {tagData mData;mData.m_Values.p…

类和对象——(2)类

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 只虽然夜晚很长&#xff0c;但天…

SpringBoot配置跨域的机种方式 spring跨域的几种方式

SpringBoot配置跨域的机种方式 spring跨域的几种方式 1、注解方式2、实现 WebMvcConfigurer 接口3、使用 FilterRegistrationBean 过滤器 (推荐) 1、注解方式 使用 CrossOrigin注解标注在 Controller或者 Mapping RestController CrossOrigin RequestMapping("/ctro&quo…

Spark_Spark高阶特性

wscg filter导致断链 Codegen 向量化 simdjson Orc Parquet 支持批量读取 spark本身对parquet支持比较好&#xff0c;因为parquet