maxgribov/Spine

How to get correct frame of `Skeleton`

W3xly opened this issue · 8 comments

Hello, first of all I want to thank you for trying to keep this library up to date.

Has anyone tried to solve the missing frame of a Skeleton character? I also tried calculateAccumulatedFrame() but it return values that make no sense (for Golbin it's it's more width than height)

And the second question that is related to this, has anyone tried to set the correct physicsBody for a character so that it corresponds to its actual size.

Everything can be solved through some magic number, but I don't like this solution very much..

Thanks a lot for answer!

Has anyone tried to solve the missing frame of a Skeleton character? I also tried calculateAccumulatedFrame() but it return values that make no sense (for Golbin it's it's more width than height)

Yes, I see the problem:

drawing
class GameScene: SKScene {
    
    override func didMove(to view: SKView) {
        
        do {
            
            let character = try Skeleton(json: "goblins-ess", folder: "goblins", skin: "goblin")
            character.name = "character"
            character.position = CGPoint(x: self.size.width / 2, y: (self.size.height / 2) - 200)
            addChild(character)
            
            for child in character["//*"] {
                
                let frameOrigin = convert(child.frame.origin, from: child)
                let outline = SKShapeNode(rect: CGRect(origin: frameOrigin, size: child.frame.size))
                outline.strokeColor = .red
                addChild(outline)
            }
            
            let outline = SKShapeNode(rect: character.calculateAccumulatedFrame())
            outline.strokeColor = .green
            addChild(outline)
       }  catch {
         print(error)
       }
   }
}

This is because of all transitions, rotations and scale changes of child nodes performed by SKAction, and there is no actual frame change:
drawing

class GameScene: SKScene {
    
    override func didMove(to view: SKView) {
        
        let atlas = SKTextureAtlas(named: "goblins/default")
        let texture = atlas.textureNamed("shield")
        let shield = SKSpriteNode(texture: texture)
        shield.size = CGSize(width: 100, height: 100)
        shield.position = CGPoint(x: size.width / 2, y: size.height / 2)
        addChild(shield)

        let moveAction = SKAction.move(by: .init(dx: 50, dy: 50), duration: 0)
        shield.run(moveAction)
        
        let outline = SKShapeNode(rect: shield.frame)
        outline.strokeColor = .green
        addChild(outline)
    }
}

Thanks a lot for such a fast answer, I understood the rotation offset, it shouldn't be a big problem.

Thank you especially for this character["//*"], I did not know that I could access individual atlases this way. I was hoping to be able to pass these SKShapeNode outlines that u created as bodies to Characters physicsBody. But so far no luck.

I am sorry for possibly stupid questions, this is one of my first experiences with SpriteKit..

And the second question that is related to this, has anyone tried to set the correct physicsBody for a character so that it corresponds to its actual size.

physicsBody adjust it's position on transition, rotation and scale changes with SKAction:
drawing

class GameScene: SKScene {
    
    override func didMove(to view: SKView) {
        
        let atlas = SKTextureAtlas(named: "goblins/default")
        let texture = atlas.textureNamed("shield")
        let shield = SKSpriteNode(texture: texture)
        shield.size = CGSize(width: 100, height: 100)
        shield.position = CGPoint(x: size.width / 2, y: size.height / 2)
        addChild(shield)
        
        let physicsBody = SKPhysicsBody(circleOfRadius: 55)
        physicsBody.isDynamic = false
        physicsBody.affectedByGravity = false
        
        shield.physicsBody = physicsBody

        let moveAction = SKAction.move(by: .init(dx: 50, dy: 50), duration: 0)
        let scaleAction = SKAction.scale(to: 1.5, duration: 0)
        shield.run(SKAction.group([moveAction, scaleAction]))
        
        let outline = SKShapeNode(rect: shield.frame)
        outline.strokeColor = .green
        addChild(outline)
   }
}

so u basically can attach physicsBody to any Slot of the Skeleton you need (or to the all of them):

drawing
class GameScene: SKScene {
    
    override func didMove(to view: SKView) {
        
        do {
            
            let character = try Skeleton(json: "goblins-ess", folder: "goblins", skin: "goblin")
            character.name = "character"
            character.position = CGPoint(x: self.size.width / 2, y: (self.size.height / 2) - 200)
            addChild(character)
            
            let torso = character.slotNode(named: "torso")
            let physicsBody = SKPhysicsBody(rectangleOf: .init(width: 100, height: 50), center: .init(x: 30, y: 0))
            physicsBody.isDynamic = false
            physicsBody.affectedByGravity = false
            
            torso?.physicsBody = physicsBody
   }
}

Thanks a lot for such a fast answer, I understood the rotation offset, it shouldn't be a big problem.

Thank you especially for this character["//*"], I did not know that I could access individual atlases this way. I was hoping to be able to pass these SKShapeNode outlines that u created as bodies to Characters physicsBody. But so far no luck.

I am sorry for possibly stupid questions, this is one of my first experiences with SpriteKit..

This is not a stupid question. But as I can see, there is no easy way to adjust SKNode'a frame after it was moved, scaled or rotated with SKAction (if it even possible). So, looks like you have to forget about Skeleton's frame and work with it's individual slots (I showed how you can it do earlier).

Thank you especially for this character["//*"], I did not know that I could access individual atlases this way.

https://developer.apple.com/documentation/spritekit/sknode/searching_the_node_tree

I understand where you're going with that, but I don't think it's possible to give a physical body in individual slots.. At the moment when I give the physical body into individual slots and simulate gravity, my whole skeleton falls apart. 😁 I'm sorry for the late answer and thank you for all your responses..

At the moment when I give the physical body into individual slots and simulate gravity

Of course, if you need to simulate gravity this is not working solution. It looks like create physical body with manually calculated dimensions and attached it o Skeleton node - this is the best choice for now, until we are figure out how to calculate correct frame automatically.