源码分析一

body {
font-family: Helvetica, arial, sans-serif;
font-size: 14px;
line-height: 1.6;
padding-top: 10px;
padding-bottom: 10px;
background-color: white;
padding: 30px; }

body > *:first-child {

margin-top: 0 !important; }

body > *:last-child {

margin-bottom: 0 !important; }

a {

color: #4183C4; }

a.absent {

color: #cc0000; }

a.anchor {

display: block;

padding-left: 30px;

margin-left: -30px;

cursor: pointer;

position: absolute;

top: 0;

left: 0;

bottom: 0; }

h1, h2, h3, h4, h5, h6 {

margin: 20px 0 10px;

padding: 0;

font-weight: bold;

-webkit-font-smoothing: antialiased;

cursor: text;

position: relative; }

h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor {

background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA09pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoMTMuMCAyMDEyMDMwNS5tLjQxNSAyMDEyLzAzLzA1OjIxOjAwOjAwKSAgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OUM2NjlDQjI4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OUM2NjlDQjM4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5QzY2OUNCMDg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5QzY2OUNCMTg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PsQhXeAAAABfSURBVHjaYvz//z8DJYCRUgMYQAbAMBQIAvEqkBQWXI6sHqwHiwG70TTBxGaiWwjCTGgOUgJiF1J8wMRAIUA34B4Q76HUBelAfJYSA0CuMIEaRP8wGIkGMA54bgQIMACAmkXJi0hKJQAAAABJRU5ErkJggg==) no-repeat 10px center;

text-decoration: none; }

h1 tt, h1 code {

font-size: inherit; }

h2 tt, h2 code {

font-size: inherit; }

h3 tt, h3 code {

font-size: inherit; }

h4 tt, h4 code {

font-size: inherit; }

h5 tt, h5 code {

font-size: inherit; }

h6 tt, h6 code {

font-size: inherit; }

h1 {

font-size: 28px;

color: black; }

h2 {

font-size: 24px;

border-bottom: 1px solid #cccccc;

color: black; }

h3 {

font-size: 18px; }

h4 {

font-size: 16px; }

h5 {

font-size: 14px; }

h6 {

color: #777777;

font-size: 14px; }

p, blockquote, ul, ol, dl, li, table, pre {

margin: 15px 0; }

hr {

background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAECAYAAACtBE5DAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OENDRjNBN0E2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OENDRjNBN0I2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4Q0NGM0E3ODY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4Q0NGM0E3OTY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PqqezsUAAAAfSURBVHjaYmRABcYwBiM2QSA4y4hNEKYDQxAEAAIMAHNGAzhkPOlYAAAAAElFTkSuQmCC) repeat-x 0 0;

border: 0 none;

color: #cccccc;

height: 4px;

padding: 0;

}

body > h2:first-child {

margin-top: 0;

padding-top: 0; }

body > h1:first-child {

margin-top: 0;

padding-top: 0; }

body > h1:first-child + h2 {

margin-top: 0;

padding-top: 0; }

body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child {

margin-top: 0;

padding-top: 0; }

a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {

margin-top: 0;

padding-top: 0; }

h1 p, h2 p, h3 p, h4 p, h5 p, h6 p {

margin-top: 0; }

li p.first {

display: inline-block; }

li {

margin: 0; }

ul, ol {

padding-left: 30px; }

ul :first-child, ol :first-child {

margin-top: 0; }

dl {

padding: 0; }

dl dt {

font-size: 14px;

font-weight: bold;

font-style: italic;

padding: 0;

margin: 15px 0 5px; }

dl dt:first-child {

padding: 0; }

dl dt > :first-child {

margin-top: 0; }

dl dt > :last-child {

margin-bottom: 0; }

dl dd {

margin: 0 0 15px;

padding: 0 15px; }

dl dd > :first-child {

margin-top: 0; }

dl dd > :last-child {

margin-bottom: 0; }

blockquote {

border-left: 4px solid #dddddd;

padding: 0 15px;

color: #777777; }

blockquote > :first-child {

margin-top: 0; }

blockquote > :last-child {

margin-bottom: 0; }

table {

padding: 0;border-collapse: collapse; }

table tr {

border-top: 1px solid #cccccc;

background-color: white;

margin: 0;

padding: 0; }

table tr:nth-child(2n) {

background-color: #f8f8f8; }

table tr th {

font-weight: bold;

border: 1px solid #cccccc;

margin: 0;

padding: 6px 13px; }

table tr td {

border: 1px solid #cccccc;

margin: 0;

padding: 6px 13px; }

table tr th :first-child, table tr td :first-child {

margin-top: 0; }

table tr th :last-child, table tr td :last-child {

margin-bottom: 0; }

img {

max-width: 100%; }

span.frame {

display: block;

overflow: hidden; }

span.frame > span {

border: 1px solid #dddddd;

display: block;

float: left;

overflow: hidden;

margin: 13px 0 0;

padding: 7px;

width: auto; }

span.frame span img {

display: block;

float: left; }

span.frame span span {

clear: both;

color: #333333;

display: block;

padding: 5px 0 0; }

span.align-center {

display: block;

overflow: hidden;

clear: both; }

span.align-center > span {

display: block;

overflow: hidden;

margin: 13px auto 0;

text-align: center; }

span.align-center span img {

margin: 0 auto;

text-align: center; }

span.align-right {

display: block;

overflow: hidden;

clear: both; }

span.align-right > span {

display: block;

overflow: hidden;

margin: 13px 0 0;

text-align: right; }

span.align-right span img {

margin: 0;

text-align: right; }

span.float-left {

display: block;

margin-right: 13px;

overflow: hidden;

float: left; }

span.float-left span {

margin: 13px 0 0; }

span.float-right {

display: block;

margin-left: 13px;

overflow: hidden;

float: right; }

span.float-right > span {

display: block;

overflow: hidden;

margin: 13px auto 0;

text-align: right; }

code, tt {

margin: 0 2px;

padding: 0 5px;

white-space: nowrap;

border: 1px solid #eaeaea;

background-color: #f8f8f8;

border-radius: 3px; }

pre code {

margin: 0;

padding: 0;

white-space: pre;

border: none;

background: transparent; }

.highlight pre {

background-color: #f8f8f8;

border: 1px solid #cccccc;

font-size: 13px;

line-height: 19px;

overflow: auto;

padding: 6px 10px;

border-radius: 3px; }

pre {

background-color: #f8f8f8;

border: 1px solid #cccccc;

font-size: 13px;

line-height: 19px;

overflow: auto;

padding: 6px 10px;

border-radius: 3px; }

pre code, pre tt {

background-color: transparent;

border: none; }

sup {

font-size: 0.83em;

vertical-align: super;

line-height: 0;

}

  • {

    -webkit-print-color-adjust: exact;

    }

    @media screen and (min-width: 914px) {

    body {

    width: 854px;

    margin:0 auto;

    }

    }

    @media print {

    table, pre {

    page-break-inside: avoid;

    }

    pre {

    word-wrap: break-word;

    }

    }

/**
* prism.js Coy theme for JavaScript, CoffeeScript, CSS and HTML
* Based on https://github.com/tshedor/workshop-wp-theme (Example: http://workshop.kansan.com/category/sessions/basics or http://workshop.timshedor.com/category/sessions/basics);
* @author Tim Shedor
*/

code[class*="language-"],
pre[class*="language-"] {
color: black;
font-family: Consolas, Monaco, 'Andale Mono', monospace;
direction: ltr;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
line-height: 1.5;

-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;

-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}

/* Code blocks */
pre[class*="language-"] {
position: relative;
margin: .5em 0;
-webkit-box-shadow: -1px 0px 0px 0px #358ccb, 0px 0px 0px 1px #dfdfdf;
-moz-box-shadow: -1px 0px 0px 0px #358ccb, 0px 0px 0px 1px #dfdfdf;
box-shadow: -1px 0px 0px 0px #358ccb, 0px 0px 0px 1px #dfdfdf;
border-left: 10px solid #358ccb;
background-color: #fdfdfd;
background-image: -webkit-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
background-image: -moz-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
background-image: -ms-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
background-image: -o-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
background-image: linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%);
background-size: 3em 3em;
background-origin: content-box;
overflow: visible;
max-height: 30em;
}

code[class*="language"] {
max-height: inherit;
height: 100%;
padding: 0 1em;
display: block;
overflow: auto;
}

/* Margin bottom to accomodate shadow */
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background-color: #fdfdfd;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
margin-bottom: 1em;
}

/* Inline code */
:not(pre) > code[class*="language-"] {
position: relative;
padding: .2em;
-webkit-border-radius: 0.3em;
-moz-border-radius: 0.3em;
-ms-border-radius: 0.3em;
-o-border-radius: 0.3em;
border-radius: 0.3em;
color: #c92c2c;
border: 1px solid rgba(0, 0, 0, 0.1);
}

pre[class*="language-"]:before,
pre[class*="language-"]:after {
content: '';
z-index: -2;
display: block;
position: absolute;
bottom: 0.75em;
left: 0.18em;
width: 40%;
height: 20%;
-webkit-box-shadow: 0px 13px 8px #979797;
-moz-box-shadow: 0px 13px 8px #979797;
box-shadow: 0px 13px 8px #979797;
-webkit-transform: rotate(-2deg);
-moz-transform: rotate(-2deg);
-ms-transform: rotate(-2deg);
-o-transform: rotate(-2deg);
transform: rotate(-2deg);
}

:not(pre) > code[class*="language-"]:after,
pre[class*="language-"]:after {
right: 0.75em;
left: auto;
-webkit-transform: rotate(2deg);
-moz-transform: rotate(2deg);
-ms-transform: rotate(2deg);
-o-transform: rotate(2deg);
transform: rotate(2deg);
}

.token.comment,
.token.block-comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #7D8B99;
}

