Merge pull request #452 from Lizard-13/skeleton-runtime-object

Add Skeleton object extension (still in Beta)
This commit is contained in:
Florian Rival
2018-04-23 21:50:09 +01:00
committed by GitHub
29 changed files with 6561 additions and 0 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"SubTexture":[{"frameY":0,"y":234,"frameWidth":112,"frameX":0,"frameHeight":210,"width":111,"height":209,"name":"parts/tailTip","x":456},{"width":112,"y":234,"height":86,"name":"parts/armUpperL","x":340},{"width":48,"y":859,"height":80,"name":"parts/armL","x":373},{"width":96,"y":922,"height":78,"name":"parts/handL","x":1},{"frameY":0,"y":677,"frameWidth":204,"frameX":0,"frameHeight":180,"width":203,"height":180,"name":"parts/legL","x":238},{"frameY":0,"y":397,"frameWidth":236,"frameX":0,"frameHeight":348,"width":235,"height":347,"name":"parts/body","x":1},{"width":216,"y":397,"height":278,"name":"parts/tail","x":238},{"width":208,"y":746,"height":174,"name":"parts/clothes1","x":1},{"width":124,"y":677,"height":282,"name":"parts/hair","x":443},{"frameY":0,"y":1,"frameWidth":338,"frameX":0,"frameHeight":394,"width":337,"height":394,"name":"parts/head","x":1},{"width":28,"y":961,"height":46,"name":"parts/eyeL","x":459},{"frameY":0,"y":961,"frameWidth":38,"frameX":0,"frameHeight":58,"width":37,"height":58,"name":"parts/eyeR","x":420},{"frameY":0,"y":1,"frameWidth":180,"frameX":0,"frameHeight":232,"width":180,"height":231,"name":"parts/legR","x":340},{"width":160,"y":859,"height":94,"name":"parts/armUpperR","x":211},{"frameY":0,"y":941,"frameWidth":46,"frameX":0,"frameHeight":78,"width":45,"height":77,"name":"parts/armR","x":373},{"width":98,"y":322,"height":58,"name":"parts/handR","x":340},{"frameY":0,"y":955,"frameWidth":120,"frameX":0,"frameHeight":36,"width":119,"height":36,"name":"parts/beardL","x":237},{"width":136,"y":955,"height":36,"name":"parts/beardR","x":99}],"width":1024,"height":1024,"name":"dragon","imagePath":"dragon_tex.png"}

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 B

View File

@@ -41,6 +41,7 @@ ADD_SUBDIRECTORY(PhysicsBehavior)
ADD_SUBDIRECTORY(PlatformBehavior)
ADD_SUBDIRECTORY(PrimitiveDrawing)
ADD_SUBDIRECTORY(Shopify)
ADD_SUBDIRECTORY(SkeletonObject)
IF (NOT EMSCRIPTEN)
ADD_SUBDIRECTORY(SoundObject)
ENDIF()

View File

@@ -0,0 +1,398 @@
/**
GDevelop - Skeleton Object Extension
Copyright (c) 2017-2018 Franco Maciel (francomaciel10@gmail.com)
This project is released under the MIT License.
*/
/**
* @namespace gdjs.sk
*/
gdjs.sk = gdjs.sk || {
// Some useful constants
SLOT_UNDEFINED: -1,
SLOT_IMAGE: 0,
SLOT_MESH: 1,
SLOT_POLYGON: 2,
SLOT_ARMATURE: 3,
EASING_CONST: 0,
EASING_LINEAR: 1,
EASING_CURVE: 2,
EVENT_STOP: 0,
EVENT_PLAY: 1,
EVENT_PLAYSINGLE: 2
};
/**
* The Matrix holds the basic transformation data in a matrix form.
*
* @namespace gdjs.sk
* @class Matrix
*/
gdjs.sk.Matrix = function(a=1, b=0, tx=0, c=0, d=1, ty=0){
this.a = a; this.b = b; this.tx = tx;
this.c = c; this.d = d; this.ty = ty;
this.u = 0; this.v = 0; this.w = 1;
};
gdjs.sk.Matrix.prototype.translation = function(x, y){
this.tx = x;
this.ty = y;
return this;
};
gdjs.sk.Matrix.prototype.rotation = function(angle){
this.a = Math.cos(angle); this.b = -Math.sin(angle);
this.c = Math.sin(angle); this.d = Math.cos(angle);
return this;
};
gdjs.sk.Matrix.prototype.scale = function(sx, sy){
this.a = sx;
this.d = sy;
return this;
};
gdjs.sk.Matrix.prototype.clone = function(){
return new gdjs.sk.Matrix(this.a, this.b, this.tx,
this.c, this.d, this.ty,
this.u, this.v, this.w );
};
gdjs.sk.Matrix.prototype.mul = function(m){
return new gdjs.sk.Matrix(this.a*m.a + this.b*m.c,
this.a*m.b + this.b*m.d,
this.a*m.tx + this.b*m.ty + this.tx,
this.c*m.a + this.d*m.c,
this.c*m.b + this.d*m.d,
this.c*m.tx + this.d*m.ty + this.ty);
};
gdjs.sk.Matrix.prototype.mulVec = function(v){
return [this.a*v[0] + this.b*v[1] + this.tx,
this.c*v[0] + this.d*v[1] + this.ty];
};
gdjs.sk.Matrix.prototype.invert = function(){
var det_inv = 1.0 / (this.a*this.d - this.b*this.c);
var a = this.a;
var tx = this.tx;
this.tx = (this.b*this.ty - this.d*tx)*det_inv;
this.ty = (this.c*tx - this.a*this.ty)*det_inv;
this.a = this.d*det_inv;
this.b =-this.b*det_inv;
this.c =-this.c*det_inv;
this.d = a*det_inv;
return this;
};
gdjs.sk.Matrix.prototype.inverse = function(){
var det_inv = 1.0 / (this.a*this.d - this.b*this.c);
return new gdjs.sk.Matrix( this.d*det_inv,
-this.b*det_inv,
(this.b*this.ty - this.d*this.tx)*det_inv,
-this.c*det_inv,
this.a*det_inv,
(this.c*this.tx - this.a*this.ty)*det_inv);
};
gdjs.sk.Matrix.prototype.str = function(){
return "|" + this.a.toFixed(2) + ", " + this.b.toFixed(2) + ", " + this.tx.toFixed(2) + "|\n" +
"|" + this.c.toFixed(2) + ", " + this.d.toFixed(2) + ", " + this.ty.toFixed(2) + "|\n" +
"|" + this.u.toFixed(2) + ", " + this.v.toFixed(2) + ", " + this.w.toFixed(2) + "|\n";
};
/**
* The Transform is the basic class for transformable objects as bones, slots and armatures.
*
* @namespace gdjs.sk
* @class Transform
*/
gdjs.sk.Transform = function(x=0, y=0, rot=0, sx=1, sy=1){
this.parent = null;
this.children = [];
this.x = x;
this.y = y;
this.rot = rot * Math.PI / 180.0;
this.sx = sx;
this.sy = sy;
this.matrix = new gdjs.sk.Matrix();
this.worldMatrix = new gdjs.sk.Matrix();
this._updateMatrix = true;
this._updateWorldMatrix = false;
this.inheritTranslation = true;
this.inheritRotation = true;
this.inheritScale = true;
};
gdjs.sk.Transform.prototype.addChild = function(child){
this.children.push(child);
child.reparent(this);
};
gdjs.sk.Transform.prototype.reparent = function(parent){
if(this.parent){
this.parent.removeChild(this);
}
this.parent = parent;
this._updateWorldMatrix = true;
};
gdjs.sk.Transform.prototype.removeChild = function(child){
var index = this.children.indexOf(child);
if(index > -1){
this.children.splice(index, 1);
}
};
gdjs.sk.Transform.prototype.getX = function(){
return this.x;
};
gdjs.sk.Transform.prototype.setX = function(x){
if(this.x !== x){
this.x = x;
this._updateMatrix = true;
}
};
gdjs.sk.Transform.prototype.getGlobalX = function(){
this.updateParentsTransform();
return this.worldMatrix.tx;
};
gdjs.sk.Transform.prototype.setGlobalX = function(x){
var globalY = this.getGlobalY(); // Also updates parent transforms
var localPos = this.parent.worldMatrix.inverse().mulVec([x, globalY, 1.0]);
this.x = localPos[0];
this.y = localPos[1];
this._updateMatrix = true;
};
gdjs.sk.Transform.prototype.getY = function(){
return this.y;
};
gdjs.sk.Transform.prototype.setY = function(y){
if(this.y !== y){
this.y = y;
this._updateMatrix = true;
}
};
gdjs.sk.Transform.prototype.getGlobalY = function(){
this.updateParentsTransform();
return this.worldMatrix.ty;
};
gdjs.sk.Transform.prototype.setGlobalY = function(y){
var globalX = this.getGlobalX(); // Also updates parent transforms
var localPos = this.parent.worldMatrix.inverse().mulVec([globalX, y, 1.0]);
this.x = localPos[0];
this.y = localPos[1];
this._updateMatrix = true;
};
gdjs.sk.Transform.prototype.setPos = function(x, y){
if(this.x !== x || this.y !== y){
this.x = x;
this.y = y;
this._updateMatrix = true;
}
};
gdjs.sk.Transform.prototype.getRot = function(){
return this.rot * 180.0 / Math.PI;
};
gdjs.sk.Transform.prototype.setRot = function(angle){
angle *= Math.PI / 180.0;
if(this.rot !== angle){
this.rot = angle;
this._updateMatrix = true;
}
};
gdjs.sk.Transform.prototype.getGlobalRot = function(){
this.updateParentsTransform();
var sx = Math.sqrt(this.worldMatrix.a * this.worldMatrix.a +
this.worldMatrix.c * this.worldMatrix.c );
var sy = Math.sqrt(this.worldMatrix.b * this.worldMatrix.b +
this.worldMatrix.d * this.worldMatrix.d );
return Math.atan2(-this.worldMatrix.b/sy, this.worldMatrix.a/sx) * 180.0 / Math.PI;
};
gdjs.sk.Transform.prototype.setGlobalRot = function(rot){
var parentGlobalRot = this.parent ? this.parent.getGlobalRot() : 0;
this.rot = (rot - parentGlobalRot)*Math.PI/180.0;
this._updateMatrix = true;
};
gdjs.sk.Transform.prototype.getSx = function(){
return this.sx;
};
gdjs.sk.Transform.prototype.getSy = function(){
return this.sy;
};
gdjs.sk.Transform.prototype.setSx = function(sx){
if(this.sx !== sx){
this.sx = sx;
this._updateMatrix = true;
}
};
gdjs.sk.Transform.prototype.setSy = function(sy){
if(this.sy !== sy){
this.sy = sy;
this._updateMatrix = true;
}
};
gdjs.sk.Transform.prototype.setScale = function(sx, sy){
if(this.sx !== sx || this.sy !== sy){
this.sx = sx;
this.sy = sy;
this._updateMatrix = true;
}
};
gdjs.sk.Transform.prototype.move = function(x, y){
this.x += x;
this.y += y;
this._updateMatrix = true;
};
gdjs.sk.Transform.prototype.rotate = function(angle){
this.rot += angle * Math.PI / 180.0;
this._updateMatrix = true;
};
gdjs.sk.Transform.prototype.scale = function(sx, sy){
this.sx *= sx;
this.sy *= sy;
this._updateMatrix = true;
};
gdjs.sk.Transform.prototype.update = function(){
this.updateTransform();
for(var i=0; i<this.children.length; i++){
this.children[i].update();
}
};
gdjs.sk.Transform.prototype.updateTransform = function(){
var sin_rot, cos_rot;
if(this._updateMatrix || this._updateWorldMatrix){
sin_rot = Math.sin(this.rot);
cos_rot = Math.cos(this.rot);
}
if(this._updateMatrix){
this.matrix = new gdjs.sk.Matrix(this.sx*cos_rot,-this.sy*sin_rot, this.x,
this.sx*sin_rot, this.sy*cos_rot, this.y,
0, 0, 1);
}
if(this._updateMatrix || this._updateWorldMatrix){
if(!this.parent){
this.worldMatrix = this.matrix.clone();
}
else{
this.worldMatrix = this.parent.worldMatrix.mul(this.matrix);
if(!this.inheritRotation || !this.inheritScale){
if(this.inheritScale){ // Non iherited rotation
var worldSx = Math.sqrt(this.worldMatrix.a*this.worldMatrix.a +
this.worldMatrix.c*this.worldMatrix.c);
var worldSy = Math.sqrt(this.worldMatrix.b*this.worldMatrix.b +
this.worldMatrix.d*this.worldMatrix.d);
this.worldMatrix.a = worldSx*cos_rot;
this.worldMatrix.b = -worldSy*sin_rot;
this.worldMatrix.c = worldSx*sin_rot;
this.worldMatrix.d = worldSy*cos_rot;
}
else if(this.inheritRotation){ // Non inherited scale
var worldSx = Math.sqrt(this.worldMatrix.a*this.worldMatrix.a +
this.worldMatrix.c*this.worldMatrix.c);
var worldSy = Math.sqrt(this.worldMatrix.b*this.worldMatrix.b +
this.worldMatrix.d*this.worldMatrix.d);
this.worldMatrix.a *= this.sx / worldSx;
this.worldMatrix.b *= this.sy / worldSy;
this.worldMatrix.c *= this.sx / worldSx;
this.worldMatrix.d *= this.sy / worldSy;
}
else{ // Non inherited rotation nor scale
this.worldMatrix.a = this.sx*cos_rot;
this.worldMatrix.b = -this.sy*sin_rot;
this.worldMatrix.c = this.sx*sin_rot;
this.worldMatrix.d = this.sy*cos_rot;
}
}
if(!this.inheritTranslation){
this.worldMatrix.tx = this.x;
this.worldMatrix.ty = this.y;
}
}
for(var i=0; i<this.children.length; i++){
this.children[i]._updateWorldMatrix = true;
}
}
this._updateMatrix = false;
this._updateWorldMatrix = false;
};
gdjs.sk.Transform.prototype.updateParentsTransform = function(){
if(this.parent){
this.parent.updateParentsTransform();
}
this.updateTransform();
};
gdjs.sk.Transform.prototype.transformPolygon = function(vertices){
this.updateParentsTransform();
var worldPoly = new gdjs.Polygon();
for(var i=0; i<vertices.length; i++){
worldPoly.vertices.push(this.worldMatrix.mulVec(vertices[i]));
}
return worldPoly;
};
gdjs.sk.Transform._statics = {
transform: {
x: 0,
y: 0,
sx: 1,
sy: 1,
skx: 0,
sky: 0,
rot: 0
}
};
gdjs.sk.Transform.decomposeMatrix = function(matrix){
var transform = gdjs.sk.Transform._statics.transform;
transform.x = matrix.tx
transform.y = matrix.ty;
var sx = Math.sqrt(matrix.a*matrix.a + matrix.c*matrix.c);
var sy = Math.sqrt(matrix.b*matrix.b + matrix.d*matrix.d);
transform.sx = sx;
transform.sy = sy;
transform.skx = -Math.atan2(matrix.d, matrix.b) + Math.PI/2.0;
transform.sky = Math.atan2(matrix.c, matrix.a);
transform.rot = Math.atan2(-matrix.b/sy, matrix.a/sx);
return transform;
};

