• Editor
  • how would you use Spine for this?

  • Đã chỉnh sửa
Related Discussions
...

How would you recommend using Spine to cover these aspects, for a horizontal scrolling game?

  • Different characters (e.g. man, boy, girl etc)
  • Different costumes clothes (even just colors of outfits) - maybe assume clothes options/colors are specific to the character
  • Powerups (e.g. backpack, shield, jetpack on back, cape that fly in the wind behind someone)
  • Same animations for them all really

For example would you:

  • draw the main character bones
  • then draw bones of powerups, take cape flying the character as an advanced case, Then
  • Characters: Use Spine "skins" for this
  • Costumes per Character: ??? What would be the best option here. Can I assume red, green, blue shirt for example should be just part of the body image for that character (skin), but then you would need multiple skins for the same character so that wouldn't really work, e.g. you might need a Boy_RedShirt_BlackPants skin for example. So do you do this as attachments & then change programmatically? How do you ensure the shirt alignment with the body is spot on?
  • Power Ups - e.g. Cape Flying behind a character (any character could get a cape) - So do you just create this as part of the character (nothing to do with a skin) and then just programmatically hide/show (haven't check the runtime API how hoping this is possible)? Is there a way to refer to the cape as one item? (i.e. as it may be multiple bones)

So overall I guess my two questions are:
1) how to handle costumes (character specific)
2) how to handle powerups (e.g. cape flying behind) (non character specific)

(I'm on the Corona/Lua runtime, however I'm assuming this is a general non-runtime specific question)


PS. Some additional thoughts re my two questions...

1) how to handle costumes (character specific) - From what I can tell this my not be easy. May be better to try to stick to characters having predefined clothes/clothes colors, then if need be follow the below "power up concept" if required. Comments?

2) how to handle powerups (e.g. cape flying behind) (non character specific) - Seems like would need to use bones. How can one turn on/off however (programmatically) a number of bones & their attachments in one hit? For example say the cape was 5 bones with images on each of them. How could you effectively turn on/off the cape in one hit?

Different characters can be either the same skeleton with different attachments (beneficial since you reuse all animations) or different skeletons (needed when characters are a different size or have a different number of bones).

Different outfits are just attachments. Attach images in Spine, then at runtime you can set any of them to visible. Skins can be used for organization. Skins can be populated and/or combined programmatically if needed. If you have a red shirt that is 3 attachments, you could just attach those at runtime. You could use a skin in Spine to group them, then at runtime create a skin for the player and add attachments from all the skins you want to combine.

Powerups as you described can be attachments. You can show attachments in sequence to achieve sprite animation. You can have bones to animate them, but the bones may do nothing when the item is not equipped. You can use a separate skeleton for each item, but it is not yet possible to preview attaching a skeleton to another skeleton in Spine, and it is more complex at runtime to have an attached skeleton participate in the draw order of the other skeleton (see SkeletonAttachment and SkeletonRenderer in spine-libgdx). It is easy if the attached skeleton can just be drawn on top at a bone location of the other skeleton.

You can edit the runtime to customize things such as not rendering many bones. You could also determine what bones you are using for a give set of items/attachments, and remove all other bones from your skeleton as an optimization.

I think those answer your questions, if not please let me know. 🙂

thanks Nate - how about this specific question I asked that was buried in my last post: "How can one turn on/off however (programmatically) a number of bones & their attachments in one hit? For example say the cape was 5 bones with images on each of them. How could you effectively turn on/off the cape in one hit?"

I guess I am asking is there a way to group these bones or attachments in a way that lets you turn them on/off in one hit? Assuming it would be better to remove/re-attachment whole thing includes bones ideally, as opposed to just changing visibility?

6 ngày sau

See my second to last paragraph. You'll have to remove bones from the skeleton or edit the runtime.

thanks Nate

If I were to go through/understand the lua spine code would there be the functions/associations I need to create a custom function like this:

state:setBoneAndItsChildrenVisibility( boneName, booleanValue )

So the function could get the bone, and then "walk" done/through all children bones, and for each one change the "isVisible" property of the display object associated with the bone. Should this be possible?

Then if my powerup's attachments had their starting/parent bone from the skeleton appropriately named, e.g. shield, jetpack, I could then do this:

player.spineState:setBoneAndItsChildrenVisibility( "shield", false )
player.spineState:setBoneAndItsChildrenVisibility( "jetpack", true )

You can just ignore the bones when unused. Just hide images in slots for those bones. If you need to avoid updating the bone world transforms, that is an optimization you can do later.

thanks Nate - so I think my question is basically this then...

Assuming I have a setup for a "cape" powerup which in Spine is something like this:

- capeBone1
  - capeSlot1
    - capeImage1
  - capeBone2  
    - capeSlot3
      - capeImage2
    - capeBone3
      - capeSlot3
         - capeImage3

So I could just do:

function setCape(turnOn)
  local image = turnOn and "head" or nil
  skeleton:setAttachment("capeSlot1", image)
  skeleton:setAttachment("capeSlot2", image)
  skeleton:setAttachment("capeSlot3", image)
