Quote: "Will this be making its way into your awesome scene editor?"
If I ever finish it yes, why not! I might add a little character editor to make it easier to assign images to bones too. Would be pretty easy to add!
Here's the code (minus ragdolls for now):
/// Include in your project as shown in example at bottom (#include "baxskeleton.agc")
// Project: bax-skeleton by Steven Holding
/// REGION - public functions
// Create an instance of the skeleton
function CreateBaxSkeleton(scale#)
skel as baxSkelType
skel.skeleton = LoadSkeleton2DFromSpineFile("bax.json", scale#, 0, 1)
skel.scale = scale#
skel.guid = BaxSkelNewGuid()
skel.shader = -1
skel.ragdoll = false
baxSkel.insert(skel)
endfunction skel.guid
function ConnectList(list as integer[])
if list.length>-1
root = list[0]
SetSpritePhysicsOn(root, 2)
endif
for j=1 to list.length
SetSpritePhysicsOn(list[j], 2)
CreateWeldJoint(root, list[j], GetSpriteXByOffset(root), GetSpriteYByOffset(root), 0)
next
endfunction
// Get all sprites attached to a bone (from bone ID)
function GetBaxSkeletonBoneSprites(i, boneId)
list as integer[]
for j=0 to baxSkel[i].slot.length
if baxSkel[i].slot[j].bone = boneId
list.insert(baxSkel[i].slot[j].sprite)
endif
next
endfunction list
// Delete a skeleton
function DeleteBaxSkeleton(guid$, deleteSprites)
for i=0 to baxSkel.length
if baxSkel[i].guid = guid$
if deleteSprites=true
for j=0 to baxSkel[i].slot.length
DeleteSprite(baxSkel[i].slot[j].sprite)
next
endif
baxSkel.remove(i)
exitfunction
endif
next
endfunction
// Get Skeleton index from GUID
function GetBaxSkeletonIndex(guid$)
for i=0 to baxSkel.length
if baxSkel[i].guid = guid$
exitfunction i
endif
next
endfunction -1
// Set debug on or off for individual skeleton
function DebugBaxSkel(i, onOff)
baxSkel[i].debug = onOff
endfunction
// Update all skeletons
function UpdateBaxSkel(ft#)
for i=0 to baxSkel.length
if baxSkel[i].ragdoll=false
for j=0 to baxSkel[i].slot.length
x# = GetSkeleton2DBoneCurrX(baxSkel[i].skeleton, baxSkel[i].slot[j].bone)
y# = GetSkeleton2DBoneCurrY(baxSkel[i].skeleton, baxSkel[i].slot[j].bone)
SetSpritePositionByOffset(baxSkel[i].slot[j].sprite, x#, y#)
a# = GetSkeleton2DBoneCurrAngle(baxSkel[i].skeleton, baxSkel[i].slot[j].bone)
SetSpriteAngle(baxSkel[i].slot[j].sprite, a# + baxSkel[i].slot[j].angleOffset)
next
if baxSkel[i].debug=true
DrawBone(i, "hips", "", 255, 255, 255)
DrawBone(i, "body", "neck", 255, 255, 255)
DrawBone(i, "neck", "head", 255, 255, 255)
DrawBone(i, "head", "", 255, 255, 255)
DrawBone(i, "leg-upper-back", "leg-lower-back", 255, 255, 255)
DrawBone(i, "leg-lower-back", "foot-back", 255, 255, 255)
DrawBone(i, "foot-back", "", 255, 255, 255)
DrawBone(i, "leg-upper-front", "leg-lower-front", 255, 255, 255)
DrawBone(i, "leg-lower-front", "foot-front", 255, 255, 255)
DrawBone(i, "foot-front", "", 255, 255, 255)
DrawBone(i, "arm-upper-back", "arm-lower-back", 255, 255, 255)
DrawBone(i, "arm-lower-back", "hand-back", 255, 255, 255)
DrawBone(i, "hand-back", "", 255, 255, 255)
DrawBone(i, "arm-upper-front", "arm-lower-front", 255, 255, 255)
DrawBone(i, "arm-lower-front", "hand-front", 255, 255, 255)
DrawBone(i, "hand-front", "", 255, 255, 255)
endif
endif
next
endfunction
// Create a sprite and assign it to a bone
function SetBaxSkelBoneImage(i, boneName$, img, angleOffset as float, offsetX as float, offsetY as float, scale as float, offsetD, replace as integer)
s as baxSkelSlotType
s.image = img
s.offsetX = offsetX
s.offsetY = offsetY
s.angleOffset = angleOffset
s.scale = scale * baxSkel[i].scale
s.bone = GetSkeleton2DBone(baxSkel[i].skeleton, boneName$)
s.sprite = CreateSprite(img)
SetSpriteOffset(s.sprite, offsetX, offsetY)
SetSpriteScale(s.sprite, s.scale, s.scale)
select boneName$
case "arm-upper-back"
offsetD = offsetD
endcase
case "arm-lower-back"
offsetD = offsetD - 1
endcase
case "hand-back"
offsetD = offsetD - 2
endcase
case "leg-upper-back"
offsetD = offsetD - 3
endcase
case "foot-back"
offsetD = offsetD - 4
endcase
case "leg-lower-back"
offsetD = offsetD - 5
endcase
case "body"
offsetD = offsetD - 6
endcase
case "hips"
offsetD = offsetD - 7
endcase
case "neck"
offsetD = offsetD - 8
endcase
case "head"
offsetD = offsetD - 9
endcase
case "leg-upper-front"
offsetD = offsetD - 10
endcase
case "foot-front"
offsetD = offsetD - 11
endcase
case "leg-lower-front"
offsetD = offsetD - 12
endcase
case "arm-upper-front"
offsetD = offsetD - 13
endcase
case "arm-lower-front"
offsetD = offsetD - 14
endcase
case "hand-front"
offsetD = offsetD - 15
endcase
endselect
SetSpriteDepth(s.sprite, baxSkel[i].depth + offsetD)
SetSpriteShape(s.sprite, 3)
found = -1
for j=0 to baxSkel[i].slot.length
if baxSkel[i].slot[j].bone = s.bone
found = j
endif
next
if found>-1
if replace=true
baxSkel[i].slot[j] = s
else
baxSkel[i].slot.insert(s)
endif
else
baxSkel[i].slot.insert(s)
endif
endfunction
// Set general depth of skeleton
// All sprites are in front of this layer
function SetBaxSkeletonDepth(guid$, depth)
baxSkel[GetBaxSkeletonIndex(guid$)].depth = depth
endfunction
// Apply a shader to a skeleton
function SetBaxSkeletonShader(guid$, shader)
i = GetBaxSkeletonIndex(guid$)
baxSkel[i].shader = shader
for j=0 to baxSkel[i].slot.length
SetSpriteShader(baxSkel[i].slot[j].sprite, shader)
next
endfunction
/// REGION - public functions
/// REGION - private functions
// Set up data types and globals
#constant false 0
#constant true 1
type baxSkelType
guid as string
ragdoll as integer
skeleton as integer
depth as integer
scale as float
debug as integer
shader as integer
slot as baxSkelSlotType[]
endtype
type baxSkelSlotType
bone as integer
image as integer
scale as float
sprite as integer
offsetX as float
offsetY as float
angleOffset as float
endtype
global baxSkel as baxSkelType[]
// Draw debug bone
function DrawBone(i, boneName1$, boneName2$, red, green, blue)
col = MakeColor(red, green, blue)
bone1 = GetSkeleton2DBone(baxSkel[i].skeleton, boneName1$)
x# = GetSkeleton2DBoneCurrX(baxSkel[i].skeleton, bone1)
y# = GetSkeleton2DBoneCurrY(baxSkel[i].skeleton, bone1)
DrawBox(x#-3, y#-3, x#+3, y#+3, col, col, col, col, 1)
if boneName2$<>""
bone2 = GetSkeleton2DBone(baxSkel[i].skeleton, boneName2$)
x2# = GetSkeleton2DBoneCurrX(baxSkel[i].skeleton, bone2)
y2# = GetSkeleton2DBoneCurrY(baxSkel[i].skeleton, bone2)
DrawLine(x#, y#, x2#, y2#, col, col)
endif
endfunction
// Create a new unique GUID
function BaxSkelNewGuid()
guid as string
done = 0
while done=0
guid = ""
for i=1 to 16
v = Random(0, 35)
if v<10
v = v + 48
else
v = v + 87
endif
guid = guid + chr(v)
if Mod(i, 4)=0
if len(guid)<19 then guid = guid + "-"
endif
next
if GetBaxSkeletonIndex(guid)=-1
done = 1
endif
endwhile
endfunction guid
/// REGION - private functions
// EXAMPLE
`#include "baxskeleton.agc"
// show all errors
`SetErrorMode(2)
// set window properties
`SetWindowTitle( "bax-skeleton" )
`SetWindowSize( 1024, 768, 0 )
// set display properties
`SetVirtualResolution( 1024, 768 )
`SetOrientationAllowed( 1, 1, 1, 1 )
`SetSyncRate( 60, 0 )
`SetPrintSize(16)
// Create the skeleton
`guid$ = CreateBaxSkeleton(0.75)
// Set up the position and idle animation
`i = GetBaxSkeletonIndex(guid$)
`SetSkeleton2DPosition(baxSkel[i].skeleton, 480, 600)
`PlaySkeleton2DAnimation(baxSkel[i].skeleton, "idle", 0, 1, 0)
// Set up the images
`SetBaxSkeletonDepth(guid$, 2000)
`SetBaxSkelBoneImage(i, "head", LoadImage("head.png"), 0, 70, 237, 0.9, 0, 1)
`SetBaxSkelBoneImage(i, "head", LoadImage("eye_indifferent.png"), 0, -42, 82, 0.9, -1, 0)
`SetBaxSkelBoneImage(i, "head", LoadImage("mouth_grind.png"), 0, -20, 10, 0.9, -1, 0)
`SetBaxSkelBoneImage(i, "neck", LoadImage("neck.png"), -110, 40, 5, 0.75, 0, 1)
`SetBaxSkelBoneImage(i, "body", LoadImage("torso.png"), 90, 50, 160, 0.9, 0, 1)
`SetBaxSkelBoneImage(i, "arm-upper-front", LoadImage("front_upper_arm.png"), 270, 30, 10, 1.3, 0, 1)
`SetBaxSkelBoneImage(i, "arm-lower-front", LoadImage("front_bracer.png"), 280, 30, 25, 1.5, 0, 1)
`SetBaxSkelBoneImage(i, "hand-front", LoadImage("front_fist_closed.png"), 280, 25, 30, 0.9, 0, 1)
`SetBaxSkelBoneImage(i, "arm-upper-back", LoadImage("rear_upper_arm.png"), 270, 20, 10, 1.3, 0, 1)
`SetBaxSkelBoneImage(i, "arm-lower-back", LoadImage("rear_bracer.png"), 290, 20, 10, 1.5, 0, 1)
`SetBaxSkelBoneImage(i, "hand-back", LoadImage("gun.png"), 300, 35, 50, 0.9, 0, 1)
`SetBaxSkelBoneImage(i, "leg-upper-front", LoadImage("front_thigh.png"), 270, 20, 10, 0.9, 0, 1)
`SetBaxSkelBoneImage(i, "leg-lower-front", LoadImage("front_shin.png"), 270, 50, 30, 0.75, 0, 1)
`SetBaxSkelBoneImage(i, "foot-front", LoadImage("rear_foot.png"), 0, 40, 30, 0.75, 0, 1)
`SetBaxSkelBoneImage(i, "leg-upper-back", LoadImage("rear_thigh.png"), 270, 20, 10, 0.9, 0, 1)
`SetBaxSkelBoneImage(i, "leg-lower-back", LoadImage("rear_shin.png"), 270, 50, 30, 0.75, 0, 1)
`SetBaxSkelBoneImage(i, "foot-back", LoadImage("rear_foot.png"), 0, 40, 30, 0.75, 0, 1)
// Load and apply the shader
`shader = LoadSpriteShader("sepia.ps")
`SetBaxSkeletonShader(guid$, shader)
// Show the debug skeleton
`DebugBaxSkel(i, true)
`do
` Print( "fps: "+ str(ScreenFPS(),0) )
`
` if GetPointerPressed()>0
` DeleteBaxSkeleton(guid$, true)
` endif
// Update the 2D world then the skeleton
// for more accurate positioning of images
` ft# = GetFrameTime()
` Update2D(ft#)
` UpdateBaxSkel(ft#)
` Sync()
//loop
///
// EXAMPLE
Example project attached.
NOTE: The skeleton only has one animation at present but now I have the system working I will add more. If anyone else has spine and wants to add some animations please let me know!
Using AppGameKit V2 Tier 1