Add a texture to an existing SKSpriteNode in Swift - swift

How can I add a texture to an existing SKSpriteNode?
In the docs all I see is a way to initialize a SKNode with a texture, but not a way to add a texture to it.
// Creating with a texture is easy.
var mySprite = SKSpriteNode(texture: myTexture)
// But no method for adding a texture.
var anotherSprite = SKSpriteNode()
anotherSprite.texture = myTexture // This is not valid.

You need to update the size of the sprite.
var anotherSprite = SKSpriteNode()
anotherSprite.texture = myTexture
anotherSprite.size = myTexture.size()
It seems SKSpriteNode() initialized the size of the sprite as width:0, height:0. So you can't see the sprite in the scene.

Related

Swift - How to add scene boundaries for specific nodes?

I'm trying to develop an IOS game using SpriteKit, and I want to add a Physics body to the scene so that the player won't be able to go through the edges of the screen. At the same time, I want some nodes (for example - bombs that fall from the sky) to be able to go through the edges of the screen.
I know that I can use the following line to add a physics body to the scene:
self.physicsBody = SKPhysicsBody (edgeLoopFrom: self.frame)
My question is how can I allow a "bomb" object to go through such body while having a "player" object obligated to those boundaries.
The answer is relative to categoryBitMask and collisionBitMask of the involved physic bodies.
For example, for the scene:
if let scenePB = scene.physicsBody {
scenePB.categoryBitMask = 1
scenePB.collisionBitMask = 2 // collides with player
}
For the player:
if let playerPB = player.physicsBody {
playerPB.categoryBitMask = 2
playerPB.collisionBitMask = 1+4 // collides with scene and bombs
}
For any bomb:
if let bombPB = bomb.physicsBody {
bombPB.categoryBitMask = 4
bombPB.collisionBitMask = 2 // collides with player
}

How to change spriteKit SKSpriteNode texture

I have a Swift 4.2 SpriteKit scene and I want to programatically change the texture of an SKSpriteNode.
How do I access the SKSpriteNode contained in the SKNode to change the texture?
Here is my code:
#IBOutlet weak var spritekitsceneFG: WKInterfaceSKScene!
var SpriteTick1 = SKNode()
SpriteTick1 = (spritekitsceneFG.scene?.childNode(withName: "SKSpriteTick1"))!
Want to change texture here!
print(SpriteTick1)
Printing out the SKNode gives the following output:
<SKSpriteNode> name:'SKSpriteTick1' texture:[<SKTexture> 'tick' (64 x 64)] position:{-48.000137, -56.000198} scale:{1.00, 1.00} size:{48, 48} anchor:{0.5, 0.5} rotation:0.00
I want to be able to programatically change the texture here, the texture is called 'tick'
Ok I found A way to do it like this. Any better ideas much welcomed.
var SpriteTick1 = SKSpriteNode()
SpriteTick1 = (spritekitsceneFG.scene?.childNode(withName: "SKSpriteTick1"))! as! SKSpriteNode
let textureCross = SKTexture(imageNamed: "cross")
SpriteTick1.texture = textureTick

parent physicsBody doesn't work

I have a GameScene.sks and Player.sks. Player.sks stores player sprite, that consists of 3 parts (body, hand[child of body] and lantern[child of hand]). In the custom class of this scene I create playerTexture from image and set it as physics body.
let playerTexture = SKTexture(imageNamed: "player_outline")
parent!.physicsBody = SKPhysicsBody(texture: playerTexture, size: playerTexture.size())
I add player scene reference to the Game Scene. And when I move player, physics body staying behind sprite and don't move at all. If I don't use 'parent!' it will work, but physics body will have offset.
But if I create physics body from the Scene Editor, it works! What's happening?
Player.swift
class PlayerNode: SKSpriteNode, EventListenerNode {
func didMoveToScene() {
let playerTexture = SKTexture(imageNamed: "player_outline")
parent!.physicsBody = SKPhysicsBody(texture: playerTexture, size: playerTexture.size())
parent!.physicsBody!.categoryBitMask = PhysicsCategory.Player
parent!.physicsBody!.collisionBitMask = PhysicsCategory.Wall
}
}
GameScene.swift
var player: PlayerNode!
player = childNode(withName: "//player") as! PlayerNode
Player.swift
Player's body called 'player', arm called 'lanternArm' and it is a child of 'player', lantern called 'lantern' and it is a child of 'lanternArm'.
With this code:
> parent!.physicsBody = SKPhysicsBody(texture: playerTexture, size:
> playerTexture.size())
You are defining the physicsBody of player's parent, not player itself. Is that what you want to do? What is player's parent?
If I don't use 'parent!' it will work,
So you have this:
physicsBody = SKPhysicsBody(texture: playerTexture, size: playerTexture.size())
Now you are defining players physics body.
but physics body will have offset.
Check the anchorPoint of player. If it's (0, 0) that will give you an offset physicsBody.

