SKPhysicsBody uses only part of SKTexture - swift

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 =)

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

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

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)

Scale a SKPhysicsBody, how?

I'm reasonably sure I've previously seen code somewhere that scales a SKPhysicsBody, but google and the docs aren't helping, making me more confused than normal.
Is there a way to scale a physic's body in SpriteKit?
The docs, here, don't mention anything about it: https://developer.apple.com/reference/spritekit/skphysicsbody
If you assign a physics body to a sprite and scale that sprite, the physics body will scale with it.
So the answer I think to your question is a solid "no"; at least not in anything I've seen before.
If you care to dabble in a workaround:
Create a new physics body that is larger than what you currently have. Make a method or two to accomplish this.
node.physicsBody = scaledPhysicsBody(bodyToScale: xxxx)
2.
I would just make a blank SKNode and child it to whatever it is that you want to be hit-detectable. Then get rid of the parent's physics body and just use the child's. Now, you can scale the child node (and thus the PB) without affecting the graphics of the main sprite.
just updating this in 2023:
if you create you physics body from the sprites texture, you can use the SKPhysicsBody initialiser with texture and size property like this:
let scale: CGFloat = 0.9
self.physicsBody = SKPhysicsBody(
texture: self.texture!,
size: CGSize(
width: self.size.width * scale,
height:self.size.height * scale
)
)

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

How to prevent SKPhysicsBody stretching

The sprite I use for my character looks something like this (pink = transparent part):
After I set physicsBody to my node with self.physicsBody = SKPhysicsBody(texture: self.texture!, size: self.size), and set my SKView to show physics, I get an outline like this:
Which is, basically, the right mask, stretched to fit the size of the image.
Is there any way to get a physicsBody exactly around my character?
After playing around for quite a while, I've found the solution:
It's weird, but giving the SKPhysicsBody initializer a new SKTexture made from the same image, used for creating the SKTexture of SKSpriteNode initializer, worked perfectly well for me.
It should work. It works in my code with this line:
self.physicsBody = SKPhysicsBody.init(texture: self.texture!, size: self.frame.size)
Are you sure you do not scale the sprite after the creation of the physics body?