View File

@@ -0,0 +1,174 @@
/**
GDevelop - Skeleton Object Extension
Copyright (c) 2017-2018 Franco Maciel (francomaciel10@gmail.com)
This project is released under the MIT License.
*/
gdjs.sk.CocosDataLoader = function()
{
this.textures = {};
};
gdjs.sk.DataLoader = gdjs.sk.CocosDataLoader;
gdjs.sk.CocosDataLoader.prototype.getData = function(dataName){
return cc.loader.getRes("res/"+dataName);
};
gdjs.sk.CocosDataLoader.prototype.loadDragonBones = function(runtimeScene, objectData){
var textureData = this.getData(objectData.textureDataFilename);
var texture = runtimeScene.getGame().getImageManager().getTexture(objectData.textureName);
if(!textureData || !texture._textureLoaded) return;
for(var i=0; i<textureData.SubTexture.length; i++){
var subTex = textureData.SubTexture[i];
var frame = new cc.rect(subTex.x, subTex.y, subTex.width, subTex.height);
if(subTex.hasOwnProperty("frameWidth")){
frame.width = subTex.frameWidth;
}
if (subTex.hasOwnProperty("frameHeight")){
frame.height = subTex.frameHeight;
}
this.textures[subTex.name] = {"texture": texture, "frame": frame};
}
};
gdjs.sk.ArmatureCocosRenderer = function()
{
this.layer = new cc.Layer();
this.slotsRenderers = new cc.Layer();
this.layer.addChild(this.slotsRenderers);
this.debugRenderers = new cc.Layer();
this.layer.addChild(this.debugRenderers);
this._convertYPosition = function(y){ return y; };
};
gdjs.sk.ArmatureRenderer = gdjs.sk.ArmatureCocosRenderer;
gdjs.sk.ArmatureCocosRenderer.prototype.putInScene = function(runtimeObject, runtimeScene){
var layerRenderer = runtimeScene.getLayer("").getRenderer();
layerRenderer.addRendererObject(this.layer, runtimeObject.getZOrder());
this._convertYPosition = layerRenderer.convertYPosition;
};
gdjs.sk.ArmatureCocosRenderer.prototype.getRendererObject = function(){
return this.layer;
};
gdjs.sk.ArmatureCocosRenderer.prototype.addRenderer = function(renderer){
this.slotsRenderers.addChild(renderer.getRendererObject());
renderer._convertYPosition = this._convertYPosition;
};
gdjs.sk.ArmatureCocosRenderer.prototype.sortRenderers = function(){
this.slotsRenderers.children.sort(function(a, b){ return a.z - b.z; });
};
gdjs.sk.ArmatureCocosRenderer.prototype.addDebugRenderer = function(renderer){
this.debugRenderers.addChild(renderer.getRendererObject());
renderer._convertYPosition = this._convertYPosition;
};
gdjs.sk.ArmatureCocosRenderer.prototype.extraInitialization = function(parentArmatureRenderer){
this._convertYPosition = parentArmatureRenderer._convertYPosition;
};
gdjs.sk.SlotCocosRenderer = function()
{
this.renderer = null;
this._convertYPosition = function(y){ return y; };
};
gdjs.sk.SlotRenderer = gdjs.sk.SlotCocosRenderer;
gdjs.sk.SlotCocosRenderer.prototype.getRendererObject = function(){
return this.renderer;
};
gdjs.sk.SlotCocosRenderer.prototype.loadAsSprite = function(texture){
if(!texture)
this.renderer = new cc.Sprite();
else
this.renderer = new cc.Sprite.createWithTexture(texture.texture, texture.frame);
this.renderer.z = 0;
};
gdjs.sk.SlotCocosRenderer.prototype.loadAsMesh = function(texture, vertices, uvs, triangles){
// Meshes not supported, load as sprites
this.loadAsSprite(texture);
};
gdjs.sk.SlotCocosRenderer.prototype.getWidth = function(){
return this.renderer.width;
};
gdjs.sk.SlotCocosRenderer.prototype.getHeight = function(){
return this.renderer.height;
};
gdjs.sk.SlotCocosRenderer.prototype.setTransform = function(transform){
this.renderer.setPositionX(transform.x);
this.renderer.setPositionY(this._convertYPosition(transform.y));
this.renderer.setScaleX(transform.sx);
this.renderer.setScaleY(transform.sy);
this.renderer.setRotationX(-transform.skx*180.0/Math.PI);
this.renderer.setRotationY( transform.sky*180.0/Math.PI);
};
gdjs.sk.SlotCocosRenderer.prototype.setZ = function(z){
this.renderer.z = z;
};
gdjs.sk.SlotCocosRenderer.prototype.setColor = function(color){
this.renderer.setColor(cc.color(color[0], color[1], color[2]));
};
gdjs.sk.SlotCocosRenderer.prototype.setAlpha = function(alpha){
this.renderer.setOpacity(255*alpha);
};
gdjs.sk.SlotCocosRenderer.prototype.setVisible = function(visible){
this.renderer.setVisible(visible);
};
// Meshes not supported
gdjs.sk.SlotCocosRenderer.prototype.setVertices = function(vertices, updateList){
};
gdjs.sk.DebugCocosRenderer = function()
{
this.renderer = new cc.DrawNode();
this._convertYPosition = function(y){ return y; };
};
gdjs.sk.DebugRenderer = gdjs.sk.DebugCocosRenderer;
gdjs.sk.DebugCocosRenderer.prototype.getRendererObject = function(){
return this.renderer;
};
gdjs.sk.DebugCocosRenderer.prototype.loadVertices = function(verts, color, fill){
var fillAlpha = fill ? 100 : 0;
var fillColor = new cc.Color(color[0], color[1], color[2], fillAlpha);
var lineColor = new cc.Color(color[0], color[1], color[2], 225);
for(var i=0; i<verts.length; i++){
var vertices = [];
for(var i=0; i<verts.length; i++){
vertices.push(cc.p(verts[i][0], -verts[i][1]));
}
this.renderer.drawPoly(vertices, fillColor, 3, lineColor);
}
};
gdjs.sk.DebugCocosRenderer.prototype.setTransform = function(transform){
this.renderer.setPositionX(transform.x);
this.renderer.setPositionY(this._convertYPosition(transform.y));
this.renderer.setScaleX(transform.sx);
this.renderer.setScaleY(transform.sy);
this.renderer.setRotationX(-transform.skx*180.0/Math.PI);
this.renderer.setRotationY( transform.sky*180.0/Math.PI);
};

View File

@@ -0,0 +1,187 @@
/**
GDevelop - Skeleton Object Extension
Copyright (c) 2017-2018 Franco Maciel (francomaciel10@gmail.com)
This project is released under the MIT License.
*/
gdjs.sk.PixiDataLoader = function()
{
this.textures = {};
};
gdjs.sk.DataLoader = gdjs.sk.PixiDataLoader;
gdjs.sk.PixiDataLoader.prototype.getData = function(dataName){
if(PIXI.loader.resources[dataName]){
return PIXI.loader.resources[dataName].data;
}
return null;
};
gdjs.sk.PixiDataLoader.prototype.loadDragonBones = function(runtimeScene, objectData){
var textureData = this.getData(objectData.textureDataFilename);
var texture = runtimeScene.getGame().getImageManager().getPIXITexture(objectData.textureName);
if(!textureData || !texture.valid) return;
for(var i=0; i<textureData.SubTexture.length; i++){
var subTex = textureData.SubTexture[i];
var frame = new PIXI.Rectangle(subTex.x, subTex.y, subTex.width, subTex.height);
if(subTex.hasOwnProperty("frameWidth")){
frame.width = subTex.frameWidth;
}
if (subTex.hasOwnProperty("frameHeight")){
frame.height = subTex.frameHeight;
}
// Fix the frame size, in case texture is not loaded
if(frame.x > texture.width) frame.x = 0;
if(frame.y > texture.height) frame.y = 0;
if(frame.x + frame.width > texture.width) frame.width = texture.width - frame.x;
if(frame.y + frame.height > texture.height) frame.height = texture.height - frame.y;
this.textures[subTex.name] = new PIXI.Texture(texture.baseTexture, frame=frame);
}
};
gdjs.sk.ArmaturePixiRenderer = function()
{
this.container = new PIXI.Container();
this.slotsRenderers = new PIXI.Container();
this.container.addChild(this.slotsRenderers);
this.debugRenderers = new PIXI.Container();
this.container.addChild(this.debugRenderers);
};
gdjs.sk.ArmatureRenderer = gdjs.sk.ArmaturePixiRenderer;
gdjs.sk.ArmaturePixiRenderer.prototype.putInScene = function(runtimeObject, runtimeScene){
runtimeScene.getLayer("").getRenderer().addRendererObject(this.container, runtimeObject.getZOrder());
};
gdjs.sk.ArmaturePixiRenderer.prototype.getRendererObject = function(){
return this.container;
};
gdjs.sk.ArmaturePixiRenderer.prototype.addRenderer = function(renderer){
this.slotsRenderers.addChild(renderer.getRendererObject());
};
gdjs.sk.ArmaturePixiRenderer.prototype.sortRenderers = function(){
this.slotsRenderers.children.sort(function(a, b){ return a.z - b.z; });
};
gdjs.sk.ArmaturePixiRenderer.prototype.addDebugRenderer = function(renderer){
this.debugRenderers.addChild(renderer.getRendererObject());
};
gdjs.sk.ArmaturePixiRenderer.prototype.extraInitialization = function(parentArmatureRenderer){
};
gdjs.sk.SlotPixiRenderer = function()
{
this.renderer = null;
};
gdjs.sk.SlotRenderer = gdjs.sk.SlotPixiRenderer;
gdjs.sk.SlotPixiRenderer.prototype.getRendererObject = function(){
return this.renderer;
};
gdjs.sk.SlotPixiRenderer.prototype.loadAsSprite = function(texture){
this.renderer = new PIXI.Sprite(texture);
this.renderer.pivot = new PIXI.Point(this.renderer.width/2.0, this.renderer.height/2.0);
this.renderer.z = 0;
};
gdjs.sk.SlotPixiRenderer.prototype.loadAsMesh = function(texture, vertices, uvs, triangles){
this.renderer = new PIXI.mesh.Mesh(texture,
new Float32Array(vertices),
new Float32Array(uvs),
new Uint16Array(triangles),
PIXI.mesh.Mesh.DRAW_MODES.TRIANGLES);
this.renderer.uploadUvTransform = true;
this.renderer.z = 0;
};
gdjs.sk.SlotPixiRenderer.prototype.getWidth = function(){
return this.renderer.width;
};
gdjs.sk.SlotPixiRenderer.prototype.getHeight = function(){
return this.renderer.height;
};
gdjs.sk.SlotPixiRenderer.prototype.setTransform = function(transform){
this.renderer.x = transform.x;
this.renderer.y = transform.y;
this.renderer.scale.x = transform.sx;
this.renderer.scale.y = transform.sy;
this.renderer.skew.x = transform.skx;
this.renderer.skew.y = transform.sky;
};
gdjs.sk.SlotPixiRenderer.prototype.setZ = function(z){
this.renderer.z = z;
};
gdjs.sk.SlotPixiRenderer.prototype.setColor = function(color){
this.renderer.tint = (color[0] << 16) + (color[1] << 8) + color[2];
};
gdjs.sk.SlotPixiRenderer.prototype.setAlpha = function(alpha){
this.renderer.alpha = alpha;
};
gdjs.sk.SlotPixiRenderer.prototype.setVisible = function(visible){
this.renderer.visible = visible;
};
// Mesh only
gdjs.sk.SlotPixiRenderer.prototype.setVertices = function(vertices, updateList){
for(var i=0; i<updateList.length; i++){
this.renderer.vertices[2*updateList[i]] = vertices[i][0];
this.renderer.vertices[2*updateList[i] + 1] = vertices[i][1];
}
};
gdjs.sk.DebugPixiRenderer = function()
{
this.renderer = new PIXI.Graphics();
};
gdjs.sk.DebugRenderer = gdjs.sk.DebugPixiRenderer;
gdjs.sk.DebugPixiRenderer.prototype.getRendererObject = function(){
return this.renderer;
};
gdjs.sk.DebugPixiRenderer.prototype.loadVertices = function(verts, color, fill){
color = color[2] | (color[1] << 8) | (color[0] << 16);
if(fill){
this.renderer.beginFill(color, 0.1);
}
this.renderer.lineStyle(3, color, 0.8);
for(var i=0; i<verts.length; i++){
this.renderer.drawPolygon(verts.reduce(function(a, b){ return a.concat(b); }).concat(verts[0]));
}
if(fill){
this.renderer.endFill();
}
};
gdjs.sk.DebugPixiRenderer.prototype.setTransform = function(transform){
this.renderer.x = transform.x;
this.renderer.y = transform.y;
this.renderer.scale.x = transform.sx;
this.renderer.scale.y = transform.sy;
this.renderer.skew.x = transform.skx;
this.renderer.skew.y = transform.sky;
};
gdjs.sk.DebugPixiRenderer.prototype.skewSupported = function(){
return true;
};

View File

@@ -0,0 +1,20 @@
cmake_minimum_required(VERSION 2.6)
cmake_policy(SET CMP0015 NEW)
project(SkeletonObject)
gd_add_extension_includes()
#Defines
###
gd_add_extension_definitions(SkeletonObject)
#The targets
###
include_directories(.)
file(GLOB source_files *)
gd_add_extension_target(SkeletonObject "${source_files}" "JsPlatform")
#Linker files for the IDE extension
###
gd_extension_link_libraries(SkeletonObject)

View File