Difficulty with filtering nearest neighbor for an SKSpriteNode and the size of said node(swift, spritekit)

I have a node named "user" and it runs an animation through user.atlas constantly. It is also pixel art (18x50) and I need it to stay looking sharp and how I designed it. If I remove the action and add
user.texture?.filteringMode = .Nearest
it looks sharp and clear and perfect - but as soon as I add the action, the texture don't seem to want to follow that rule.
Also!
The image is stretched, even if I set the size to (18 , 50) it still is stretched vertically and the pixels are longer than they are wide. This problem persists no matter the animation.
Anyone have any ideas? Thanks.
You should set filtering mode of the textures before you add to the sprite.
Here is an example:
// this creates a walking character with endless loop
// create textures of the sprite
let frame1 : SKTexture = SKTexture.init(imageNamed: "walk-left-1")
let frame2 : SKTexture = SKTexture.init(imageNamed: "walk-left-2")
let frame3 : SKTexture = SKTexture.init(imageNamed: "walk-left-3")
let frame4 : SKTexture = SKTexture.init(imageNamed: "walk-left-4")
// set filter for pixelart
frame1.filteringMode = .nearest
frame2.filteringMode = .nearest
frame3.filteringMode = .nearest
frame4.filteringMode = .nearest
// create the textures array
let walkFrames = [frame1, frame2, frame3, frame4]
// create sprite and add to the scene
let sprite = SKSpriteNode.init(texture: walkFrames[0])
sprite.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
self.addChild(sprite)
// create the walking animation
let animate = SKAction.animate(with: walkFrames, timePerFrame: 0.2)
//OPTIONAL: make sprite bigger if you need
sprite.setScale(4)
// start walking
sprite.run(SKAction.repeatForever(animate))

Is there a way to include a SpriteKit scene in a SceneKit Scene?

I am wondering if it is possible to include a SpriteKit scene in a SceneKit scene, and if it is, how to do that ?
Yes there is!
You can assign a Sprite Kit scene (SKScene) as the contents of a material property (SCNMaterialProperty) in Scene Kit.
I've come across a few questions about this exact topic and there don't seem to be a whole lot of actual code examples, so here's another one. Hopefully this is helpful:
SKSpriteNode *someSKSpriteNode;
// initialize your SKSpriteNode and set it up..
SKScene *tvSKScene = [SKScene sceneWithSize:CGSizeMake(100, 100)];
tvSKScene.anchorPoint = CGPointMake(0.5, 0.5);
[tvSKScene addChild:someSKSpriteNode];
// use spritekit scene as plane's material
SCNMaterial *materialProperty = [SCNMaterial material];
materialProperty.diffuse.contents = tvSKScene;
// this will likely change to whereever you want to show this scene.
SCNVector3 tvLocationCoordinates = SCNVector3Make(0, 0, 0);
SCNPlane *scnPlane = [SCNPlane planeWithWidth:100.0 height:100.0];
SCNNode *scnNode = [SCNNode nodeWithGeometry:scnPlane];
scnNode.geometry.firstMaterial = materialProperty;
scnNode.position = tvLocationCoordinates;
// Assume we have a SCNCamera and SCNNode set up already.
SCNLookAtConstraint *constraint = [SCNLookAtConstraint lookAtConstraintWithTarget:cameraNode];
constraint.gimbalLockEnabled = NO;
scnNode.constraints = #[constraint];
// Assume we have a SCNView *sceneView set up already.
[sceneView.scene.rootNode addChildNode:scnNode];