How to measure volume or opaque pixel count of part of a sprite in Spritekit - swift

I have a SKSpriteNode which has a PNG texture, partly transparent.
I want to make a logical split line on this sprite and then measure the volume or opaque pixel count in each part. The object of the exercise is to tell what percentage total sprite volume exists in each part.
I have done some research and came empty. Seems there are no built in methods to do so. Can you guide me in the right direction here?

you could create a "pixel perfect" SKPhysicsBody like this:
let sprite = SKSpriteNode(imageNamed: "Spaceship")
sprite.physicsBody = SKPhysicsBody(texture: sprite.texture!,
size: sprite.texture!.size())
And then access the property sprite.physicsBody.area which gives you the area of the body in square meters (you can convert it to points, here is the documentation)

Related

Creating a physicsBody from a texture out of a texture atlas results in weird proportions

I use physicsBodies that are made from an image, I put an image file in the Assets.xcassets file and create the spriteNode using the image name as the imageNamed argument, I then use the spriteNodes texture as the texture argument of the physicsBody and the same size value from the spriteNode as the size argument. This works like a charm below 13.0 (13.0 has some issues with this). However, if I try to do this same thing with the same image files but in a Texture Atlas the spriteNode() still looks perfectly fine but the physicsBody is massively out of proportion, I would be able to get them to line up by dividing the width and height of the physicsBody by different values but the fact that I'm gonna have to brute force something means I've probably done something wrong
Image of result when using spriteAtlas, keep in mind the wings aren't part of the spriteNode and the rectangle around the eagle is a different body: oh no no no
How I create physicsBodies:
func createPigeon(size: CGSize, position: CGPoint) {
//W/o texture atlas
sprite = SKSpriteNode(imageNamed: "pigeonHitBox")
//with textureAtlas
sprite = SKSpriteNode(texture: gameScene.spriteAtlas.textureNamed("pigeonHitBox"))
sprite!.size = size
sprite!.position = position
sprite!.name = "Pigeon"
sprite!.physicsBody = SKPhysicsBody(texture: sprite!.texture!, size: size)
sprite!.zPosition = 1
sprite!.physicsBody!.isDynamic = true
defaultCollisions()
gameScene.addChild(sprite!)
}
So I figured out that the problem was due to the way SpriteKit overlaps and deletes alpha in order to squeeze more images into one atlas. The only fix I could find for this was putting the images I used for hitboxes into the Assets.xcassets file and making sure the animation action had resize set to false.
I get why this is done but this has just resulted in me not being able to put a good 13 images inside a textureAtlas, there should be an option to not axe alpha

SKSpriteNode or SKShapeNode for Circular Object

Does anyone have any guidance how to create a SpriteKit object that looks like a circle with circular physics properties? I've considered using SKShapeNode, yet after reading comments in documentation like this one "the SKSpriteNode class offers higher performance than this class, so use shape nodes sparingly" here https://developer.apple.com/documentation/spritekit/skshapenode, I'm reluctant to use SKShapeNode.
I have code to create an SKSpriteNode from image that makes it look like a circle...
sprite = SKSpriteNode(imageNamed:spriteImage)
...and I've applied a circular physics body...
sprite.physicsBody = SKPhysicsBody(circleOfRadius: (width / 2))
I've set properties such as allowrotation, affectedbygravity and isDynamic to true in the physics body...
physics = sprite.physicsBody
physics.affectedByGravity = true
physics.allowsRotation = true
physics.isDynamic = true
The circle SKSpriteNode still behaves like a square. Instead of rolling like a wheel, the object flops like a square.
cc was right. The original physics body was set to a circle, then at some point in the code the physics body was changed back into a square. I fixed that part of the code and it is working now. Thanks!

How to assign an SKPhysicsBody around a sprite node so its wraps around the objects frame perfectly

I'm trying to make a physics body that outlines the sprite node, example: instead of using SKPhysicsBody(circleOfSize...) and just getting the circle shape or using SKPhysicsBody(RectangleOfSize...) but i thought there was an "AlphaMask" or something like that that would allow, say if my sprite node was the shape of a cup or a "V" shape that would allow objects into the open top and get caught inside the "V"? thanks in advance :)
so the first picture is what i keep getting when i try the rectangle one and the second picture is the type i need!
I think the best solution could be to build a path and after to make:
SKPhysicsBody.init(edgeLoopFrom: path!)
This is the official source documentation:
/**
Creates an edge loop from a path. A loop is automatically created by joining the last point to the first. The path must have no self intersection. Edges have no volume and are intended to be used to create static environments. Edges can collide with body's of volume, but not with each other.
#param path the path to use
*/
public /*not inherited*/ init(edgeLoopFrom path: CGPath)
With this solution you will able to define precisely your shape following CGPath construction (the 'V' shape).
If you're using a PNG image (or any image type that supports clear pixels), you can just create a physicsBody from a texture:
let sprite = SKSpriteNode(imageNamed: "Spaceship")
sprite.physicsBody = SKPhysicsBody(texture: sprite.texture!, size: sprite.texture!.size())
This creates a physicsBody based on the clear and coloured pixels of the texture to do its best at matching the shape.
Be warned that using this isn't always 100% accurate and may cause issues if used with highly complex textures (lag, memory issues, etc...)
As per Apples Docs:
When choosing a shape for your physics
body, do not be overly precise.
More complex shapes require more work to be properly simulated.
SKPhysicsBody Apple Docs

Swift Sprite-kit SKPhyshicsBody

I have a few images that can detect when they get touched right now I am using
plane.physicsBody = SKPhysicsBody(circleOfRadius: plane.frame.height / 2)
but I need it so it is the boarder of the image not a circle or rectangle.
We have a plane and you want a physical body.
Your first approach is circleOfRadius (the physical representation is a circle with a given radius). You can use another shape, such a rectangle:
plane.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(100, height: 100))
As explained in the comments you can also use the shape of a sprite (texture) to create the shape of the physics body:
plane.physicsBody = SKPhysicsBody(texure: plane.texture!, size: plane.size)
But a good way to choose it's this: if you want your game to run smootly on many different devices, don't make sure the physics calculations become too complicated. In other words if you have many object around your plane with physical behavior moving around and colliding with each other, you may choose to use simplified shapes to deal with the physics more efficiently, especially if a shape already looks a lot like a rectangle or a circle.

SKPhysicsBody uses only part of SKTexture

I'm using an SKTexture with an image and set the SKPhysicsBody. Like that:
var moleTexture = SKTexture(imageNamed: "moleTop1")
leftPlayer = SKSpriteNode(texture: moleTexture)
leftPlayer.physicsBody = SKPhysicsBody(texture: moleTexture, size: leftPlayer.texture!.size())
Now after I start my game, I noticed that the physicsBody is set wrong. I've activated the showPhysics property and my image looks like that:
As you see, the only thing which is used by SKPhysicsBody is the little part on the middle left(blue border).
How can I change that so that the whole image will be used?
That looks interesting. I believe it will only create an outline (or one shape) and it appears to be starting from the left and because there are no other pixels near enough it calls it done.
I wonder if you get a different result if those pixels are touching. I would try and validate that first. If that is the case you may have to change the texture or use a different variation of the texture for the physical body.
I hope that helps =)