@@ -0,0 +1,131 @@
/**
GDevelop - Skeleton Object Extension
Copyright (c) 2017-2018 Franco Maciel (francomaciel10@gmail.com)
This project is released under the MIT License.
*/
/**
* @namespace gdjs.sk
* @class SharedBone
*/
gdjs.sk.SharedBone = function(){
this.x = 0;
this.y = 0;
this.rot = 0;
this.sx = 1;
this.sy = 1;
this.name = "";
this.length = 0;
this.parent = -1;
this.childBones = [];
this.childSlots = [];
this.restX = 0;
this.restY = 0;
this.restRot = 0;
this.restSx = 1;
this.restSy = 1;
};
gdjs.sk.SharedBone.prototype.loadDragonBones = function(boneData){
this.name = boneData.name;
this.length = boneData.hasOwnProperty("length") ? boneData.length : 0;
var transformData = boneData.transform;
this.restX = transformData.hasOwnProperty("x") ? transformData.x : 0;
this.restY = transformData.hasOwnProperty("y") ? transformData.y : 0;
this.restRot = transformData.hasOwnProperty("skX") ? transformData.skX * Math.PI / 180.0 : 0;
this.restSx = transformData.hasOwnProperty("scX") ? transformData.scX : 1;
this.restSy = transformData.hasOwnProperty("scY") ? transformData.scY : 1;
this.inheritRotation = boneData.hasOwnProperty("inheritRotation") ? transformData.inheritRotation : true;
this.inheritScale = boneData.hasOwnProperty("inheritScale") ? transformData.inheritScale : true;
};
/**
* The Bone holds basic transform data in a hierarchy tree.
*
* @namespace gdjs.sk
* @class Bone
* @extends gdjs.sk.Transform
*/
gdjs.sk.Bone = function(armature){
gdjs.sk.Transform.call(this);
this.shared = null;
this.armature = armature;
};
gdjs.sk.Bone.prototype = Object.create(gdjs.sk.Transform.prototype);
gdjs.sk.Bone.prototype.loadData = function(boneData){
this.shared = boneData;
this.resetState();
};
gdjs.sk.Bone.prototype.resetState = function(){
this.setPos(0, 0);
this.setRot(0);
this.setScale(1, 1);
};
gdjs.sk.Bone.prototype.setX = function(x){
var prevX = this.x;
this.x = this.shared.restX + x;
if(this.x !== prevX){
this._updateMatrix = true;
}
};
gdjs.sk.Bone.prototype.setY = function(y){
var prevY = this.y;
this.y = this.shared.restY + y;
if(this.y !== prevY){
this._updateMatrix = true;
}
};
gdjs.sk.Bone.prototype.setPos = function(x, y){
var prevX = this.x;
var prevY = this.y;
this.x = this.shared.restX + x;
this.y = this.shared.restY + y;
if(this.x !== prevX || this.y !== prevY){
this._updateMatrix = true;
}
};
gdjs.sk.Bone.prototype.setRot = function(angle){
var prevRot = this.rot;
this.rot = this.shared.restRot + angle*Math.PI/180.0;
if(this.rot !== prevRot){
this._updateMatrix = true;
}
};
gdjs.sk.Bone.prototype.setSx = function(sx){
var prevSx = this.sx;
this.sx = this.shared.restSx * sx;
if(this.sx !== prevSx){
this._updateMatrix = true;
}
};
gdjs.sk.Bone.prototype.setSy = function(sy){
var prevSy = this.sy;
this.sy = this.shared.restSy * sy;
if(this.sy !== prevSy){
this._updateMatrix = true;
}
};
gdjs.sk.Bone.prototype.setScale = function(sx, sy){
var prevSx = this.sx;
var prevSy = this.sy;
this.sx = this.shared.restSx * sx;
this.sy = this.shared.restSy * sy;
if(this.sx !== prevSx || this.sy !== prevSy){
this._updateMatrix = true;
}
};

View File

@@ -0,0 +1,456 @@
/**
GDevelop - Skeleton Object Extension
Copyright (c) 2017-2018 Franco Maciel (francomaciel10@gmail.com)
This project is released under the MIT License.
*/
/**
* @namespace gdjs.sk
* @class SharedSlot
*/
gdjs.sk.SharedSlot = function(){
// Transform
this.x = 0;
this.y = 0;
this.rot = 0;
this.sx = 1;
this.sy = 1;
// Slot
this.name = "";
this.type = gdjs.sk.SLOT_UNDEFINED;
this.path = "";
this.parent = -1;
this.defaultZ = 0;
this.defaultR = 255;
this.defaultG = 255;
this.defaultB = 255;
this.defaultAlpha = 1.0;
this.defaultVisible = true;
this.aabb = null;
// Polygon
this.polygons = [];
// Mesh
this.rawVertices = [];
this.rawUVs = [];
this.rawTriangles = [];
this.defaultVertices = [];
this.skinned = false;
this.skinBones = [];
this.skinBonesMatricesInverses = [];
this.vertexBones = [];
this.vertexWeights = [];
// Armature
this.armature = "";
};
gdjs.sk.SharedSlot.prototype.loadDragonBonesSlotData = function(slotData){
this.name = slotData.name;
this.defaultZ = slotData.hasOwnProperty("z") ? slotData.z : 0;
this.defaultR = slotData.color.hasOwnProperty("rM") ? Math.ceil(slotData.color.rM * 255 / 100) : 255;
this.defaultG = slotData.color.hasOwnProperty("gM") ? Math.ceil(slotData.color.gM * 255 / 100) : 255;
this.defaultB = slotData.color.hasOwnProperty("bM") ? Math.ceil(slotData.color.bM * 255 / 100) : 255;
this.defaultAlpha = slotData.color.hasOwnProperty("aM") ? slotData.color.aM / 100.0 : 1.0;
this.defaultVisible = slotData.hasOwnProperty("displayIndex") ? (slotData.displayIndex + 1) / 2 : 1; // {-1, 1} -> {0, 1}
};
gdjs.sk.SharedSlot.prototype.loadDragonBonesSkinData = function(skinDatas, index){
var skinData = skinDatas[index];
var transformData = skinData.display[0].transform;
this.x = transformData.hasOwnProperty("x") ? transformData.x : 0;
this.y = transformData.hasOwnProperty("y") ? transformData.y : 0;
this.rot = transformData.hasOwnProperty("skX") ? transformData.skX * Math.PI / 180.0 : 0;
this.sx = transformData.hasOwnProperty("scX") ? transformData.scX : 1;
this.sy = transformData.hasOwnProperty("scY") ? transformData.scY : 1;
// If another slot is already using the same image path we have to search for it
if(!skinData.display[0].hasOwnProperty("path")){
for(var i=0; i<skinDatas.length; i++){
if(skinDatas[i].display[0].name === skinData.display[0].name && skinDatas[i].display[0].path){
this.path = skinDatas[i].display[0].path;
break;
}
}
}
else{
this.path = skinData.display[0].path;
}
if(skinData.display[0].type === "image"){
this.type = gdjs.sk.SLOT_IMAGE;
}
else if(skinData.display[0].type === "armature"){
this.type = gdjs.sk.SLOT_ARMATURE;
}
else if(skinData.display[0].type === "boundingBox"){
this.type = gdjs.sk.SLOT_POLYGON;
var polygon = [];
var verts = skinData.display[0].vertices;
for(var i=0; i<verts.length; i+=2){
polygon.push([verts[i], verts[i+1]]);
}
this.polygons.push(polygon);
}
else if(skinData.display[0].type === "mesh"){
this.type = gdjs.sk.SLOT_MESH;
for(var i=0; i<skinData.display[0].vertices.length; i+=2){
this.defaultVertices.push([skinData.display[0].vertices[i],
skinData.display[0].vertices[i+1]]);
}
this.rawVertices = skinData.display[0].vertices;
this.rawUVs = skinData.display[0].uvs;
this.rawTriangles = skinData.display[0].triangles;
if(skinData.display[0].hasOwnProperty("weights")){
this.skinned = true;
var slotPose = skinData.display[0].slotPose;
var worldMatrixInverse = new gdjs.sk.Matrix( slotPose[0],-slotPose[1], slotPose[4],
-slotPose[2], slotPose[3], slotPose[5]);
worldMatrixInverse.invert();
// maps Armature.bones index -> skinBones index
var boneMap = {};
for(var i=0, j=0; i<skinData.display[0].bonePose.length; i+=7, j++){
var bonePose = skinData.display[0].bonePose;
var boneWorldMatrix = new gdjs.sk.Matrix( bonePose[i+1],-bonePose[i+2], bonePose[i+5],
-bonePose[i+3], bonePose[i+4], bonePose[i+6]);
boneMap[bonePose[i]] = j;
this.skinBones.push(bonePose[i]);
this.skinBonesMatricesInverses.push(worldMatrixInverse.mul(boneWorldMatrix).invert());
}
for(var i=0; i<skinData.display[0].weights.length;){
var boneCount = skinData.display[0].weights[i];
var vertexWeights = [];
var vertexBones = [];
for(var k=0; k<boneCount; k++){
var boneId = skinData.display[0].weights[i + 2*k + 1];
vertexBones.push(boneMap[boneId]);
var boneWeight = skinData.display[0].weights[i + 2*k + 2];
vertexWeights.push(boneWeight);
}
this.vertexBones.push(vertexBones);
this.vertexWeights.push(vertexWeights);
i += 2 * boneCount + 1;
}
}
}
};
/**
* The Slot display images transformed by animations itself and bones.
*
* @namespace gdjs.sk
* @class Slot
* @extends gdjs.sk.Transform
*/
gdjs.sk.Slot = function(armature){
gdjs.sk.Transform.call(this);
this.shared = null;
this.armature = armature;
this.z = 0;
this.r = 0;
this.g = 0;
this.b = 0;
this.alpha = 0;
this.visible = false;
this.renderer = new gdjs.sk.SlotRenderer();
this._updateRender = false;
// Mesh only
this.vertices = []; // same as this.shared.defaultVertices, but modified on animations
this.skinBones = [];
// Armature only
this.childArmature = null;
// Debug only
this.debugRenderer = null;
}
gdjs.sk.Slot.prototype = Object.create(gdjs.sk.Transform.prototype);
gdjs.sk.Slot.prototype.loadData = function(slotData, skeletalData, textures, debugPolygons){
this.shared = slotData;
this.z = this.shared.defaultZ;
this.r = this.shared.defaultR;
this.g = this.shared.defaultG;
this.b = this.shared.defaultB;
this.alpha = this.shared.defaultAlpha;
this.visible = this.shared.defaultVisible;
this.x = this.shared.x;
this.y = this.shared.y;
this.rot = this.shared.rot;
this.sx = this.shared.sx;
this.sy = this.shared.sy;
this._updateMatrix = true;
this._updateWorldMatrix = true;
if(this.shared.type === gdjs.sk.SLOT_IMAGE){
this.renderer.loadAsSprite(textures[this.shared.path]);
if(!this.shared.aabb){
this.shared.aabb = [];
this.shared.aabb.push([-this.renderer.getWidth()/2.0,-this.renderer.getHeight()/2.0]);
this.shared.aabb.push([ this.renderer.getWidth()/2.0,-this.renderer.getHeight()/2.0]);
this.shared.aabb.push([ this.renderer.getWidth()/2.0, this.renderer.getHeight()/2.0]);
this.shared.aabb.push([-this.renderer.getWidth()/2.0, this.renderer.getHeight()/2.0]);
}
if(debugPolygons){
this.debugRenderer = new gdjs.sk.DebugRenderer();
this.debugRenderer.loadVertices(this.shared.aabb, [255, 100, 100], false);
}
}
else if(this.shared.type === gdjs.sk.SLOT_MESH){
for(var i=0; i<this.shared.defaultVertices.length; i++){
this.vertices.push([this.shared.defaultVertices[i][0], this.shared.defaultVertices[i][1]]);
}
for(var i=0; i<this.shared.skinBones.length; i++){
this.skinBones.push(this.armature.bones[this.shared.skinBones[i]]);
}
this.renderer.loadAsMesh(textures[this.shared.path],
this.shared.rawVertices,
this.shared.rawUVs,
this.shared.rawTriangles);
if(!this.shared.aabb){
this.shared.aabb = [];
this.shared.aabb.push([-this.renderer.getWidth()/2.0,-this.renderer.getHeight()/2.0]);
this.shared.aabb.push([ this.renderer.getWidth()/2.0,-this.renderer.getHeight()/2.0]);
this.shared.aabb.push([ this.renderer.getWidth()/2.0, this.renderer.getHeight()/2.0]);
this.shared.aabb.push([-this.renderer.getWidth()/2.0, this.renderer.getHeight()/2.0]);
}
if(debugPolygons){
this.debugRenderer = new gdjs.sk.DebugRenderer();
this.debugRenderer.loadVertices(this.shared.aabb, [255, 100, 100], false);
}
}
else if(this.shared.type === gdjs.sk.SLOT_POLYGON){
if(debugPolygons){
this.debugRenderer = new gdjs.sk.DebugRenderer();
this.debugRenderer.loadVertices(this.shared.polygons[0], [100, 255, 100], true);
}
}
else if(this.shared.type === gdjs.sk.SLOT_ARMATURE){
for(var i=0; i<skeletalData.armatures.length; i++){
if(skeletalData.armatures[i].name === this.shared.path){
this.childArmature = new gdjs.sk.Armature(this.armature.skeleton, this.armature, this);
this.childArmature.getRenderer().extraInitialization(this.armature.getRenderer());
this.childArmature.loadData(skeletalData.armatures[i], skeletalData, debugPolygons);
this.addChild(this.childArmature);
if(!this.shared.aabb){
this.shared.aabb = [];
var verts = this.childArmature.getAABB().vertices;
for(var j=0; j<verts.length; j++){
this.shared.aabb.push([verts[j][0], verts[j][1]]);
}
}
}
}
}
this.updateRendererColor();
this.updateRendererAlpha();
this.updateRendererVisible();
};
gdjs.sk.Slot.prototype.resetState = function(){
this.setZ(this.shared.defaultZ);
this.setColor(this.shared.defaultR, this.shared.defaultG, this.shared.defaultB);
this.setAlpha(this.shared.defaultAlpha);
this.setVisible(this.shared.defaultVisible);
if(this.shared.type === gdjs.sk.SLOT_MESH){
var verts = [];
var updateList = [];
for(var i=0; i<this.shared.defaultVertices.length; i++){
verts.push([0, 0]);
updateList.push(i);
}
this.setVertices(verts, updateList);
}
if(this.shared.type === gdjs.sk.SLOT_ARMATURE){
this.childArmature.resetState();
}
};
gdjs.sk.Slot.prototype.getZ = function(){
return this.z;
};
gdjs.sk.Slot.prototype.setZ = function(z){
this.z = z;
if(this.shared.type === gdjs.sk.SLOT_IMAGE || this.shared.type === gdjs.sk.SLOT_MESH){
this.renderer.setZ(z);
}
};
gdjs.sk.Slot.prototype.getColor = function(){
if(!this.armature.parentSlot){
return [this.r, this.g, this.b];
}
var armatureColor = this.armature.parentSlot.getColor();
return [this.r * armatureColor[0] / 255,
this.g * armatureColor[1] / 255,
this.b * armatureColor[2] / 255];
};
gdjs.sk.Slot.prototype.setColor = function(r, g, b){
if(this.r !== r || this.g !== g || this.b !== b){
this.r = r;
this.g = g;
this.b = b;
this.updateRendererColor();
}
};
gdjs.sk.Slot.prototype.updateRendererColor = function(){
if(this.shared.type === gdjs.sk.SLOT_IMAGE || this.shared.type === gdjs.sk.SLOT_MESH){
this.renderer.setColor(this.getColor());
}
else if(this.shared.type === gdjs.sk.SLOT_ARMATURE && this.childArmature){
for(var i=0; i<this.childArmature.slots.length; i++){
this.childArmature.slots[i].updateRendererColor();
}
}
};
gdjs.sk.Slot.prototype.getAlpha = function(){
if(!this.armature.parentSlot){
return this.alpha;
}
var armatureAlpha = this.armature.parentSlot.getAlpha();
return (this.alpha * armatureAlpha);
};
gdjs.sk.Slot.prototype.setAlpha = function(alpha){
if(this.alpha !== alpha){
this.alpha = alpha;
this.updateRendererAlpha();
}
};
gdjs.sk.Slot.prototype.updateRendererAlpha = function(){
if(this.shared.type === gdjs.sk.SLOT_IMAGE || this.shared.type === gdjs.sk.SLOT_MESH){
this.renderer.setAlpha(this.getAlpha());
}
else if(this.shared.type === gdjs.sk.SLOT_ARMATURE && this.childArmature){
for(var i=0; i<this.childArmature.slots.length; i++){
this.childArmature.slots[i].updateRendererAlpha();
}
}
};
gdjs.sk.Slot.prototype.getVisible = function(){
if(!this.armature.parentSlot){
return this.visible;
}
return (this.visible && this.armature.parentSlot.getVisible());
};
gdjs.sk.Slot.prototype.setVisible = function(visible){
if(this.visible !== visible){
this.visible = visible;
this.updateRendererVisible();
}
};
gdjs.sk.Slot.prototype.updateRendererVisible = function(){
if(this.shared.type === gdjs.sk.SLOT_IMAGE || this.shared.type === gdjs.sk.SLOT_MESH){
this.renderer.setVisible(this.getVisible());
}
else if(this.shared.type === gdjs.sk.SLOT_ARMATURE && this.childArmature){
for(var i=0; i<this.childArmature.slots.length; i++){
this.childArmature.slots[i].updateRendererVisible();
}
}
};
// Mesh only
gdjs.sk.Slot.prototype.setVertices = function(vertices, updateList){
var verts = [];
for(var i=0; i<updateList.length; i++){
this.vertices[updateList[i]] = [vertices[i][0] + this.shared.defaultVertices[updateList[i]][0],
vertices[i][1] + this.shared.defaultVertices[updateList[i]][1]];
verts.push(this.vertices[updateList[i]]);
}
this.renderer.setVertices(verts, updateList);
}
// Mesh only
gdjs.sk.Slot.prototype.updateSkinning = function(){
var verts = [];
var updateList = [];
var boneMatrices = [];
var inverseWorldMatrix = this.worldMatrix.inverse();
for(var i=0; i<this.skinBones.length; i++){
var localBoneMatrix = inverseWorldMatrix.mul(this.skinBones[i].worldMatrix);
boneMatrices.push(localBoneMatrix.mul(this.shared.skinBonesMatricesInverses[i]));
}
for(var i=0; i<this.shared.vertexWeights.length; i++){
var vx = 0.0;
var vy = 0.0;
for(var j=0; j<this.shared.vertexWeights[i].length; j++){
var v = boneMatrices[this.shared.vertexBones[i][j]].mulVec(this.vertices[i]);
vx += this.shared.vertexWeights[i][j] * v[0];
vy += this.shared.vertexWeights[i][j] * v[1];
}
verts.push([vx, vy]);
updateList.push(i);
}
this.renderer.setVertices(verts, updateList);
};
gdjs.sk.Slot.prototype.getPolygons = function(){
if(this.shared.type === gdjs.sk.SLOT_POLYGON){
var worldPolygons = [];
for(var i=0; i<this.shared.polygons.length; i++){
worldPolygons.push(this.transformPolygon(this.shared.polygons[i]));
}
return worldPolygons;
}
return [this.transformPolygon(this.shared.aabb)];
};
gdjs.sk.Slot.prototype.update = function(){
gdjs.sk.Transform.prototype.update.call(this);
if(this._updateRender && (this.shared.type === gdjs.sk.SLOT_IMAGE || this.shared.type === gdjs.sk.SLOT_MESH)){
var transform = gdjs.sk.Transform.decomposeMatrix(this.worldMatrix);
this.renderer.setTransform(transform);
}
if(this._updateRender && this.debugRenderer){
var transform = gdjs.sk.Transform.decomposeMatrix(this.worldMatrix);
this.debugRenderer.setTransform(transform);
}
this._updateRender = false;
};
gdjs.sk.Slot.prototype.updateTransform = function(){
if(this._updateMatrix || this._updateWorldMatrix){
this._updateRender = true;
}
gdjs.sk.Transform.prototype.updateTransform.call(this);
};