.token.punctuation {
color: #5F6364;
}

.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.function-name,
.token.constant,
.token.symbol,
.token.deleted {
color: #c92c2c;
}

.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.function,
.token.builtin,
.token.inserted {
color: #2f9c0a;
}

.token.operator,
.token.entity,
.token.url,
.token.variable {
color: #a67f59;
background: rgba(255, 255, 255, 0.5);
}

.token.atrule,
.token.attr-value,
.token.keyword,
.token.class-name {
color: #1990b8;
}

.token.regex,
.token.important {
color: #e90;
}

.language-css .token.string,
.style .token.string {
color: #a67f59;
background: rgba(255, 255, 255, 0.5);
}

.token.important {
font-weight: normal;
}

.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}

.token.entity {
cursor: help;
}

.namespace {
opacity: .7;
}

@media screen and (max-width: 767px) {
pre[class*="language-"]:before,
pre[class*="language-"]:after {
bottom: 14px;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}

}

/* Plugin styles */
.token.tab:not(:empty):before,
.token.cr:before,
.token.lf:before {
color: #e0d7d1;
}

/* Plugin styles: Line Numbers */
pre[class*="language-"].line-numbers {
padding-left: 0;
}

pre[class*="language-"].line-numbers code {
padding-left: 3.8em;
}

