您需要 登录 才可以下载或查看,没有账号?注册
x
本帖最后由 大西几 于 2019-6-18 21:56 编辑
它的操作很简单,我非常喜欢。它也支持UI缩放,所在高DPI的显示器上效果也很好,这是很多其它程序不擅长的地方,我很喜欢这一点。你可以在左边的视框内创建角色和动画,在右边的视框可以看到各式各样的场景图在项目中的层级。主界面横跨在屏幕的底部。你可以使用组合键或者RMB和Ctrl + RMB很容易地在显示器上平移和缩放。这里有一些额外的复杂性被隐藏在下面这个菜单里:
但大多数时候,你所看到的实际上是所有你所需要的。这是一个非常干净和简单的用户界面。在左上角的通知栏显示SETUP。这是因为你当前正处在设置模式。一旦我们的精灵已经被装配并且骨骼动画被准备好,我们就可以通过点击SETUP切换到动画模式。 在动画模式下,都是角色动作的相关内容。SETUP模式切换到ANIMATE模式之后我们的界面稍有变化。现在我们在屏幕底部可以看到时间窗。我们可以查看动画的任一时刻。 创建Spine精灵 在Spine中创建一个能够动起来的精灵非常接近基于传统动画技术创建的精灵,但有如下两处不同。第一,将你的图片剪裁成不同的部分。如果你愿意,你可以将你一张图片制作一个精灵,但是你必须将它剪裁成不同的可动的部分。考虑一下来自上面屏幕的精灵: 它看起来像一个被绘制的独立的精灵,实际上却是由排列在一起的不同部分组成。如果你在项目的层次结构中查看图片部分,你可以看到它实际上是由几个不同的图片组成: 同样,你可以像平常一样绘制精灵,但是每个可动的部分需要被剪裁成不同的部分才能在Spine中运行。这也导致了我们的第二个要求,你需要绘制图片被遮盖的部分。同样,使用这个例子,虽然上臂由于身体的遮挡没有全部显示,但是你仍然需要绘制完整的手臂,因为它的可见性会随着精灵的移动而改变,例如: 所以当你绘制你的精灵的不同部分,你必须考虑深度。这里是组成例子中精灵模型的所有部分。 装配你的角色 接下来可能是用Spine工作最耗时部分,装配你的角色。你可以认为这是将各种各样的图片排列到一起同时定义在下面的支架(骨骼的好听说法),进而去创建你的角色。我们将做一个非常简单的骨骼,仅仅为了演示创建过程。你会注意到在层级树上的skeleton节点下有一个root节点: 这是骨骼的基础并且所有的骨骼最终都继承于它。在这里我们需要创建根节点骨骼,从臀部开始是非常常见的,这也是我们要做的 。使用Create工具,我们将快速的创建一个简单的腿骨骼。 鼠标点击第一次设置骨骼的起点位置,然后移动鼠标,点击第二次完成第一个骨骼的设置。现在向下稍微移动并且设置另一个骨骼,像这样: 在层级目录中我对骨骼进行重命名,使其显得有意义。 现在我们拥有了骨骼,接下来给每个骨骼贴上图片。 从图片目录部分你可以很简单地将合适的图片拖放到骨骼上,像这样: 如果你这么做,将会收到下面的提示: 现在图片依附于骨骼之上。通过选择图片你可以平移、旋转和缩放它,确定图片和在下面的骨骼是最匹配的: 你可以讲鼠标移至尖端的上方来改变骨骼的长度,像这样:
现在重复操作制作低一级的骨骼,像这样:
你最终的层级树应该是: 极其简单,但是不管怎么样角色被装配了腿。 生成动画 现在我们拥有了一个非常简单的可动的角色,让我们切换到动画模式。在树视图中你会发现一个叫做 Animations 的节点。这可能是默认的,也可以用当动画被选中时出现的NewAnimation按钮创建一个新的: 关键帧动画在概念上很简单。你会注意到在屏幕下方有一个Dopesheet视图: 动画是由一组关键帧组成。布置你的角色并且获取骨骼位置、旋转和缩放的快照,然后推进时间轴到不同的位置,重复上述过程。计算机会在关键帧之间进行插值去创建平滑的动画。这样当你编辑界面进行改变之后会自动设置为关键帧。否则你需要人工点击在变换栏右侧的绿色“钥匙“按钮去创建关键帧: 通过默认旋转、平移和缩放值设置关键帧,或者使用Atuokey。然后将时间轴刻度线调至5,如下图所示: 接着使用旋转,操纵每块骨骼,如下图所示: 微调时间轴线,然后重复以上过程。你可以用这个简单的VCR风格的控件来回放你的动画: 这是一个非常简单和粗糙的踢腿动画: 另外一件很棒的事情是你可以向时间轴线添加监听事件,如下图所示: 你可以在代码中加入事件监听,将音乐插入动画,例如加入一个播放脚步声的效果。我们下面将看到这个过程。 输出动画 现在我们有了在游戏中使用的动画,接下来我们要将它导出。这里有一组选项。
你可以将动画导出为一个视频、一组图片或者是数据文件。如果你选择导出为图片,有几个高级选项可供选择,生成纹理图集(可以在LibGDX中直接使用)或者是精灵图表。 结果如下: 这个方法几乎可以在当今流行的每一个游戏引擎中被利用。然而当使用Spine导出数据文件是会更有用处。 这里会使用到运行时环境。其本质上就是为各种游戏引擎开发的兼容性类库或代码,使你能够直接使用spine的原生格式。所有的资源都可以在github上获取,并且运行时支持绝大多数的2D引擎包括Unity, LibGDX, Love, MonoGame,Torque2D, Cocos2d-x等等。在本例中将使用LibGDX。 在这个示例中我将用以下设置导出JSON数据格式文件给你并且生成纹理图集: 现在让我贴出一部分代码。 在游戏开发中使用Spine 上文说过在github上可以获取Spine不同的可用的运行时。例如在LibGDX项目中,你可以将相关代码拷贝到功能的相应的文件夹中 。假设你使用utility创建了一个工程,你可以拷贝esotericsoftware的文件到你的core\src\com文件路径下。那么,我写了以下代码,在LibGDX官方示例代码基础上做了修改。 确定已经在工作目录下导出了你的资源并且创建了图集。然后使用下面的代码: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
| [size=1em]package [size=1em]com.gamefromscratch;
[size=1em]import [size=1em]com.badlogic.gdx.ApplicationAdapter;
[size=1em]import [size=1em]com.badlogic.gdx.Gdx;
[size=1em]import [size=1em]com.badlogic.gdx.graphics.GL20;
[size=1em]import [size=1em]com.badlogic.gdx.graphics.OrthographicCamera;
[size=1em]import [size=1em]com.badlogic.gdx.graphics.g2d.SpriteBatch;
[size=1em]import [size=1em]com.badlogic.gdx.graphics.g2d.TextureAtlas;
[size=1em]import [size=1em]com.esotericsoftware.spine.*;
[size=1em]public [size=1em]class [size=1em]Spine2 [size=1em]extends [size=1em]ApplicationAdapter {
[size=1em] [size=1em]private [size=1em]OrthographicCamera camera;
[size=1em] [size=1em]private [size=1em]SpriteBatch batch;
[size=1em] [size=1em]private [size=1em]SkeletonRenderer renderer;
[size=1em] [size=1em]private [size=1em]TextureAtlas atlas;
[size=1em] [size=1em]private [size=1em]Skeleton skeleton;
[size=1em] [size=1em]private [size=1em]AnimationState state;
[size=1em] [size=1em]public [size=1em]void [size=1em]create () {
[size=1em] [size=1em]camera = [size=1em]new [size=1em]OrthographicCamera();
[size=1em] [size=1em]camera.setToOrtho([size=1em]false[size=1em]);
[size=1em] [size=1em]batch = [size=1em]new [size=1em]SpriteBatch();
[size=1em] [size=1em]renderer = [size=1em]new [size=1em]SkeletonRenderer();
[size=1em] [size=1em]renderer.setPremultipliedAlpha([size=1em]true[size=1em]); [size=1em]// PMA results in correct blending without outlines.
[size=1em] [size=1em]atlas = [size=1em]new [size=1em]TextureAtlas(Gdx.files.internal([size=1em]"skeleton.atlas"[size=1em]));
[size=1em] [size=1em]SkeletonJson json = [size=1em]new [size=1em]SkeletonJson(atlas);
[size=1em] [size=1em]SkeletonData skeletonData = json.readSkeletonData(Gdx.files.internal([size=1em]"skeleton.json"[size=1em]));
[size=1em] [size=1em]skeleton = [size=1em]new [size=1em]Skeleton(skeletonData);
[size=1em] [size=1em]skeleton.setPosition([size=1em]0[size=1em], [size=1em]0[size=1em]);
[size=1em] [size=1em]AnimationStateData stateData = [size=1em]new [size=1em]AnimationStateData(skeletonData);
[size=1em] [size=1em]state = [size=1em]new [size=1em]AnimationState(stateData);
[size=1em] [size=1em]// Set up an animation listener so we can respond to custom events or completion
[size=1em] [size=1em]final [size=1em]AnimationState.TrackEntry track = state.setAnimation([size=1em]0[size=1em], [size=1em]"kick"[size=1em], [size=1em]false[size=1em]);
[size=1em] [size=1em]track.setListener([size=1em]new [size=1em]AnimationState.AnimationStateListener() {
[size=1em] [size=1em]@Override
[size=1em] [size=1em]public [size=1em]void [size=1em]event([size=1em]int [size=1em]trackIndex, Event event) {
[size=1em] [size=1em]// Check for the "half" event we defined in the editor
[size=1em] [size=1em]if[size=1em](event.getString().equals([size=1em]"half"[size=1em]))
[size=1em] [size=1em]System.out.println([size=1em]"Half way baby"[size=1em]);
[size=1em] [size=1em]}
[size=1em] [size=1em]@Override
[size=1em] [size=1em]public [size=1em]void [size=1em]complete([size=1em]int [size=1em]trackIndex, [size=1em]int [size=1em]loopCount) {
[size=1em] [size=1em]// or the complete event (not END!) when done, fire the idle animation instead
[size=1em] [size=1em]state.setAnimation([size=1em]0[size=1em],[size=1em]"idle"[size=1em],[size=1em]false[size=1em]);
[size=1em] [size=1em]}
[size=1em] [size=1em]@Override
[size=1em] [size=1em]public [size=1em]void [size=1em]start([size=1em]int [size=1em]trackIndex) {
[size=1em] [size=1em]}
[size=1em] [size=1em]@Override
[size=1em] [size=1em]public [size=1em]void [size=1em]end([size=1em]int [size=1em]trackIndex) {
[size=1em] [size=1em]}
[size=1em] [size=1em]});
[size=1em] [size=1em]}
[size=1em] [size=1em]public [size=1em]void [size=1em]render () {
[size=1em] [size=1em]state.update(Gdx.graphics.getDeltaTime()); [size=1em]// Update the animation time.
[size=1em] [size=1em]state.apply(skeleton);
[size=1em] [size=1em]skeleton.updateWorldTransform();
[size=1em] [size=1em]Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
[size=1em] [size=1em]camera.update();
[size=1em] [size=1em]batch.getProjectionMatrix().set(camera.combined);
[size=1em] [size=1em]batch.begin();
[size=1em] [size=1em]renderer.draw(batch, skeleton);
[size=1em] [size=1em]batch.end();
[size=1em] [size=1em]}
[size=1em] [size=1em]public [size=1em]void [size=1em]dispose () {
[size=1em] [size=1em]atlas.dispose();
[size=1em] [size=1em]}
[size=1em]}
|
当你运行这段代码… 在上面的示例代码中你可以看到在Spine中定义的处理事件的方法。另外,加载和播放在Spine中创建的角色动画是非常简单的。这是一个庞大的API,由于篇幅问题在这里只涉及了其中的一小部分(已经相当的长了…)。有一些特性我没有提及到(对一些形状比如披肩非常有用),例如自由变形、更换皮肤、使用道具等… 如果你正在做2D动画,Spine是一个可以考虑并试用的产品。 Spine并不是创建游戏2D动画的唯一选择,Spriter 和 Creature是两个可替代Spine的产品。然而Spine是一个非常不错的选择。
|