[SOLVED]
After some thorough research, it seems as though the Spine runtime, at least the AS3 version, is not able to swap attachments at runtime from dynamically generated ones. Only from attachments created in the editor.
So instead I went in and manually swapped the renderObject of the attachment and updated its coordinates. This allowed me to swap the player's weapon with a texture from a different atlas, outside of Spine. Here's my example code, hope it helps!
// First gather the texture and corresponding atlas from which the desired new asset is originating
var atlas:TextureAtlas;
var texture:Texture;
var atlases:Dictionary = GameAsset.getFxTextureAtlases();
for each (var atl:TextureAtlas in atlases)
{
var tex:Texture = atl.getTexture(weaponAsset);
if (tex) {
texture = tex;
atlas = atl;
break;
}
}
// Find the attachment on the Spine skeleton that needs swapping
var attachment:RegionAttachment = _skeleton.getAttachmentForSlotName(_weaponSlot, _weaponSlot) as RegionAttachment;
// Swap Image
attachment.rendererObject = new SkeletonImage(texture);
// Update coordinates so the positioning/offset/scaling is of the new imported asset
// See StarlingAtlasAttachmentLoader.newRegionAttachment
var frame:Rectangle = texture.frame;
attachment.regionOffsetX = frame ? -frame.x : 0;
attachment.regionOffsetY = frame ? -frame.y : 0;
attachment.regionWidth = texture.width;
attachment.regionHeight = texture.height;
attachment.regionOriginalWidth = frame ? frame.width : texture.width;
attachment.regionOriginalHeight = frame ? frame.height : texture.height;
var subTexture:SubTexture = texture as SubTexture;
if (subTexture) {
var root:Texture = subTexture.root;
var rectRegion:Rectangle = atlas.getRegion(weaponAsset);
attachment.regionU = rectRegion.x / root.width;
attachment.regionV = rectRegion.y / root.height;
attachment.regionU2 = (rectRegion.x + subTexture.width) / root.width;
attachment.regionV2 = (rectRegion.y + subTexture.height) / root.height;
attachment.setUVs(attachment.regionU, attachment.regionV, attachment.regionU2, attachment.regionV2, atlas.getRotation(weaponAsset));
} else {
attachment.regionU = 0;
attachment.regionV = 1;
attachment.regionU2 = 1;
attachment.regionV2 = 0;
}
attachment.updateOffset();
[ORIGINAL POST]
Hi there,
we've just started using Spine AS3 for our AIR game in Starling and it's working wonders. We're using one skeleton data for all animations and several Starling Atlases to load up the different skins.
The problem I'm encountering is with swapping the weapon a player has in his/her hands with a new attachment created at runtime (from a different Atlas containing all weapons). This will happen frequently as the player can drop/pickup weapons.
Steps are:
- create texture data
- create skeleton data
- create new attachment with weapon texture
- add attachment to existing skeleton slot
- create animation
- swap slot attachment
- start up animation and add to stage
- repeat swap slot attachment for drop/pickup.
I've tried swapping the slot attachment on the skeleton before instantiating the animation, and on the skeletonData before creating a skeletong instance, but with no luck. The original attachment disappears and nothing else happens.
I've also tried the setAttachment method on the skeleton itself.
Has anyone encountered this? Thank you!
// Load skin's Atlas
var attachmentLoader:AttachmentLoader = new StarlingAtlasAttachmentLoader(GameAsset.getAvatarAtlas(_skin));
var json:SkeletonJson = new SkeletonJson(attachmentLoader);
json.scale = .14;
// Load Skeleton pose/animation data
var skeletonData:SkeletonData = json.readSkeletonData(GameAsset.getAvatarCoords(_skin + "Coords"));
_skeleton = new Skeleton(skeletonData);
// Create mixes for smoothing transitions
var stateData:AnimationStateData = new AnimationStateData(skeletonData);
stateData.setMixByName(PlayerAnimationType.IDLE, PlayerAnimationType.RUN, 0.3);
stateData.setMixByName(PlayerAnimationType.RUN, PlayerAnimationType.IDLE, 0.2);
stateData.setMixByName(PlayerAnimationType.IDLE, PlayerAnimationType.JUMP, .1);
stateData.setMixByName(PlayerAnimationType.RUN, PlayerAnimationType.JUMP, .1);
stateData.setMixByName(PlayerAnimationType.JUMP, PlayerAnimationType.FLY, 0.3);
// Get weapon textures from master weapon atlas
var weaponLoader:AttachmentLoader = new StarlingAtlasAttachmentLoader(GameAsset.getFxTextureAtlas("FxAssets1"));
// Create new attachment to swap original weapon attachment
var region:RegionAttachment = weaponLoader.newRegionAttachment(_skeleton.data.defaultSkin, "WeaponRocket", "WeaponRocket");
// Find Slot index of the weapon slot
var slotIndex:Number = _skeleton.data.slots.indexOf(_skeleton.findSlot(_weaponSlot).data);
// Add new attachment to weapon slot
_skeleton.data.defaultSkin.addAttachment(slotIndex, "WeaponRocket", region);
//var weaponSlot:Slot = _skeleton.findSlot(_weaponSlot);
//weaponSlot.attachment = region;
//weaponSlot.data.attachmentName = "equippedWeapon";
//weaponSlot.setToSetupPose();
_animation = new SkeletonAnimation(skeletonData, true, stateData);
_animation.x = 0;
_animation.y = _actorSize;
// Assign new attachment to weapon slot
_animation.skeleton.findSlot(_weaponSlot).attachment = region;
_animation.skeleton.findSlot(_weaponSlot).data.attachmentName = "WeaponRocket";
_animation.skeleton.setToSetupPose();
_animation.state.setAnimationByName(0, PlayerAnimationType.IDLE, true);
addAnimation(_animation, _avatar);