View File

@@ -0,0 +1,317 @@
/**
GDevelop - Skeleton Object Extension
Copyright (c) 2017-2018 Franco Maciel (francomaciel10@gmail.com)
This project is released under the MIT License.
*/
/**
* @namespace gdjs.sk
* @class SharedArmature
*/
gdjs.sk.SharedArmature = function(){
this.name = "";
this.bones = [];
this.bonesMap = {};
this.rootBone = -1;
this.slots = [];
this.slotsMap = {};
this.animations = [];
this.animationsMap = {};
this.aabb = [];
};
gdjs.sk.SharedArmature.prototype.loadDragonBones = function(armatureData, textures){
this.name = armatureData.name;
var aabb = armatureData.aabb;
this.aabb.push([aabb.x, aabb.y ]);
this.aabb.push([aabb.x + aabb.width, aabb.y ]);
this.aabb.push([aabb.x + aabb.width, aabb.y + aabb.height]);
this.aabb.push([aabb.x, aabb.y + aabb.height]);
// Get all the bones
for(var i=0; i<armatureData.bone.length; i++){
var bone = new gdjs.sk.SharedBone();
bone.loadDragonBones(armatureData.bone[i]);
this.bones.push(bone);
this.bonesMap[armatureData.bone[i].name] = i;
}
// Set bone parents
for(var i=0; i<armatureData.bone.length; i++){
if(armatureData.bone[i].hasOwnProperty("parent")){ // Child bone
this.bones[i].parent = this.bonesMap[armatureData.bone[i].parent];
this.bones[this.bones[i].parent].childBones.push(i);
}
else{ // Root bone
this.rootBone = i;
}
}
// Get all the slots
for(var i=0; i<armatureData.slot.length; i++){
var slot = new gdjs.sk.SharedSlot()
slot.loadDragonBonesSlotData(armatureData.slot[i]);
this.slots.push(slot);
this.slotsMap[armatureData.slot[i].name] = i;
this.slots[i].parent = this.bonesMap[armatureData.slot[i].parent];
this.bones[this.slots[i].parent].childSlots.push(i);
}
// Generate displayers
for(var i=0; i<armatureData.skin[0].slot.length; i++){
var skinData = armatureData.skin[0].slot[i];
var slot = this.slots[this.slotsMap[skinData.name]];
slot.loadDragonBonesSkinData(armatureData.skin[0].slot, i);
}
// Get all the animations
for(var i=0; i<armatureData.animation.length; i++){
var animation = new gdjs.sk.SharedAnimation();
animation.loadDragonBones(armatureData.animation[i], armatureData.frameRate, this.slots);
this.animations.push(animation);
this.animationsMap[animation.name] = i;
}
};
/**
* The Armature holds the bones and slots/attachments as well as its animations.
*
* @namespace gdjs.sk
* @class Armature
* @extends gdjs.sk.Transform
*/
gdjs.sk.Armature = function(skeleton, parentArmature=null, parentSlot=null){
gdjs.sk.Transform.call(this);
this.shared = null;
this.skeleton = skeleton;
this.parentArmature = parentArmature;
this.parentSlot = parentSlot;
this.bones = [];
this.bonesMap = {};
this.slots = [];
this.slotsMap = {};
this.animations = [];
this.animationsMap = {};
this.currentAnimation = -1;
this.renderer = new gdjs.sk.ArmatureRenderer();
this.debugRenderer = null;
this.isRoot = false;
};
gdjs.sk.Armature.prototype = Object.create(gdjs.sk.Transform.prototype);
gdjs.sk.Armature.prototype.loadData = function(armatureData, skeletalData, debugPolygons){
this.shared = armatureData;
if(debugPolygons){
this.debugRenderer = new gdjs.sk.DebugRenderer();
this.debugRenderer.loadVertices(this.shared.aabb, [100, 100, 255], false);
}
// Get all the bones
for(var i=0; i<this.shared.bones.length; i++){
var bone = new gdjs.sk.Bone(this);
bone.loadData(this.shared.bones[i]);
this.bones.push(bone);
this.bonesMap[bone.shared.name] = bone;
}
// With all the bones loaded, set parents
for(var i=0; i<this.shared.bones.length; i++){
if(this.shared.bones[i].parent !== -1){ // Child bone
this.bones[this.shared.bones[i].parent].addChild(this.bones[i]);
}
else{ // Root bone
this.addChild(this.bones[i]);
}
}
// Get all the slots
for(var i=0; i<this.shared.slots.length; i++){
var slot = new gdjs.sk.Slot(this);
this.bones[this.shared.slots[i].parent].addChild(slot);
slot.loadData(this.shared.slots[i], skeletalData, skeletalData.loader.textures, debugPolygons);
this.slots.push(slot);
this.slotsMap[slot.shared.name] = slot;
}
// Get all the animations
for(var i=0; i<this.shared.animations.length; i++){
var animation = new gdjs.sk.Animation(this);
animation.loadData(this.shared.animations[i]);
this.animations.push(animation);
this.animationsMap[animation.shared.name] = animation;
}
this.setRenderers();
};
gdjs.sk.Armature.prototype.setAsRoot = function(){
this.isRoot = true;
// Create an empty shared data, in case nothing is loaded
this.shared = new gdjs.sk.SharedArmature();
this.shared.aabb = [[0,0], [0,0], [0,0], [0,0]];
};
gdjs.sk.Armature.prototype.getRenderer = function(){
return this.renderer;
};
gdjs.sk.Armature.prototype.getRendererObject = function(){
return this.renderer.getRendererObject();
};
gdjs.sk.Armature.prototype.setRenderers = function(){
for(var i=0; i<this.slots.length; i++){
if(this.slots[i].shared.type === gdjs.sk.SLOT_IMAGE || this.slots[i].shared.type === gdjs.sk.SLOT_MESH){
this.renderer.addRenderer(this.slots[i].renderer);
if(this.slots[i].debugRenderer){
this.renderer.addDebugRenderer(this.slots[i].debugRenderer);
}
}
else if(this.slots[i].shared.type === gdjs.sk.SLOT_ARMATURE){
this.renderer.addRenderer(this.slots[i].childArmature.renderer);
if(this.slots[i].childArmature.debugRenderer){
this.renderer.addDebugRenderer(this.slots[i].childArmature.debugRenderer);
}
}
else if(this.slots[i].shared.type === gdjs.sk.SLOT_POLYGON){
if(this.slots[i].debugRenderer){
this.renderer.addDebugRenderer(this.slots[i].debugRenderer);
}
}
}
if(this.isRoot){
this.renderer.addDebugRenderer(this.debugRenderer);
}
};
gdjs.sk.Armature.prototype.getAABB = function(){
return this.transformPolygon(this.shared.aabb);
};
gdjs.sk.Armature.prototype.getDefaultWidth = function(){
return this.shared.aabb[1][0] - this.shared.aabb[0][0];
};
gdjs.sk.Armature.prototype.getDefaultHeight = function(){
return this.shared.aabb[2][1] - this.shared.aabb[1][1];
};
gdjs.sk.Armature.prototype.resetState = function(){
for(var i=0; i<this.bones.length; i++){
this.bones[i].resetState();
}
for(var i=0; i<this.slots.length; i++){
this.slots[i].resetState();
}
this.renderer.sortRenderers();
};
gdjs.sk.Armature.prototype.updateZOrder = function(){
this.renderer.sortRenderers();
};
gdjs.sk.Armature.prototype.update = function(){
gdjs.sk.Transform.prototype.update.call(this);
if(this.debugRenderer){
var transform = gdjs.sk.Transform.decomposeMatrix(this.worldMatrix);
this.debugRenderer.setTransform(transform);
}
};
gdjs.sk.Armature.prototype.getCurrentAnimation = function(){
if(this.currentAnimation >= 0 && this.currentAnimation < this.animations.length){
return this.animations[this.currentAnimation];
}
return null;
};
gdjs.sk.Armature.prototype.updateAnimation = function(delta){
var animation = this.getCurrentAnimation();
if(animation){
animation.update(delta);
}
};
gdjs.sk.Armature.prototype.isAnimationFinished = function(){
var animation = this.getCurrentAnimation();
return animation ? animation.isFinished() : false;
};
gdjs.sk.Armature.prototype.getAnimationTime = function(){
var animation = this.getCurrentAnimation();
return animation ? animation.getTime() : 0;
};
gdjs.sk.Armature.prototype.setAnimationTime = function(time){
var animation = this.getCurrentAnimation();
if(animation){
animation.setTime(time);
}
};
gdjs.sk.Armature.prototype.getAnimationTimeLength = function(){
var animation = this.getCurrentAnimation();
return animation ? animation.getTimeLength() : 0;
};
gdjs.sk.Armature.prototype.getAnimationFrame = function(){
var animation = this.getCurrentAnimation();
return animation ? animation.getFrame() : 0;
};
gdjs.sk.Armature.prototype.setAnimationFrame = function(frame){
var animation = this.getCurrentAnimation();
if(animation){
animation.setFrame(frame);
}
};
gdjs.sk.Armature.prototype.getAnimationFrameLength = function(){
var animation = this.getCurrentAnimation();
return animation ? animation.getFrameLength() : 0;
};
gdjs.sk.Armature.prototype.getAnimationIndex = function(){
return this.currentAnimation;
};
gdjs.sk.Armature.prototype.setAnimationIndex = function(newAnimation, blendTime, loops){
if(newAnimation >= 0 && newAnimation < this.animations.length && newAnimation !== this.currentAnimation){
this.resetState();
var oldAnimation = this.currentAnimation;
this.currentAnimation = newAnimation;
this.animations[this.currentAnimation].reset(loops);
if(blendTime > 0 && oldAnimation >= 0 && oldAnimation < this.animations.length){
this.animations[this.currentAnimation].blendFrom(this.animations[oldAnimation], blendTime);
}
var armatureAnimators = this.animations[this.currentAnimation].armatureAnimators;
for(var i=0; i<armatureAnimators.length; i++){
armatureAnimators[i].setFirstFrameAnimation(blendTime);
}
this.animations[this.currentAnimation].update(0);
}
};
gdjs.sk.Armature.prototype.getAnimationName = function(){
var animation = this.getCurrentAnimation();
return animation ? animation.shared.name : "";
};
gdjs.sk.Armature.prototype.setAnimationName = function(newAnimation, blendTime, loops){
if(newAnimation in this.animationsMap){
this.setAnimationIndex(this.animations.indexOf(this.animationsMap[newAnimation]), blendTime, loops);
}
};
gdjs.sk.Armature.prototype.resetAnimation = function(){
var animation = this.getCurrentAnimation();
if(animation){
animation.reset();
}
};