end

But if I wanted a function that would work for any powerup, and I could just say "show" or "hide" at the root bone or slot for that powerup is this possible. So I think my question is:

Question: Can I retrieve a list of all the slots (slot names) under (i.e. children of) a given starting bone, and their images? So for the above is there a way to create a function to pass back to me in this case, "getSlotsAndImagesForBone("capeBone1")" and get a table with effectively in the table:

{ 
  { "capeSlot1", {capeImage1} }, 
  { "capeSlot2", {capeImage2} },
  { "capeSlot3", {capeImage3} },
}

You can iterate the slots on the skeleton and check the slots bone.

There is no existing bone hierarchy I can access then correct? That is, there is no existing function like "getChildBonesForParentBone(parentBoneName)" then? So I would need to iterate through the bones in the data & effectively build the hierarchy, and then from this I could easily implement a "getchildBonesForParentBone(parentBoneName)" right?

Yes, to get the children, loop through the bones and find bones who have a specific parent.

Hi Nate

I've managed to find/determine the bones under a parent bone (see code below - not sure if it's the best way).

QUESTION: I'm not sure now (can find the write functions) how to get for each bone the slots & attachments under them? Which Lua file/method would I need to use here. I note in the JSON export there is a slot section that does seem to get for Slot/Attachment/Bone combinations but trying to find in the Corona LUA API how to get this.

That is to ultimately then be able to do the required "skeleton:setAttachment("slotNameX", "attachmentNameX")" for each slot/attachment for each of the bones identified.

Getting all Bones Hierarchically Under the Parent (including the Parent)

local function getChildBoneNames(parentBoneName)
   local childBoneNames = {}
   for i,boneData in ipairs(skeletonData.bones) do
      if boneData.parent then
         if boneData.parent.name == parentBoneName then
            table.insert(childBoneNames, boneData.name)
         end
      end
   end
   return childBoneNames
end

local function getChildBoneNamesRecursive(parentBoneName, includeParent)
   local allBoneNames = {}
   if includeParent then
      table.insert(allBoneNames, parentBoneName)
   end
   local nextChildBoneNames = getChildBoneNames(parentBoneName)
   if nextChildBoneNames then
      for i,childBoneName in ipairs(nextChildBoneNames) do
         local grandchildrenBoneNames = getChildBoneNamesRecursive(childBoneName, true)
         for i,boneName in ipairs(grandchildrenBoneNames) do
            table.insert(allBoneNames, boneName)
         end
      end
   end
   return allBoneNames
end

local childrenBones = getChildBoneNamesRecursive("capeBone1", true)
pretty.dump(childrenBones)



Update:

Ok - think I have it - this seems to work 🙂 If anyone happens to use/optimize I'd be interested is seeing:

local function getChildBoneNames(parentBoneName)
   local childBoneNames = {}
   for i,boneData in ipairs(skeletonData.bones) do
      if boneData.parent then
         if boneData.parent.name == parentBoneName then
            table.insert(childBoneNames, boneData.name)
         end
      end
   end
   return childBoneNames
end

local function getChildBoneNamesRecursive(parentBoneName, includeParent)
   local allBoneNames = {}
   if includeParent then
      table.insert(allBoneNames, parentBoneName)
   end
   local nextChildBoneNames = getChildBoneNames(parentBoneName)
   if nextChildBoneNames then
      for i,childBoneName in ipairs(nextChildBoneNames) do
         local grandchildrenBoneNames = getChildBoneNamesRecursive(childBoneName, true)
         for i,boneName in ipairs(grandchildrenBoneNames) do
            table.insert(allBoneNames, boneName)
         end
      end
   end
   return allBoneNames
end

local function getBoneSlotAttachmentTable()
   local outputTable = {}
   local slots = skeleton.slots
   for i,slot in ipairs(slots) do
      outputTable[slot.data.boneData.name] = { slotName = slot.data.name, attachmentName = slot.data.attachmentName}
   end
   return outputTable
end

local function getBSAforParentBone(parentBoneName)
   local outputTable = {}
   local boneSlotAttachments = getBoneSlotAttachmentTable()
   local childrenBones = getChildBoneNamesRecursive(parentBoneName, true)
   for i,boneName in ipairs(childrenBones) do
      local slotAttachment = boneSlotAttachments[boneName]
      if slotAttachment then
         outputTable[boneName] = slotAttachment
      end
   
end return outputTable end local function setPowerUp(parentBoneName, turnOn) local BSA = getBSAforParentBone(parentBoneName) for k,v in pairs(BSA) do local attachmentNameValue = turnOn and v.attachmentName or nil skeleton:setAttachment(v.slotName, attachmentNameValue) end return BSA end --- Testing timer.performWithDelay(2000, function(event) setPowerUp("capeBone1", false) end) timer.performWithDelay(4000, function(event) setPowerUp("capeBone1", true) end)