Animate an SKSpriteNode with textures that have a size different from the original - swift

I want to animate an SKSpriteNode using textures from an SKTextureAtlas, using SKAction.animateWithTextures(textures,timePerFrame,resize,restore). However, the textures in the atlas have a size that is slightly larger than the original texture (it's basically a character moving). When the action is run, the textures are either compressed to fit the original size of the sprite, or recentered when I set resize to false, which changes the position of the character. What I want, though, is for the textures to be anchored at the lower-left corner (or lower-right, depending on the direction) so that the position of the character doesn't change apart from the extra part of the texture.
I've tried changing the anchor point of the sprite prior to running the action, but obviously that applies to the original texture as well. Also, I guess changing the size of the original texture would have an impact on the physics behaviour, which I want to avoid.
Does anyone have a suggestion about how to do this?
Thanks!
David

This would work
Edit all the textures to match the size of the largest sized texture.
Just give the smaller textures some padding using an alpha channel to give you a transparent background.
E.g. Notice how the first texture has lots of negative space
(From CartoonSmart.com)
Create the physics body with a certain size in mind. E.g. You can load the texture without the padding and get the size. Then position it as needed onto the new and improved texture with padding. So after you create the Sprite as normal with the new resized textures you can then
/// load a texture to be a template for the size
let imageTextureSizeTemplate = SKTexture(imageNamed: textureWithoutPadding)
let bodySize = imageTextureSizeTemplate.size()
/// position template texture physics body on texture that will be used
let bodyCenter = CGPointMake(0.5, 0.5)
// create physics body
let body:SKPhysicsBody = SKPhysicsBody(rectangleOfSize: bodySize, center: bodyCeneter)
self.physicsBody = body
Set resize: false when you animate the textures.

Related

How to feed a transform.position into shader graph?

I am trying to mask a sprite by using shader graph.
Here is a picture of what I have so far:
my problem is that when I feed the mask texture into the shader it centers itself on the main texture, as you see in this image.
See the slightly transparent checkerboard to the right side of the character? I only want this operation to affect the parts where the checkerboard intercepts with the character.
For this I would need someway to displace and scale(?) the mask texture so that it detaches from the center of the main texture.
What nodes do I have to add to accomplish this, and where to connect them? Thanks.
As I commended I do not fully understand the question, but I will give it a try!
You want to move the UV of the texture to only make it apply to part of the image, and disable wrapping!
This can be done by using UV node while using the same channel you have on the overlapping texture and then adding the offset to it.
In order to disable wrapping you need to disable it on texture itself
Change Wrap Mode to Clamp
Set offset to values below 1. Now you need to just calculate what offset value for you will be as 1 is the full width of the image.
EDIT:
Instead of manually changing the UV texture you should use Tiling and Offset node which has easy scaling by changing tiling values.
Good luck :)

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

Detect touches on SKSpriteNode with oddly shaped image(s) running animations