View File

@@ -0,0 +1,678 @@
/**
GDevelop - Skeleton Object Extension
Copyright (c) 2017-2018 Franco Maciel (francomaciel10@gmail.com)
This project is released under the MIT License.
*/
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/Tools/Localization.h"
#include "SkeletonObject.h"
void DeclareSkeletonObjectExtension(gd::PlatformExtension & extension)
{
extension.SetExtensionInformation("SkeletonObject",
_("Skeleton"),
_("Enables the use of animated skeleton objects.\nCurrently supported formats:\n *DragonBones"),
"Franco Maciel",
"Open source (MIT License)");
gd::ObjectMetadata & obj = extension.AddObject<SkeletonObject>(
"Skeleton",
_("Skeleton"),
_("Object animated through bones"),
"JsPlatform/Extensions/skeletonicon.png");
#if !defined(GD_NO_WX_GUI)
SkeletonObject::LoadEdittimeIcon();
#endif
// Object instructions
obj.AddCondition("ScaleX",
_("Scale X"),
_("Check the object scale X."),
_("Current scale X of _PARAM0_ is _PARAM1__PARAM2_"),
_("Size"),
"JsPlatform/Extensions/skeletonicon24.png",
"JsPlatform/Extensions/skeletonicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddAction("SetScaleX",
_("Scale X"),
_("Change the object scale X."),
_("Set _PARAM0_ scale X _PARAM1__PARAM2_"),
_("Size"),
"JsPlatform/Extensions/skeletonicon24.png",
"JsPlatform/Extensions/skeletonicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddExpression("ScaleX", _("Scale X"), _("Object scale X"), _("Size"), "JsPlatform/Extensions/skeletonicon16.png")
.AddParameter("object", _("Object"), "Skeleton");
obj.AddCondition("ScaleY",
_("Scale Y"),
_("Check the object scale Y."),
_("Current scale Y of _PARAM0_ is _PARAM1__PARAM2_"),
_("Size"),
"JsPlatform/Extensions/skeletonicon24.png",
"JsPlatform/Extensions/skeletonicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddAction("SetScaleY",
_("Scale Y"),
_("Change the object scale Y."),
_("Set _PARAM0_ scale Y _PARAM1__PARAM2_"),
_("Size"),
"JsPlatform/Extensions/skeletonicon24.png",
"JsPlatform/Extensions/skeletonicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddExpression("ScaleY", _("Scale Y"), _("Object scale Y"), _("Size"), "JsPlatform/Extensions/skeletonicon16.png")
.AddParameter("object", _("Object"), "Skeleton");
obj.AddCondition("Width",
_("Width"),
_("Check the object width."),
_("Current width of _PARAM0_ is _PARAM1__PARAM2_"),
_("Size"),
"JsPlatform/Extensions/skeletonicon24.png",
"JsPlatform/Extensions/skeletonicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddAction("SetWidth",
_("Width"),
_("Change the object width."),
_("Set _PARAM0_ width _PARAM1__PARAM2_"),
_("Size"),
"JsPlatform/Extensions/skeletonicon24.png",
"JsPlatform/Extensions/skeletonicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddExpression("Width", _("Width"), _("Object width"), _("Size"), "JsPlatform/Extensions/skeletonicon16.png")
.AddParameter("object", _("Object"), "Skeleton");
obj.AddCondition("Height",
_("Height"),
_("Check the object height."),
_("Current height of _PARAM0_ is _PARAM1__PARAM2_"),
_("Size"),
"JsPlatform/Extensions/skeletonicon24.png",
"JsPlatform/Extensions/skeletonicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddAction("SetHeight",
_("Height"),
_("Change the object height."),
_("Set _PARAM0_ height _PARAM1__PARAM2_"),
_("Size"),
"JsPlatform/Extensions/skeletonicon24.png",
"JsPlatform/Extensions/skeletonicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddExpression("Height", _("Height"), _("Object height"), _("Size"), "JsPlatform/Extensions/skeletonicon16.png")
.AddParameter("object", _("Object"), "Skeleton");
obj.AddAction("SetDefaultHitbox",
_("Default hitbox"),
_("Change the object default hitbox to be used by other conditions and behaviors."),
_("Set _PARAM0_ default hitbox to _PARAM1_"),
_("Size"),
"JsPlatform/Extensions/skeletonicon24.png",
"JsPlatform/Extensions/skeletonicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Slot path")).SetDefaultValue("\"\"");
// Animation instructions
obj.AddCondition("AnimationPaused",
_("Paused"),
_("Test if the animation for the skeleton is paused"),
_("Animation of _PARAM0_ is paused"),
_("Animation"),
"JsPlatform/Extensions/skeletonanimationicon24.png",
"JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton");
obj.AddAction("PauseAnimation",
_("Pause"),
_("Pauses animation for the skeleton"),
_("Pause animation for _PARAM0_"),
_("Animation"),
"JsPlatform/Extensions/skeletonanimationicon24.png",
"JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddCodeOnlyParameter("yesorno", "").SetDefaultValue("true");
obj.AddAction("UnpauseAnimation",
_("Unpause"),
_("Unpauses animation for the skeleton"),
_("Unpause animation for _PARAM0_"),
_("Animation"),
"JsPlatform/Extensions/skeletonanimationicon24.png",
"JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddCodeOnlyParameter("yesorno", "").SetDefaultValue("false");
obj.AddCondition("AnimationFinished",
_("Finished"),
_("Test if the animation has finished on this frame"),
_("Animation of _PARAM0_ has finished"),
_("Animation"),
"JsPlatform/Extensions/skeletonanimationicon24.png",
"JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton");
obj.AddCondition("AnimationTime",
_("Current time"),
_("Check the current animation elapsed time."),
_("Current animation time of _PARAM0_ is _PARAM1_ _PARAM2_"),
_("Animation"),
"JsPlatform/Extensions/skeletonanimationicon24.png",
"JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddAction("SetAnimationTime",
_("Current time"),
_("Change the current animation elapsed time."),
_("Set _PARAM0_ current animation time _PARAM1__PARAM2_"),
_("Animation"),
"JsPlatform/Extensions/skeletonanimationicon24.png",
"JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddExpression("AnimationTime", _("Current time"), _("Current animation elapsed time"), _("Animation"), "JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton");
obj.AddExpression("AnimationTimeLength", _("Animation time length"), _("Current animation time length"), _("Animation"), "JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton");
obj.AddCondition("AnimationFrame",
_("Current frame"),
_("Check the current animation frame.\nIf the animation is set as smooth, a float can be (and probably will be) returned."),
_("Current animation frame of _PARAM0_ is _PARAM1__PARAM2_"),
_("Animation"),
"JsPlatform/Extensions/skeletonanimationicon24.png",
"JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddAction("SetAnimationFrame",
_("Current frame"),
_("Change the current animation frame"),
_("Set _PARAM0_ current animation frame _PARAM1__PARAM2_"),
_("Animation"),
"JsPlatform/Extensions/skeletonanimationicon24.png",
"JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddExpression("AnimationFrame", _("Current frame"), _("Current animation frame"), _("Animation"), "JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton");
obj.AddExpression("AnimationFrameLength", _("Animation frame length"), _("Current animation frame length"), _("Animation"), "JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton");
obj.AddCondition("AnimationIndex",
_("Animation index"),
_("Check the current animation index.\nIf not sure about the index, you can use the \"by name\" action"),
_("Current animation of _PARAM0_ is _PARAM1__PARAM2_"),
_("Animation"),
"JsPlatform/Extensions/skeletonanimationicon24.png",
"JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddAction("SetAnimationIndex",
_("Animation index"),
_("Change the current animation from the animation index.\nIf not sure about the index, you can use the \"by name\" action"),
_("Set _PARAM0_ animation _PARAM1__PARAM2_"),
_("Animation"),
"JsPlatform/Extensions/skeletonanimationicon24.png",
"JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.AddParameter("expression", _("Blend time (0 for automatic blending)"), "", true).SetDefaultValue("0")
.AddParameter("expression", _("Loops (0 for infinite loops)"), "", true).SetDefaultValue("-1")
.SetManipulatedType("number");
obj.AddExpression("AnimationIndex", _("Animation index"), _("Current animation index"), _("Animation"), "JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton");
obj.AddCondition("AnimationName",
_("Animation name"),
_("Check the current animation name."),
_("Current animation of _PARAM0_ is _PARAM1__PARAM2_"),
_("Animation"),
"JsPlatform/Extensions/skeletonanimationicon24.png",
"JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("string", _("Text"))
.SetManipulatedType("string");
obj.AddAction("SetAnimationName",
_("Animation name"),
_("Change the current animation from the animation name."),
_("Set _PARAM0_ animation to _PARAM1_"),
_("Animation"),
"JsPlatform/Extensions/skeletonanimationicon24.png",
"JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Text"))
.AddParameter("expression", _("Blend time (0 for automatic blending)"), "", true).SetDefaultValue("0")
.AddParameter("expression", _("Loops (0 for infinite loops)"), "", true).SetDefaultValue("-1");
obj.AddStrExpression("AnimationName", _("Animation name"), _("Current animation name"), _("Animation"), "JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton");
obj.AddCondition("AnimationSmooth",
_("Smooth"),
_("Check if the object animation interpolator is smooth."),
_("Animation mode of _PARAM0_ is smooth"),
_("Animation"),
"JsPlatform/Extensions/skeletonanimationicon24.png",
"JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton");
obj.AddAction("SetAnimationSmooth",
_("Smooth"),
_("Change the object animation interpolator."),
_("Set animation mode of _PARAM0_ as smooth: _PARAM1_"),
_("Animation"),
"JsPlatform/Extensions/skeletonanimationicon24.png",
"JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("yesorno", _("Smooth"));
obj.AddCondition("AnimationTimeScale",
_("Time scale"),
_("Check the animation time scale."),
_("Animation time scale of _PARAM0_ is _PARAM1__PARAM2_"),
_("Animation"),
"JsPlatform/Extensions/skeletonanimationicon24.png",
"JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddAction("SetAnimationTimeScale",
_("Time scale"),
_("Change the animation time scale"),
_("Set _PARAM0_ animation time scale _PARAM1__PARAM2_"),
_("Animation"),
"JsPlatform/Extensions/skeletonanimationicon24.png",
"JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddExpression("AnimationTimeScale", _("Time scale"), _("Animation time scale"), _("Animation"), "JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton");
obj.AddAction("ResetAnimation",
_("Reset"),
_("Reset current animation"),
_("Reset _PARAM0_ current animation"),
_("Animation"),
"JsPlatform/Extensions/skeletonanimationicon24.png",
"JsPlatform/Extensions/skeletonanimationicon16.png")
.AddParameter("object", _("Object"), "Skeleton");
// Bone instructions
obj.AddCondition("BonePositionX",
_("Position X"),
_("Check the bone position X."),
_("Current position X of _PARAM0_:_PARAM1_ is _PARAM2__PARAM3_"),
_("Bone"),
"JsPlatform/Extensions/skeletonboneicon24.png",
"JsPlatform/Extensions/skeletonboneicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Bone path")).SetDefaultValue("\"\"")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddAction("SetBonePositionX",
_("Position X"),
_("Change the bone position X."),
_("Set _PARAM0_:_PARAM1_ position X _PARAM2__PARAM3_"),
_("Bone"),
"JsPlatform/Extensions/skeletonboneicon24.png",
"JsPlatform/Extensions/skeletonboneicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Bone path")).SetDefaultValue("\"\"")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddExpression("BonePositionX", _("Position X"), _("Bone position X"), _("Bone"), "JsPlatform/Extensions/skeletonboneicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Bone path")).SetDefaultValue("\"\"");
obj.AddCondition("BonePositionY",
_("Position Y"),
_("Check the bone position Y."),
_("Current position Y of _PARAM0_:_PARAM1_ is _PARAM2__PARAM3_"),
_("Bone"),
"JsPlatform/Extensions/skeletonboneicon24.png",
"JsPlatform/Extensions/skeletonboneicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Bone path")).SetDefaultValue("\"\"")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddAction("SetBonePositionY",
_("Position Y"),
_("Change the bone position Y."),
_("Set _PARAM0_:_PARAM1_ position Y _PARAM2__PARAM3_"),
_("Bone"),
"JsPlatform/Extensions/skeletonboneicon24.png",
"JsPlatform/Extensions/skeletonboneicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Bone path")).SetDefaultValue("\"\"")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddExpression("BonePositionY", _("Position Y"), _("Bone position Y"), _("Bone"), "JsPlatform/Extensions/skeletonboneicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Bone path")).SetDefaultValue("\"\"");
obj.AddAction("SetBonePosition",
_("Position"),
_("Change the bone position."),
_("Set _PARAM0_:_PARAM1_ position X _PARAM2__PARAM3_; Y _PARAM4__PARAM5_"),
_("Bone"),
"JsPlatform/Extensions/skeletonboneicon24.png",
"JsPlatform/Extensions/skeletonboneicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Bone path")).SetDefaultValue("\"\"")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Position X"))
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Position Y"));
obj.AddCondition("BoneAngle",
_("Angle"),
_("Check the bone angle (in degrees)."),
_("Current angle of _PARAM0_:_PARAM1_ is _PARAM2__PARAM3_"),
_("Bone"),
"JsPlatform/Extensions/skeletonboneicon24.png",
"JsPlatform/Extensions/skeletonboneicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Bone path")).SetDefaultValue("\"\"")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddAction("SetBoneAngle",
_("Angle"),
_("Change the bone angle (in degrees)."),
_("Set _PARAM0_:_PARAM1_ angle _PARAM2__PARAM3_"),
_("Bone"),
"JsPlatform/Extensions/skeletonboneicon24.png",
"JsPlatform/Extensions/skeletonboneicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Bone path")).SetDefaultValue("\"\"")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddExpression("BoneAngle", _("Angle"), _("Slot angle (in degrees)"), _("Bone"), "JsPlatform/Extensions/skeletonboneicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Bone path")).SetDefaultValue("\"\"");
obj.AddCondition("BoneScaleX",
_("Scale X"),
_("Check the bone scale X."),
_("Current scale X of _PARAM0_:_PARAM1_ is _PARAM2__PARAM3_"),
_("Bone"),
"JsPlatform/Extensions/skeletonboneicon24.png",
"JsPlatform/Extensions/skeletonboneicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Bone path")).SetDefaultValue("\"\"")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddAction("SetBoneScaleX",
_("Scale X"),
_("Change the bone scale X."),
_("Set _PARAM0_:_PARAM1_ scale X _PARAM2__PARAM3_"),
_("Bone"),
"JsPlatform/Extensions/skeletonboneicon24.png",
"JsPlatform/Extensions/skeletonboneicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Bone path")).SetDefaultValue("\"\"")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddExpression("BoneScaleX", _("Scale X"), _("Slot scale X"), _("Bone"), "JsPlatform/Extensions/skeletonboneicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Bone path")).SetDefaultValue("\"\"");
obj.AddCondition("BoneScaleY",
_("Scale Y"),
_("Check the bone scale Y."),
_("Current scale Y of _PARAM0_:_PARAM1_ is _PARAM2__PARAM3_"),
_("Bone"),
"JsPlatform/Extensions/skeletonboneicon24.png",
"JsPlatform/Extensions/skeletonboneicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Bone path")).SetDefaultValue("\"\"")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddAction("SetBoneScaleY",
_("Scale Y"),
_("Change the bone scale Y."),
_("Set _PARAM0_:_PARAM1_ scale Y _PARAM2__PARAM3_"),
_("Bone"),
"JsPlatform/Extensions/skeletonboneicon24.png",
"JsPlatform/Extensions/skeletonboneicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Bone path")).SetDefaultValue("\"\"")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddExpression("BoneScaleY", _("Scale Y"), _("Slot scale Y"), _("Bone"), "JsPlatform/Extensions/skeletonboneicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Bone path")).SetDefaultValue("\"\"");
obj.AddAction("SetBoneScale",
_("Scale"),
_("Change the bone scale."),
_("Set _PARAM0_:_PARAM1_ scale X _PARAM2__PARAM3_; Y _PARAM4__PARAM5_"),
_("Bone"),
"JsPlatform/Extensions/skeletonboneicon24.png",
"JsPlatform/Extensions/skeletonboneicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Bone path")).SetDefaultValue("\"\"")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Scale X"))
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Scale Y"));
obj.AddAction("ResetBone",
_("Reset"),
_("Reset the bone transformation."),
_("Reset _PARAM0_:_PARAM1_ transformation"),
_("Bone"),
"JsPlatform/Extensions/skeletonboneicon24.png",
"JsPlatform/Extensions/skeletonboneicon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Bone path")).SetDefaultValue("\"\"");
// Slot instructions
obj.AddAction("SetSlotColor",
_("Color"),
_("Change the slot color."),
_("Set _PARAM0_:_PARAM1_ color to _PARAM2_"),
_("Slot"),
"JsPlatform/Extensions/skeletonsloticon24.png",
"JsPlatform/Extensions/skeletonsloticon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Sloth path")).SetDefaultValue("\"\"")
.AddParameter("color", _("Color"));
obj.AddCondition("SlotVisible",
_("Visible"),
_("Check the slot visibility."),
_("_PARAM0_:_PARAM1_ is visible"),
_("Slot"),
"JsPlatform/Extensions/skeletonsloticon24.png",
"JsPlatform/Extensions/skeletonsloticon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Slot path")).SetDefaultValue("\"\"");
obj.AddAction("ShowSlot",
_("Show"),
_("Show the slot, making it visible."),
_("Show _PARAM0_:_PARAM1_"),
_("Slot"),
"JsPlatform/Extensions/skeletonsloticon24.png",
"JsPlatform/Extensions/skeletonsloticon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Slot path")).SetDefaultValue("\"\"")
.AddCodeOnlyParameter("yesorno", "").SetDefaultValue("true");
obj.AddAction("HideSlot",
_("Hide"),
_("Hide the slot, making it invisible."),
_("Hide _PARAM0_:_PARAM1_"),
_("Slot"),
"JsPlatform/Extensions/skeletonsloticon24.png",
"JsPlatform/Extensions/skeletonsloticon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Slot path")).SetDefaultValue("\"\"")
.AddCodeOnlyParameter("yesorno", "").SetDefaultValue("false");
obj.AddCondition("SlotZOrder",
_("Z-order"),
_("Check the slot Z-order."),
_("Z-order of _PARAM0_:_PARAM1_ is _PARAM2__PARAM3_"),
_("Slot"),
"JsPlatform/Extensions/skeletonsloticon24.png",
"JsPlatform/Extensions/skeletonsloticon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Slot path")).SetDefaultValue("\"\"")
.AddParameter("relationalOperator", _("Sign of the test"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddAction("SetSlotZOrder",
_("Z-order"),
_("Change the slot Z-order."),
_("Set _PARAM0_:_PARAM1_ Z-order _PARAM2__PARAM3_"),
_("Slot"),
"JsPlatform/Extensions/skeletonsloticon24.png",
"JsPlatform/Extensions/skeletonsloticon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Slot path")).SetDefaultValue("\"\"")
.AddParameter("operator", _("Modification's sign"))
.AddParameter("expression", _("Value"))
.SetManipulatedType("number");
obj.AddExpression("SlotZOrder", _("Z-order"), _("Slot Z-order"), _("Slot"), "JsPlatform/Extensions/skeletonsloticon16.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Sloth path")).SetDefaultValue("\"\"");
obj.AddCondition("PointInsideSlot",
_("Point inside slot"),
_("Check if the point is inside the slot"),
_("The point _PARAM2_;_PARAM3_ is inside _PARAM0_:_PARAM1_"),
_("Collision"),
"res/conditions/collisionPoint24.png",
"res/conditions/collisionPoint.png")
.AddParameter("object", _("Object"), "Skeleton")
.AddParameter("string", _("Sloth path")).SetDefaultValue("\"\"")
.AddParameter("expression", _("Point X"))
.AddParameter("expression", _("Point Y"));
// Extension instructions
extension.AddCondition("SlotCollidesWithObject",
_("Slot collides with object"),
_("Check if the slot collides with an object"),
_("_PARAM0_:_PARAM1_ collides with _PARAM2_"),
_("Collision"),
"res/conditions/collision24.png",
"res/conditions/collision.png")
.AddParameter("objectList", _("Skeleton"), "Skeleton")
.AddParameter("string", _("Sloth path")).SetDefaultValue("\"\"")
.AddParameter("objectList", _("Object"))
.AddCodeOnlyParameter("conditionInverted", "");
extension.AddCondition("SlotCollidesWithSlot",
_("Slot collides with slot"),
_("Check if the slot collides with another skeleton slot"),
_("_PARAM0_:_PARAM1_ collides with _PARAM2_:_PARAM3_"),
_("Collision"),
"res/conditions/collision24.png",
"res/conditions/collision.png")
.AddParameter("objectList", _("Skeleton"), "Skeleton")
.AddParameter("string", _("Sloth path")).SetDefaultValue("\"\"")
.AddParameter("objectList", _("Other skeleton"), "Skeleton")
.AddParameter("string", _("Sloth path")).SetDefaultValue("\"\"")
.AddCodeOnlyParameter("conditionInverted", "");
extension.AddCondition("RaycastSlot",
_("Raycast slot"),
_("Same as Raycast, but intersects specific slots instead."),
_("Raycast _PARAM0_:_PARAM1_ from _PARAM2_;_PARAM3_"),
_("Collision"),
"res/conditions/collision24.png",
"res/conditions/collision.png")
.AddParameter("objectList", _("Skeleton to test against the ray"), "Skeleton")
.AddParameter("string", _("Sloth path")).SetDefaultValue("\"\"")
.AddParameter("expression", _("Ray source X position"))
.AddParameter("expression", _("Ray source Y position"))
.AddParameter("expression", _("Ray angle (in degrees)"))
.AddParameter("expression", _("Ray maximum distance (in pixels)"))
.AddParameter("scenevar", _("Variable where to store the X position of the intersection"))
.AddParameter("scenevar", _("Variable where to store the Y position of the intersection"))
.AddCodeOnlyParameter("conditionInverted", "")
.MarkAsAdvanced();
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,451 @@
/**
GDevelop - Skeleton Object Extension
Copyright (c) 2017-2018 Franco Maciel (francomaciel10@gmail.com)
This project is released under the MIT License.
*/
/**
* The SkeletonRuntimeObject imports and displays skeletal animations files.
*
* @namespace gdjs
* @class SkeletonRuntimeObject
* @extends RuntimeObject
*/
gdjs.SkeletonRuntimeObject = function(runtimeScene, objectData){
gdjs.RuntimeObject.call(this, runtimeScene, objectData);
this.rootArmature = new gdjs.sk.Armature(this);
this.rootArmature.getRenderer().putInScene(this, runtimeScene);
this.rootArmature.setAsRoot();
this.animationPlaying = true;
this.animationSmooth = true;
this.timeScale = 1.0;
this.scaleX = 1.0;
this.scaleY = 1.0;
this.hitboxSlot = null;
this.manager = gdjs.SkeletonObjectsManager.getManager(runtimeScene);
this.getSkeletonData(runtimeScene, objectData);
};
gdjs.SkeletonRuntimeObject.prototype = Object.create(gdjs.RuntimeObject.prototype);
gdjs.SkeletonRuntimeObject.thisIsARuntimeObjectConstructor = "SkeletonObject::Skeleton";
gdjs.SkeletonRuntimeObject.prototype.extraInitializationFromInitialInstance = function(initialInstanceData) {
if(initialInstanceData.customSize){
this.setWidth(initialInstanceData.width);
this.setHeight(initialInstanceData.height);
}
};
gdjs.SkeletonRuntimeObject.prototype.getSkeletonData = function(runtimeScene, objectData){
var skeletonData = this.manager.getSkeleton(runtimeScene, this.name, objectData);
if(skeletonData.armatures.length > 0){
this.rootArmature.loadData(skeletonData.armatures[skeletonData.rootArmature],
skeletonData,
objectData.debugPolygons);
this.rootArmature.resetState();
}
};
// RuntimeObject overwrites
gdjs.SkeletonRuntimeObject.prototype.setX = function(x){
this.x = x;
this.rootArmature.setX(x);
};
gdjs.SkeletonRuntimeObject.prototype.setY = function(y){
this.y = y;
this.rootArmature.setY(y);
};
gdjs.SkeletonRuntimeObject.prototype.setAngle = function(angle){
this.angle = angle;
this.rootArmature.setRot(angle);
};
gdjs.SkeletonRuntimeObject.prototype.getRendererObject = function(){
return this.rootArmature.getRendererObject();
};
gdjs.SkeletonRuntimeObject.prototype.getHitBoxes = function(){
if(this.hitboxSlot){
return this.hitboxSlot.getPolygons();
}
return [this.rootArmature.getAABB()];
};
gdjs.SkeletonRuntimeObject.prototype.stepBehaviorsPreEvents = function(runtimeScene){
var delta = this.getElapsedTime(runtimeScene) / 1000.0;
if(this.animationPlaying){
this.rootArmature.updateAnimation(delta*this.timeScale);
}
gdjs.RuntimeObject.prototype.stepBehaviorsPreEvents.call(this, runtimeScene);
};
gdjs.SkeletonRuntimeObject.prototype.update = function(runtimeScene){
this.rootArmature.update();
};
gdjs.SkeletonRuntimeObject.prototype.getDrawableX = function(){
return this.getX() - this.rootArmature.shared.aabb[0][0] * Math.abs(this.scaleX);
};
gdjs.SkeletonRuntimeObject.prototype.getDrawableY = function(){
return this.getY() - this.rootArmature.shared.aabb[0][1] * Math.abs(this.scaleY);
};
// Object instructions
gdjs.SkeletonRuntimeObject.prototype.getScaleX = function(){
return this.scaleX;
};
gdjs.SkeletonRuntimeObject.prototype.setScaleX = function(scaleX){
this.scaleX = scaleX;
this.rootArmature.setSx(scaleX);
};
gdjs.SkeletonRuntimeObject.prototype.getScaleY = function(){
return this.scaleY;
};
gdjs.SkeletonRuntimeObject.prototype.setScaleY = function(scaleY){
this.scaleY = scaleY;
this.rootArmature.setSy(scaleY);
};
gdjs.SkeletonRuntimeObject.prototype.getWidth = function(){
return this.rootArmature.getDefaultWidth() * Math.abs(this.scaleX);
};
gdjs.SkeletonRuntimeObject.prototype.setWidth = function(width){
if(width < 0) width = 0;
this.setScaleX(width / this.rootArmature.getDefaultWidth());
};
gdjs.SkeletonRuntimeObject.prototype.getHeight = function(){
return this.rootArmature.getDefaultHeight() * Math.abs(this.scaleY);
};
gdjs.SkeletonRuntimeObject.prototype.setHeight = function(height){
if(height < 0) height = 0;
this.setScaleY(height / this.rootArmature.getDefaultHeight());
};
gdjs.SkeletonRuntimeObject.prototype.setDefaultHitbox = function(slotPath){
if(slotPath === ""){
this.hitboxSlot = null;
return;
}
var slot = this.getSlot(slotPath);
if(slot){
this.hitboxSlot = slot;
}
};
// Animation instructions
gdjs.SkeletonRuntimeObject.prototype.isAnimationPaused = function(){
return !this.animationPlaying;
};
gdjs.SkeletonRuntimeObject.prototype.setAnimationPaused = function(paused){
this.animationPlaying = !paused;
};
gdjs.SkeletonRuntimeObject.prototype.isAnimationFinished = function(){
return this.rootArmature.isAnimationFinished();
};
gdjs.SkeletonRuntimeObject.prototype.getAnimationTime = function(){
return this.rootArmature.getAnimationTime();
};
gdjs.SkeletonRuntimeObject.prototype.setAnimationTime = function(time){
this.rootArmature.setAnimationTime(time);
};
gdjs.SkeletonRuntimeObject.prototype.getAnimationTimeLength = function(){
return this.rootArmature.getAnimationTimeLength();
};
gdjs.SkeletonRuntimeObject.prototype.getAnimationFrame = function(){
return this.rootArmature.getAnimationFrame();
};
gdjs.SkeletonRuntimeObject.prototype.setAnimationFrame = function(frame){
this.rootArmature.setAnimationFrame(frame);
};
gdjs.SkeletonRuntimeObject.prototype.getAnimationFrameLength = function(){
return this.rootArmature.getAnimationFrameLength();
};
gdjs.SkeletonRuntimeObject.prototype.getAnimationIndex = function(){
return this.rootArmature.getAnimationIndex();
};
gdjs.SkeletonRuntimeObject.prototype.setAnimationIndex = function(newAnimation, blendTime=0, loops=-1){
this.rootArmature.setAnimationIndex(newAnimation, blendTime, loops);
};
gdjs.SkeletonRuntimeObject.prototype.getAnimationName = function(){
return this.rootArmature.getAnimationName();
};
gdjs.SkeletonRuntimeObject.prototype.setAnimationName = function(newAnimation, blendTime=0, loops=-1){
this.rootArmature.setAnimationName(newAnimation, blendTime, loops);
};
gdjs.SkeletonRuntimeObject.prototype.isAnimationSmooth = function(){
return this.animationSmooth;
};
gdjs.SkeletonRuntimeObject.prototype.setAnimationSmooth = function(smooth){
this.animationSmooth = smooth;
};
gdjs.SkeletonRuntimeObject.prototype.getAnimationTimeScale = function(){
return this.timeScale;
};
gdjs.SkeletonRuntimeObject.prototype.setAnimationTimeScale = function(timeScale){
if(timeScale < 0) timeScale = 0; // Support negative timeScale (backward animation) ?
this.timeScale = timeScale;
};
gdjs.SkeletonRuntimeObject.prototype.resetAnimation = function(){
this.rootArmature.resetAnimation();
};
// Bone instructions
gdjs.SkeletonRuntimeObject.prototype.getBoneX = function(bonePath){
var bone = this.getBone(bonePath);
return bone ? bone.getGlobalX() : 0;
};
gdjs.SkeletonRuntimeObject.prototype.setBoneX = function(bonePath, x){
var bone = this.getBone(bonePath);
if(bone){
bone.setGlobalX(x);
bone.update();
}
};
gdjs.SkeletonRuntimeObject.prototype.getBoneY = function(bonePath){
var bone = this.getBone(bonePath);
return bone ? bone.getGlobalY() : 0;
};
gdjs.SkeletonRuntimeObject.prototype.setBoneY = function(bonePath, y){
var bone = this.getBone(bonePath);
if(bone){
bone.setGlobalY(y);
bone.update();
}
};
gdjs.SkeletonRuntimeObject.prototype.getBoneAngle = function(bonePath){
var bone = this.getBone(bonePath);
return bone ? bone.getGlobalRot() : 0;
};
gdjs.SkeletonRuntimeObject.prototype.setBoneAngle = function(bonePath, angle){
var bone = this.getBone(bonePath);
if(bone){
bone.setGlobalRot(angle);
bone.update();
}
};
gdjs.SkeletonRuntimeObject.prototype.getBoneScaleX = function(bonePath){
var bone = this.getBone(bonePath);
return bone ? bone.getSx() : 0;
};
gdjs.SkeletonRuntimeObject.prototype.setBoneScaleX = function(bonePath, scaleX){
var bone = this.getBone(bonePath);
if(bone){
bone.setSx(scaleX);
bone.update();
}
};
gdjs.SkeletonRuntimeObject.prototype.getBoneScaleY = function(bonePath){
var bone = this.getBone(bonePath);
return bone ? bone.getSy() : 0;
};
gdjs.SkeletonRuntimeObject.prototype.setBoneScaleY = function(bonePath, scaleY){
var bone = this.getBone(bonePath);
if(bone){
bone.setSy(scaleY);
bone.update();
}
};
gdjs.SkeletonRuntimeObject.prototype.resetBone = function(bonePath){
var bone = this.getBone(bonePath);
if(bone){
bone.resetState();
}
};
// Slot instructions
gdjs.SkeletonRuntimeObject.prototype.setSlotColor = function(slotPath, color){
var slot = this.getSlot(slotPath);
if(slot){
var rgb = color.split(";");
if(rgb.length < 3) return;
slot.setColor(...rgb);
}
};
gdjs.SkeletonRuntimeObject.prototype.isSlotVisible = function(slotPath){
var slot = this.getSlot(slotPath);
return slot ? slot.getVisible() : false;
};
gdjs.SkeletonRuntimeObject.prototype.setSlotVisible = function(slotPath, visible){
var slot = this.getSlot(slotPath);
if(slot){
slot.setVisible(visible);
}
};
gdjs.SkeletonRuntimeObject.prototype.getSlotZOrder = function(slotPath){
var slot = this.getSlot(slotPath);
return slot ? slot.getZ() : 0;
};
gdjs.SkeletonRuntimeObject.prototype.setSlotZOrder = function(slotPath, z){
var slot = this.getSlot(slotPath);
if(slot){
slot.setZ(z);
}
};
gdjs.SkeletonRuntimeObject.prototype.isPointInsideSlot = function(slotPath, x, y){
var hitBoxes = this.getPolygons(slotPath);
if(!hitBoxes) return false;
for(var i = 0; i < this.hitBoxes.length; ++i) {
if ( gdjs.Polygon.isPointInside(hitBoxes[i], x, y) )
return true;
}
return false;
};
// Extension instructions
gdjs.SkeletonRuntimeObject.prototype.raycastSlot = function(slotPath, x, y, angle, dist, closest){
var result = gdjs.Polygon.raycastTest._statics.result;
result.collision = false;
var endX = x + dist*Math.cos(angle*Math.PI/180.0);
var endY = y + dist*Math.sin(angle*Math.PI/180.0);
var testSqDist = closest ? dist*dist : 0;
var hitBoxes = this.getPolygons(slotPath);
if(!hitBoxes) return result;
for(var i=0; i<hitBoxes.length; i++){
var res = gdjs.Polygon.raycastTest(hitBoxes[i], x, y, endX, endY);
if ( res.collision ) {
if ( closest && (res.closeSqDist < testSqDist) ) {
testSqDist = res.closeSqDist;
result = res;
}
else if ( !closest && (res.farSqDist > testSqDist) && (res.farSqDist <= dist*dist) ) {
testSqDist = res.farSqDist;
result = res;
}
}
}
return result;
};
// Warning!, assuming gdjs.evtTools.object.twoListsTest calls the predicate
// respecting the given objects lists paramenters order
gdjs.SkeletonRuntimeObject.slotObjectCollisionTest = function(skl, obj, slotPath){
var hitBoxes1 = skl.getPolygons(slotPath);
if(!hitBoxes1) return false;
var hitBoxes2 = obj.getHitBoxes();
for(var k=0, lenBoxes1=hitBoxes1.length; k<lenBoxes1; ++k){
for(var l=0, lenBoxes2=hitBoxes2.length; l<lenBoxes2; ++l){
if (gdjs.Polygon.collisionTest(hitBoxes1[k], hitBoxes2[l]).collision){
return true;
}
}
}
return false;
};
gdjs.SkeletonRuntimeObject.slotSlotCollisionTest = function(skl1, skl2, slotPaths){
var hitBoxes1 = skl1.getPolygons(slotPaths[0]);
var hitBoxes2 = skl2.getPolygons(slotPaths[1]);
if(!hitBoxes1 || !hitBoxes2) return false;
for(var k=0, lenBoxes1=hitBoxes1.length; k<lenBoxes1; ++k){
for(var l=0, lenBoxes2=hitBoxes2.length; l<lenBoxes2; ++l){
if (gdjs.Polygon.collisionTest(hitBoxes1[k], hitBoxes2[l]).collision){
return true;
}
}
}
return false;
};
// Helpers
gdjs.SkeletonRuntimeObject.prototype.getSlot = function(slotPath){
var slotArray = slotPath.split("/");
var currentSlot = null;
if(slotArray[0] in this.rootArmature.slotsMap){
currentSlot = this.rootArmature.slotsMap[slotArray[0]];
for(var i=1; i<slotArray.length; i++){
if(currentSlot.type === gdjs.sk.SLOT_ARMATURE &&
slotArray[i] in currentSlot.childArmature.slotsMap){
currentSlot = currentSlot.childArmature.slotsMap[slotArray[i]];
}
else{
return null
}
}
}
return currentSlot;
};
gdjs.SkeletonRuntimeObject.prototype.getBone = function(bonePath){
var slotArray = bonePath.split("/");
var boneName = slotArray.pop();
if(slotArray.length === 0 && boneName in this.rootArmature.bonesMap){
return this.rootArmature.bonesMap[boneName];
}
var slot = this.getSlot(slotArray.join("/"));
if(slot && slot.type === gdjs.sk.SLOT_ARMATURE && boneName in slot.childArmature.bonesMap){
return slot.childArmature.bonesMap[boneName];
}
return null;
};
gdjs.SkeletonRuntimeObject.prototype.getPolygons = function(slotPath){
if(slotPath === ""){
return this.rootArmature.getHitBoxes();
}
var slot = this.getSlot(slotPath);
if(slot){
return slot.getPolygons();
}
return null;
};