pre[class*="language-"].line-numbers .line-numbers-rows {
left: 0;
}

/* Plugin styles: Line Highlight */
pre[class*="language-"][data-line] {
padding-top: 0;
padding-bottom: 0;
padding-left: 0;
}
pre[data-line] code {
position: relative;
padding-left: 4em;
}
pre .line-highlight {
margin-top: 0;
}

pre.line-numbers {
position: relative;
padding-left: 3.8em;
counter-reset: linenumber;
}

pre.line-numbers > code {
position: relative;
}

.line-numbers .line-numbers-rows {
position: absolute;
pointer-events: none;
top: 0;
font-size: 100%;
left: -3.8em;
width: 3em; /* works for line-numbers below 1000 lines */
letter-spacing: -1px;
border-right: 1px solid #999;

-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;

}

.line-numbers-rows > span {
pointer-events: none;
display: block;
counter-increment: linenumber;
}

.line-numbers-rows > span:before {
content: counter(linenumber);
color: #999;
display: block;
padding-right: 0.8em;
text-align: right;
}

cocos2dx骨骼动画Armature源码分析(一)

cocos2dx中的骨骼动画使用起来比较方便,从编辑器(cocostudio或flash插件dragonBones)得到xml或json数据,调用类似下面的代码就可以展示出动画

    ArmatureDataManager::getInstance()->addArmatureFileInfoAsync(
"armature/Dragon.png", "armature/Dragon.plist", "armature/Dragon.xml",
this, schedule_selector(TestAsynchronousLoading::dataLoaded));
Armature *armature = nullptr;
armature = Armature::create("Dragon");
armature->getAnimation()->playWithIndex(1);
addChild(armature);

那么调用内部是怎么实现的呢?Armature::create和armature->getAnimation()->playWithIndex都实现了些什么呢?这几篇文章将从源码上分析Armature。

本文是Armature分析的第一篇,将从整体上对cocos2dx里的骨骼动画进行分析。涉及到内容如下:

  • 什么是骨骼动画
  • 编辑器导出数据格式概览
  • 源码概述

什么是骨骼动画

游戏中的动画大体可以分成下面三种:

  1. 帧动画
  2. 补间动画(Tween)
  3. 骨骼蒙皮动画

帧动画

这个是最基本的动画,也是下面两个动画的基础,一帧展示一张图,cocos2dx Action中Animate就是帧动画。优点是实现简单,缺点是浪费资源(一帧一张图,可对比下面两种动画)。

补间动画

flash中补间动画用的比较多,不需要一帧一张图,只需起始状态和结束状态,中间的状态可以进行根据差值与经过时间计算出来。优点是节省资源,美术人员比较熟悉。

骨骼蒙皮动画

骨骼动画可以认为是补间动画的一种扩展,让动画的各个部分之间产生关联结构(骨骼),之后把图绑定到骨骼上。缺点是程序实现较复杂,其优点较补间动画有下面两点(其他优点暂时没有发现):

1.导出配置数据少并且美术制作简单

假设有一个下面这样结构的骨骼

armRight

head