Using SpriteKit for an iOS 9.0 app/game (and no physics body).
I have a few SpriteNodes on a scene. SpriteNodes are with oddly shaped images and runs through multiple frames for animation.
What is the best way to detect touches on a SpriteNode's image content, but not on transparent area of the entire image rectangle.
I see a lot of posts on using SKCropNode / MaskImage. In my scenario, I have multiple images/frames for each SpriteNode for the animation.
Please advice on an approach or point me in the right direction. Thanks.
Based on additional info from comments above:
With only 16 shapes, from the 16 frames, one of the more efficient ways would be to draw primitive shapes that roughly approximate the outlines of your character at each frame, and convert these to CGPaths. These can then be swapped in and out for each frame or (better) plucked out appropriately when there's a touch for testing based on the frame currently being shown at time of touch.
CGPaths are very lightweight structs, so there shouldn't be any performance problems with either approach.
CGPathContainsPoint is the old name of this test, which is now a modernised API for Swift 3 and onwards:
Troubles using CGPathContainsPoint SWIFT
There is an app called PaintCode, that's about $100 USD, which translates vectors into CGPaths, amongst other things, so you could use this to import your shapes. You can copy/paste vectors into it, which I suggest, because you might want to draw in a friendly drawing program. PaintCode doesn't have the world's best drawing experience.
Additionally, here's a free, online tool for doing the creation of a polygon path from textures. Probably more painful than using a drawing app and PaintCode, but it's FREE!
Alternative: Physics Bodies from Texture, and Contact with Touch
You can automagically create physics body shapes from a texture, like so, from the docs on this page:
let texturedSpaceShip = SKSpriteNode(texture: spaceShipTexture)
texturedSpaceShip.physicsBody = SKPhysicsBody(texture: spaceShipTexture,
size: CGSize(width: circularSpaceShip.size.width,
height: circularSpaceShip.size.height))
There have been reports of problems with determining if a point is within a given physics body, so it might be better to create a small physics object, place it where the touch is, and then determine if its in contact with the physics body shape appropriate for the current frame of the current game entity.
Caveat:
There's no telling (nor way to control, that I know of) how complex the resultant CGPaths are for these automagically created physics shapes.
I personally would just check the pixel of the current texture to see if is transparent or not. You can do this to get the pixel data:
(Note this code is hypothetical to get you started, I will try to work out a real example later on for you if you can't figure it out.)
(Also note, if you scale sprites, you need to handle that with converting touch location to texture)
let image = sprite.texture.cgImage()
if let dataProvider = image.dataProvider, let data = dataProvider.data
{
let screenScale = UIScreen.main.scale //let's handle retina graphics (may need work)
//touchedLocation is the location on the sprite, if the anchor was bottom left (it may be top left, will have to verify)
//So if I touch the bottom left corner of the sprite, I should get (0,0)
let x = touchedLocation.x * screenScale
let y = touchedLocation.y * screenScale
let width = sprite.texture.size().width * screenScale
let bpp = 4 // 4 bytes per pixel
let alphaChannel = 3 //Alpha channel is usually the highest byte
let index = bpp * (y * width + x) + alphaChannel
let byte = data.withUnsafeBytes({[UInt8](UnsafeBufferPointer(start:$0 + index,count:1))})
print(Alpha: \(byte))
}
else
{
//we have no data
}

How to colorize an SKTexture that is created with imageFromFile?

I have created png images of several shapes, such as hexagons and stars, and they are all white color.
I want to colorize these SKSpriteNodes or SKTextures so that I can assign any color rather than creating shape images for each color I need and loading those textures into memory. I need the images to be high resolution, so having several images and loading them into memory is not a good option since I receive memory warnings from XCode. Loading them into memory as they are needed also does not work because they cause my game to lag for about 0.25 seconds.
So, is there any way I can create 1 SKTexture and colorize the image texture of an SKSpriteNode whenever I need it to change colors?
You can change color of white texture like this (assuming that you are using pure white textures):
//Colorize to red
let yourNode = SKSpriteNode(imageNamed: "textureName")
yourNode.colorBlendFactor = 1
yourNode.color = UIColor.redColor()
About colorBlendFactor:
The value must be a number between 0.0 and 1.0, inclusive. The default
value (0.0) indicates the color property is ignored and that the
texture’s values should be used unmodified. For values greater than
0.0, the texture is blended with the color before being drawn to the scene.
More about this topic on StackOverflow.
Hope this helps.

Sprite Kit Physics Body Complex Shape - Spritekit

I have this situation: http://mokainteractive.com/example.png
I'd like to move the white ball inside the red track and detect wherever the balls touch the limit of the red track.
Which is the best solution? I have to create multiple transparent shape along the borders? Do you have other ideas?
thanks so much
In iOS8 you can create a single physics body for that kind of shape.
Make a texture of your shape with p.e. Adobe Illustrator and use this method:
init(texture texture: SKTexture!,alphaThreshold alphaThreshold: CFloat,size size: CGSize) -> SKPhysicsBody
The SKTexture is your shaped image. The body is defined by the colored pixels.
The alphaThresHold: The minimum alpha value for texels that should be part of the new physics body.
The Size is clear I think.
The texture is analyzed and all invisible pixels around the egg are ignored and only the color pixels are interpreted as the body of the SKPhysicsNode. You should use too many of these because they are very expensive to calculate for the Physics Engine.
Variations of this method are found in the SpriteKit Class Reference.
To your problem. Make an inverse texture of your area which should be transparent and pass it as texture to the physics body. It will be analyzed and a body around the free zone is created.
You cannot create a single physics body for that kind of shape.
Using bodyWithPolygonFromPath: will only allow you to create a convex polygonal path which obviously does not work for your shape.
I think you have 3 options here:
Use a number of bodyWithPolygonFromPath: bodies (probably the hardest to do and time consuming).
Use a number of various size bodyWithRectangleOfSize: bodies (not so hard but time consuming).
Use only straight lines in your image and use bodyWithRectangleOfSize: (the easiest and fastest). If you choose this option remember you are still free to rotate your straight lines to various angles.