View File

@@ -0,0 +1,53 @@
/**
GDevelop - Skeleton Object Extension
Copyright (c) 2017-2018 Franco Maciel (francomaciel10@gmail.com)
This project is released under the MIT License.
*/
gdjs.SkeletonObjectsManager = function(){
// List of loaded skeletons per object type
this.loadedObjects = {};
};
gdjs.SkeletonObjectsManager.getManager = function(runtimeScene){
if( !runtimeScene.skeletonObjectsManager ){
runtimeScene.skeletonObjectsManager = new gdjs.SkeletonObjectsManager();
}
return runtimeScene.skeletonObjectsManager;
};
gdjs.SkeletonObjectsManager.prototype.getSkeleton = function(runtimeScene, objectName, objectData){
if( !(objectName in this.loadedObjects) ){
this.loadedObjects[objectName] = this.loadSkeleton(runtimeScene, objectData);
}
return this.loadedObjects[objectName];
};
gdjs.SkeletonObjectsManager.prototype.loadSkeleton = function(runtimeScene, objectData){
var loader = new gdjs.sk.DataLoader();
var skeletalData = loader.getData(objectData.skeletalDataFilename);
var skeleton = {"loader": loader,
"armatures": [],
"rootArmature": 0};
if(!skeletalData) return skeleton;
if(objectData.apiName === "DragonBones"){
// Load sub-textures
loader.loadDragonBones(runtimeScene, objectData);
// Load the root armature with the given name
for(var i=0; i<skeletalData.armature.length; i++){
var armature = new gdjs.sk.SharedArmature();
armature.loadDragonBones(skeletalData.armature[i]);
skeleton.armatures.push(armature);
if(armature.name === objectData.rootArmatureName){
skeleton.rootArmature = i;
}
}
}
return skeleton;
};