legLeft

legRight

假设想在一帧中把动画整体向右移动,采用补间动画需要把body、armLeft、legRight等等全部移动,创建新的帧,而骨骼动画只需移动body的位置,其子节点会跟随父节点移动。对应导出的配置中,补间动画要处理body、armLeft等所有子节点导出的数据,而骨骼动画只有body一个节点数据的改变,导出的数据会小很多。

2.关节裂纹修复

下面的图是偷的《游戏引擎架构》449页,意思是如果美术作图时候不注意,关节链接处可能会有裂缝。采用骨骼动画可以解决这个问题,骨骼动画中的蒙皮可以按权重绑定到多个关节(骨骼中),并且可以按权重进行拉伸,cocostudio骨骼动画编辑器不熟,不知可不可多绑定,flash的dragonBones插件是不行的。spine对这种多绑定有不错的支持。

cocos2dx骨骼动画Armature源码分析(一)-LMLPHP

编辑器导出数据格式概览

cocostudio导出的json结构和dragonbones导出的xml结构相似,都是骨骼层,动画层,图片层三层结构,已dragonbones官方的demo为例(有删减):

<skeleton name="DragonBones_Tutorial_MultiBehavior" frameRate="24" version="2.2">
<armatures>
<armature name="Dragon">
<b name="tail" parent="body" x="45.9" y="-70.8" kX="30" kY="30" cX="1" cY="1" pX="11.5" pY="176.35" z="10">
<d name="parts-tail" pX="0" pY="-63.8"/>
</b>
</armature>
</armatures>
<animations>
<animation name="Dragon">
<mov name="stand" dr="7" to="6" drTW="100" lp="1" twE="0">
</mov>
<mov name="walk" dr="8" to="5" drTW="200" lp="1" twE="0">
</mov>
<mov name="jump" dr="5" to="3" drTW="5" lp="1" twE="NaN">
</mov>
<mov name="fall" dr="5" to="6" drTW="5" lp="1" twE="NaN">
</mov>
</animation>
</animations>
<TextureAtlas name="DragonBones_Tutorial_MultiBehavior" width="512" height="512">
</TextureAtlas>
</skeleton>

<armatures></armatures>是骨骼部分,对应flash中1区域,一个layer就是一个bone。

<animations></animations>是动画部分,对应flash中2区域,用帧标签区分哪个动画,比如stand、walk、jump等。

<TextureAtlas></TextureAtlas>是骨骼部分,对应flash中3区域,是皮肤,也就是图信息。

有了这些信息,就可以在程序中还原flash中的动画效果,具体dr、drTW、x、kX、kY等等是什么意思之后的文章里会说。

cocos2dx骨骼动画Armature源码分析(一)-LMLPHP

源码概述

代码大体可以分成xml或json数据的解析 和 用解析出的数据产生动画两部分。

数据解析的相关代码的UML

cocos2dx骨骼动画Armature源码分析(一)-LMLPHP
大致介绍下每个类的作用:

  • DataReaderHelper:解析armatures、animations、TextureAtlas的数据生成程序能直接使用的数据结构ArmatureData、AnimationData、TextureData。
  • ArmatureDataManager:管理DataReaderHelper及其解析出来的数据。
  • ArmatureData:对应xml中的<armature></armature>。
  • AnimationData:对应xml中的<animation></animation>。
  • TextureData:对应xml中的<SubTexture></SubTexture>。
  • BoneData:对应xml中的<b></b>。
  • DisplayData:对应xml中的<d></d>。
  • MovementData:对应xml中的<mov></mov>。
  • MovementBoneData:对应xml中的<mov><b></b></mov>。
  • FrameData:对应xml中的<mov><b><f></f></b></mov>。

产生动画相关代码的UML

cocos2dx骨骼动画Armature源码分析(一)-LMLPHP
大致介绍下每个类的作用:

  • Armature:里面包含了骨骼信息及动画信息,有个这个就可以播放动画。
  • Tween:骨骼动画的补间,一个骨骼一个Tween。对应上面的flash面板就是stand动画的tail层的第一到第七帧。
  • ArmatureAnimation:所有Tween的集合,够成一个动画。
  • Bone:带有Tween的骨骼信息,从这里面可以得到某个时间点的骨骼状态。
  • DisplayFactory:创建skin等显示对象。
  • DisplayManager:每个Bone中有一个,管理骨骼上的显示对象。
  • Skin:图的显示对象。

代码的详细介绍之后的文章中介绍。下一篇文章将介绍编辑器导出的xml(json)中各个字段的含义及数据解析源码的分析。吐槽下自己,文章里的代码好丑,用macDown写的markdown放到博客园的编辑器里有些不支持,直接转成html传上来了,以后在博客园写博还是不用markdown了。

04-26 19:18
查看更多