View File

@@ -0,0 +1,57 @@
/**
GDevelop - Skeleton Object Extension
Copyright (c) 2017-2018 Franco Maciel (francomaciel10@gmail.com)
This project is released under the MIT License.
*/
gdjs.sk.slotObjectCollision = function(objectsLists1, slotPath, objectsLists2, inverted){
return gdjs.evtTools.object.twoListsTest(gdjs.SkeletonRuntimeObject.slotObjectCollisionTest,
objectsLists1, objectsLists2, inverted, slotPath);
};
gdjs.sk.slotSlotCollision = function(objectsLists1, slotPath1, objectsLists2, slotPath2, inverted){
return gdjs.evtTools.object.twoListsTest(gdjs.SkeletonRuntimeObject.slotSlotCollisionTest,
objectsLists1, objectsLists2, inverted, [slotPath1, slotPath2]);
};
gdjs.sk.raycastSlot = function(objectsLists, slotPath, x, y, angle, dist, varX, varY, inverted){
var matchObject = null;
var testSqDist = inverted ? 0 : dist*dist;
var resultX = 0;
var resultY = 0;
var lists = gdjs.staticArray(gdjs.sk.raycastSlot);
objectsLists.values(lists);
for (var i = 0; i < lists.length; i++) {
var list = lists[i];
for (var j = 0; j < list.length; j++) {
var object = list[j];
var result = object.raycastSlot(slotPath, x, y, angle, dist, !inverted);
if( result.collision ) {
if ( !inverted && (result.closeSqDist <= testSqDist) ) {
testSqDist = result.closeSqDist;
matchObject = object;
resultX = result.closeX;
resultY = result.closeY;
}
else if ( inverted && (result.farSqDist >= testSqDist) ) {
testSqDist = result.farSqDist;
matchObject = object;
resultX = result.farX;
resultY = result.farY;
}
}
}
}
if ( !matchObject )
return false;
gdjs.evtTools.object.pickOnly(objectsLists, matchObject);
varX.setNumber(resultX);
varY.setNumber(resultY);
return true;
};

View File

@@ -0,0 +1,159 @@
/**
GDevelop - Skeleton Object Extension
Copyright (c) 2017-2018 Franco Maciel (francomaciel10@gmail.com)
This project is released under the MIT License.
*/
#if defined(GD_IDE_ONLY)
#include "GDCore/Extensions/PlatformExtension.h"
#include "SkeletonObject.h"
#include <iostream>
void DeclareSkeletonObjectExtension(gd::PlatformExtension & extension);
/**
* \brief This class declares information about the JS extension.
*/
class SkeletonObjectJsExtension : public gd::PlatformExtension
{
public:
/**
* Constructor of an extension declares everything the extension contains: objects, actions, conditions and expressions.
*/
SkeletonObjectJsExtension()
{
DeclareSkeletonObjectExtension(*this);
GetObjectMetadata("SkeletonObject::Skeleton")
.SetIncludeFile("Extensions/SkeletonObject/Isk-tools.js")
.AddIncludeFile("Extensions/SkeletonObject/Hskmanager.js")
.AddIncludeFile("Extensions/SkeletonObject/Gskeletonruntimeobject.js")
.AddIncludeFile("Extensions/SkeletonObject/Fskanimation.js")
.AddIncludeFile("Extensions/SkeletonObject/Eskarmature.js")
.AddIncludeFile("Extensions/SkeletonObject/Dskslot.js")
.AddIncludeFile("Extensions/SkeletonObject/Cskbone.js")
.AddIncludeFile("Extensions/SkeletonObject/Bskeletonruntimeobject-cocos-renderer.js")
.AddIncludeFile("Extensions/SkeletonObject/Bskeletonruntimeobject-pixi-renderer.js")
.AddIncludeFile("Extensions/SkeletonObject/Ask.js");
auto & actions = GetAllActionsForObject("SkeletonObject::Skeleton");
auto & conditions = GetAllConditionsForObject("SkeletonObject::Skeleton");
auto & expressions = GetAllExpressionsForObject("SkeletonObject::Skeleton");
auto & strExpressions = GetAllStrExpressionsForObject("SkeletonObject::Skeleton");
// Object instructions
conditions["SkeletonObject::ScaleX"].SetFunctionName("getScaleX");
actions["SkeletonObject::SetScaleX"].SetFunctionName("setScaleX").SetGetter("getScaleX");
expressions["ScaleX"].SetFunctionName("getScaleX");
conditions["SkeletonObject::ScaleY"].SetFunctionName("getScaleY");
actions["SkeletonObject::SetScaleY"].SetFunctionName("setScaleY").SetGetter("getScaleY");
expressions["ScaleY"].SetFunctionName("getScaleY");
conditions["SkeletonObject::Width"].SetFunctionName("getWidth");
actions["SkeletonObject::SetWidth"].SetFunctionName("setWidth").SetGetter("getWidth");
expressions["Width"].SetFunctionName("getWidth");
conditions["SkeletonObject::Height"].SetFunctionName("getHeight");
actions["SkeletonObject::SetHeight"].SetFunctionName("setHeight").SetGetter("getHeight");
expressions["Height"].SetFunctionName("getHeight");
actions["SkeletonObject::SetDefaultHitbox"].SetFunctionName("setDefaultHitbox");
// Animation instructions
conditions["SkeletonObject::AnimationPaused"].SetFunctionName("isAnimationPaused");
actions["SkeletonObject::PauseAnimation"].SetFunctionName("setAnimationPaused");
actions["SkeletonObject::UnpauseAnimation"].SetFunctionName("setAnimationPaused");
conditions["SkeletonObject::AnimationFinished"].SetFunctionName("isAnimationFinished");
conditions["SkeletonObject::AnimationTime"].SetFunctionName("getAnimationTime");
actions["SkeletonObject::SetAnimationTime"].SetFunctionName("setAnimationTime").SetGetter("getAnimationTime");
expressions["AnimationTime"].SetFunctionName("getAnimationTime");
expressions["AnimationTimeLength"].SetFunctionName("getAnimationTimeLength");
conditions["SkeletonObject::AnimationFrame"].SetFunctionName("getAnimationFrame");
actions["SkeletonObject::SetAnimationFrame"].SetFunctionName("setAnimationFrame").SetGetter("getAnimationFrame");
expressions["AnimationFrame"].SetFunctionName("getAnimationFrame");
expressions["AnimationFrameLength"].SetFunctionName("getAnimationFrameLength");
conditions["SkeletonObject::AnimationIndex"].SetFunctionName("getAnimationIndex");
actions["SkeletonObject::SetAnimationIndex"].SetFunctionName("setAnimationIndex").SetGetter("getAnimationIndex");
expressions["AnimationIndex"].SetFunctionName("getAnimationIndex");
conditions["SkeletonObject::AnimationName"].SetFunctionName("getAnimationName");
actions["SkeletonObject::SetAnimationName"].SetFunctionName("setAnimationName").SetGetter("getAnimationName");
strExpressions["AnimationName"].SetFunctionName("getAnimationName");
conditions["SkeletonObject::AnimationSmooth"].SetFunctionName("isAnimationSmooth");
actions["SkeletonObject::SetAnimationSmooth"].SetFunctionName("setAnimationSmooth");
conditions["SkeletonObject::AnimationTimeScale"].SetFunctionName("getAnimationTimeScale");
actions["SkeletonObject::SetAnimationTimeScale"].SetFunctionName("setAnimationTimeScale").SetGetter("getAnimationTimeScale");
expressions["AnimationTimeScale"].SetFunctionName("getAnimationTimeScale");
actions["SkeletonObject::ResetAnimation"].SetFunctionName("resetAnimation");
// Bone instructions
conditions["SkeletonObject::BonePositionX"].SetFunctionName("getBoneX");
actions["SkeletonObject::SetBonePositionX"].SetFunctionName("setBoneX").SetGetter("getBoneX");
expressions["BonePositionX"].SetFunctionName("getBoneX");
conditions["SkeletonObject::BonePositionY"].SetFunctionName("getBoneY");
actions["SkeletonObject::SetBonePositionY"].SetFunctionName("setBoneY").SetGetter("getBoneY");
expressions["BonePositionY"].SetFunctionName("getBoneY");
conditions["SkeletonObject::BoneAngle"].SetFunctionName("getBoneAngle");
actions["SkeletonObject::SetBoneAngle"].SetFunctionName("setBoneAngle").SetGetter("getBoneAngle");
expressions["BoneAngle"].SetFunctionName("getBoneAngle");
conditions["SkeletonObject::BoneScaleX"].SetFunctionName("getBoneScaleX");
actions["SkeletonObject::SetBoneScaleX"].SetFunctionName("setBoneScaleX").SetGetter("getBoneScaleX");
expressions["BoneScaleX"].SetFunctionName("getBoneScaleX");
conditions["SkeletonObject::BoneScaleY"].SetFunctionName("getBoneScaleY");
actions["SkeletonObject::SetBoneScaleY"].SetFunctionName("setBoneScaleY").SetGetter("getBoneScaleY");
expressions["BoneScaleY"].SetFunctionName("getBoneScaleY");
actions["SkeletonObject::ResetBone"].SetFunctionName("resetBone");
// Slot instructions
actions["SkeletonObject::SetSlotColor"].SetFunctionName("setSlotColor");
conditions["SkeletonObject::SlotVisible"].SetFunctionName("isSlotVisible");
actions["SkeletonObject::ShowSlot"].SetFunctionName("setSlotVisible");
actions["SkeletonObject::HideSlot"].SetFunctionName("setSlotVisible");
conditions["SkeletonObject::SlotZOrder"].SetFunctionName("getSlotZOrder");
actions["SkeletonObject::SetSlotZOrder"].SetFunctionName("setSlotZOrder").SetGetter("getSlotZOrder");
expressions["SlotZOrder"].SetFunctionName("getSlotZOrder");
conditions["SkeletonObject::PointInsideSlot"].SetFunctionName("isPointInsideSlot");
// Extension instructions
GetAllConditions()["SkeletonObject::SlotCollidesWithObject"].SetFunctionName("gdjs.sk.slotObjectCollision");
GetAllConditions()["SkeletonObject::SlotCollidesWithSlot"].SetFunctionName("gdjs.sk.slotSlotCollision");
GetAllConditions()["SkeletonObject::RaycastSlot"].SetFunctionName("gdjs.sk.raycastSlot");
GD_COMPLETE_EXTENSION_COMPILATION_INFORMATION();
};
};
#if defined(EMSCRIPTEN)
extern "C" gd::PlatformExtension * CreateGDJSSkeletonObjectExtension() {
return new SkeletonObjectJsExtension;
}
#else
/**
* Used by GDevelop to create the extension class
* -- Do not need to be modified. --
*/
extern "C" gd::PlatformExtension * GD_EXTENSION_API CreateGDJSExtension() {
return new SkeletonObjectJsExtension;
}
#endif
#endif

View File

@@ -0,0 +1,151 @@
/**
GDevelop - Skeleton Object Extension
Copyright (c) 2017-2018 Franco Maciel (francomaciel10@gmail.com)
This project is released under the MIT License.
*/
#include <SFML/Graphics.hpp>
#include "GDCpp/Runtime/Project/Project.h"
#include "GDCpp/Runtime/Project/Object.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/IDE/Dialogs/PropertyDescriptor.h"
#include "GDCpp/Runtime/ImageManager.h"
#include "GDCpp/Runtime/Serialization/SerializerElement.h"
#include "GDCpp/Runtime/Serialization/Serializer.h"
#include "GDCpp/Runtime/Project/InitialInstance.h"
#include "GDCpp/Runtime/CommonTools.h"
#include "SkeletonObject.h"
#include "GDCore/String.h"
#include "GDCpp/Runtime/ResourcesLoader.h"
#include <iostream>
#if defined(GD_IDE_ONLY)
#if !defined(GD_NO_WX_GUI)
#include <wx/bitmap.h>
#include <wx/filename.h>
#endif
sf::Texture SkeletonObject::edittimeIconImage;
sf::Sprite SkeletonObject::edittimeIcon;
#endif
SkeletonObject::SkeletonObject(gd::String name_) :
Object(name_)
{
#if defined(GD_IDE_ONLY)
originalSize = sf::Vector2f(32.0f, 32.0f),
originOffset = sf::Vector2f(16.0f, 16.0f),
sizeDirty = true;
#endif
}
void SkeletonObject::DoUnserializeFrom(gd::Project & project, const gd::SerializerElement & element)
{
skeletalDataFilename = element.GetStringAttribute("skeletalDataFilename");
rootArmatureName = element.GetStringAttribute("rootArmatureName");
textureDataFilename = element.GetStringAttribute("textureDataFilename");
textureName = element.GetStringAttribute("textureName");
apiName = element.GetStringAttribute("apiName");
debugPolygons = element.GetBoolAttribute("debugPolygons", false);
}
#if defined(GD_IDE_ONLY)
void SkeletonObject::DoSerializeTo(gd::SerializerElement & element) const
{
element.SetAttribute("skeletalDataFilename", skeletalDataFilename);
element.SetAttribute("rootArmatureName", rootArmatureName);
element.SetAttribute("textureDataFilename", textureDataFilename);
element.SetAttribute("textureName", textureName);
element.SetAttribute("apiName", apiName);
element.SetAttribute("debugPolygons", debugPolygons);
}
std::map<gd::String, gd::PropertyDescriptor> SkeletonObject::GetProperties(gd::Project & project) const
{
std::map<gd::String, gd::PropertyDescriptor> properties;
properties[_("Skeletal data filename")].SetValue(skeletalDataFilename);
properties[_("Main armature name")].SetValue(rootArmatureName);
properties[_("Texture data filename")].SetValue(textureDataFilename);
properties[_("Texture")].SetValue(textureName);
properties[_("API")]
.SetValue(apiName)
.SetType("Choice")
.AddExtraInfo("DragonBones");
properties[_("Debug Polygons")].SetValue(debugPolygons ? "true" : "false").SetType("Boolean");
return properties;
}
bool SkeletonObject::UpdateProperty(const gd::String & name, const gd::String & value, gd::Project & project)
{
if (name == _("Skeletal data filename")) {
skeletalDataFilename = value;
sizeDirty = true;
}
if (name == _("Main armature name")) {
rootArmatureName = value;
sizeDirty = true;
}
if (name == _("Texture data filename")) textureDataFilename = value;
if (name == _("Texture")) textureName = value;
if (name == _("API")) apiName = value;
if (name == _("Debug Polygons")) debugPolygons = value == "1";
return true;
}
void SkeletonObject::LoadEdittimeIcon()
{
edittimeIconImage.loadFromFile("JsPlatform/Extensions/skeletonicon.png");
edittimeIcon.setTexture(edittimeIconImage);
}
#if !defined(GD_NO_WX_GUI)
bool SkeletonObject::GenerateThumbnail(const gd::Project & project, wxBitmap & thumbnail) const
{
thumbnail = wxBitmap("JsPlatform/Extensions/skeletonicon24.png", wxBITMAP_TYPE_ANY);
return true;
}
#endif
void SkeletonObject::DrawInitialInstance(gd::InitialInstance & instance, sf::RenderTarget & renderTarget, gd::Project & project, gd::Layout & layout)
{
#if !defined(GD_NO_WX_GUI)
if(sizeDirty) UpdateSize(project);
#endif
edittimeIcon.setPosition(instance.GetX() - originalSize.x/2.0f, instance.GetY() - originalSize.y/2.0f);
renderTarget.draw(edittimeIcon);
}
sf::Vector2f SkeletonObject::GetInitialInstanceOrigin(gd::InitialInstance & instance, gd::Project & project, gd::Layout & layout) const
{
return originOffset;
}
#if !defined(GD_NO_WX_GUI)
void SkeletonObject::UpdateSize(gd::Project & project)
{
sizeDirty = false;
// Force the path as relative
wxString projectDir = wxFileName::FileName(project.GetProjectFile()).GetPath();
wxFileName fileName(skeletalDataFilename.ToWxString());
fileName.SetPath(projectDir);
// Can't unserialize from JSON's with empty arrays/objects ?
// gd::String fileContent = gd::ResourcesLoader::Get()->LoadPlainText(gd::String::FromWxString(fileName.GetFullPath()));
// gd::SerializerElement element = gd::Serializer::FromJSON(fileContent);
}
#endif
#endif
gd::Object * CreateSkeletonObject(gd::String name)
{
return new SkeletonObject(name);
}

View File

@@ -0,0 +1,68 @@
/**
GDevelop - Skeleton Object Extension
Copyright (c) 2017-2018 Franco Maciel (francomaciel10@gmail.com)
This project is released under the MIT License.
*/
#ifndef SKELETONOBJECT_H
#define SKELETONOBJECT_H
#include "GDCpp/Runtime/Project/Object.h"
#include "GDCpp/Runtime/String.h"
namespace gd { class InitialInstance; }
namespace gd { class Project; }
namespace sf { class Texture; }
namespace sf { class Sprite; }
class wxBitmap;
class GD_EXTENSION_API SkeletonObject : public gd::Object
{
public:
SkeletonObject(gd::String name_);
virtual ~SkeletonObject() {};
virtual std::unique_ptr<gd::Object> Clone() const { return gd::make_unique<SkeletonObject>(*this); }
#if defined(GD_IDE_ONLY)
static void LoadEdittimeIcon();
#if !defined(GD_NO_WX_GUI)
bool GenerateThumbnail(const gd::Project & project, wxBitmap & thumbnail) const override;
#endif
void DrawInitialInstance(gd::InitialInstance & instance, sf::RenderTarget & renderTarget, gd::Project & project, gd::Layout & layout) override;
sf::Vector2f GetInitialInstanceOrigin(gd::InitialInstance & instance, gd::Project & project, gd::Layout & layout) const override;
#if !defined(GD_NO_WX_GUI)
void UpdateSize(gd::Project & project);
#endif
std::map<gd::String, gd::PropertyDescriptor> GetProperties(gd::Project & project) const override;
bool UpdateProperty(const gd::String & name, const gd::String & value, gd::Project & project) override;
#endif
private:
void DoUnserializeFrom(gd::Project & project, const gd::SerializerElement & element) override;
#if defined(GD_IDE_ONLY)
void DoSerializeTo(gd::SerializerElement & element) const override;
#endif
gd::String skeletalDataFilename;
gd::String rootArmatureName;
gd::String textureDataFilename;
gd::String textureName;
gd::String apiName;
bool debugPolygons;
#if defined(GD_IDE_ONLY)
static sf::Texture edittimeIconImage;
static sf::Sprite edittimeIcon;
sf::Vector2f originalSize;
sf::Vector2f originOffset;
bool sizeDirty;
#endif
};
gd::Object * CreateSkeletonObject(gd::String name);
#endif // SKELETONOBJECT_H