Spritekit: Animate node with running atlas and move node - swift

I want animate a character as running using .atlas and simultaneously also move the character on screen.
I was able to simulate running using atlas but don't know how to simultaneously move it.
Right now I use this:
let animation = SKAction.animateWithTextures(frames, timePerFrame: 0.2)
monsterNode.runAction((animation)).

You can, for instance, apply force to the node's physicsBody. This is great for a platformer, as obstacles and the landmark would slow down the character, making it more realistic.
let force = CGVector(dx: 9000, dy: 0)
self.physicsBody?.applyForce(force)
For a space racer or other more simple movement, you could simply apply velocity to it.
self.physicsBody?.velocity = CGVector(dx: 100, dy:10)
See SKPhysicsBody reference for more.
Update:
For a very simple movement, you can use the SKAction's moveBy and moveTo methods and group the movement and the animation.
let vector = CGVector(dx:100, dy: 10)
let moveAction = SKAction.move(by: vector, duration: 1)
yourNode.run(SKAction.group([moveAction, animationAction])

Related

SKSpriteNode - constant speed, and detect which SKSpriteNode does something

I have two questions:
How can I make an SKSpriteNode move at a constant speed and direction?
I'm currently using item.physicsBody?.velocity, but I want just a constant speed, in the direction to the left.
let item = SKSpriteNode(color: .black, size: CGSize(width: 32, height: 16))
item.position = CGPoint(x: 600, y: self.heights[random])
item.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width:32, height: 16))
addChild(item)
item.physicsBody?.velocity = CGVector(dx: -360, dy: 0)
item.physicsBody!.affectedByGravity = false
I have the above code in touchesBegan(). I want to add some code to update(), to detect when one of these created SKSpriteNodes does a certain thing (e.g. reaches a specified x position), and then make a change to that SKSpriteNode (e.g. delete it). How do I do that, so that I get that particular SKSpriteNode?
Just manually update your sprite's position. Define a speed in points per second, use a timer in update() to see how much time has passed since it was last called and with a bi of maths, work out its new position. I've done this and it works.
I'm not sure what the relevance of the touchesBegan() code is to this point (are you creating a sprite and setting it moving when you touch the screen?), but in general you could iterate over the array of child nodes in the scene using enumerateChildNodes(). When you have a node that matches your criteria (specific x position etc.), perform the action on the node.

ARKit - create world boundaries/get position at edge of visible plane?

Ok, what I am trying to do is create physics body/colliding boundaries for my character, my SCNNode, in my SceneKit game Im building with ARKit. This is so my node cannot move out of the user's vision/go so far away that it isn't visible as it is currently doing. My SCNNode is moved by user input, so I need to make "world boundaries" while ARKit still doesn't have vertical wall detection
I know you can place an object some set distance ahead of you in the real world as stated here Understand coordinate spaces in ARKit
and I have done that with this, just making a box with physics body here -
let box = SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0) //change to be VERY TALL - need to make it a giant room
node.physicsBody = SCNPhysicsBody(type: SCNPhysicsBodyType.static, shape: nil)
box.firstMaterial?.diffuse.contents = UIColor.red
box.firstMaterial?.isDoubleSided = true
node = SCNNode(geometry: box)
node.position = SCNVector3(view.pointOfView.simdWorldFront + float3(0, 0, -0.5)) //random distance ahead
And this works, and I could add it as a child node of camera so it moves as user moves, but I don't think Im doing this correctly.
Essentially I need 4 walls to box the user/SCNNode in (corral the character) that are infinitely high, and at the VERY edge of the horizontal plane that the user can see. Really I don't know what this distance should be in the x plane:
+ float3(0, 0, -0.5)
How would you create AR boundaries like this?

Rejecting gravity effect SceneKit

This's my first project using SpriteKit.
I'm using these nodes
let physicsBody = SCNPhysicsBody(type: .dynamic, shape: nil)
physicsBody.isAffectedByGravity = true
physicsBody.mass = 1
geometryNode.physicsBody = physicsBody
let force = SCNVector3(0, 9.8, 0)
let position = SCNVector3(0, 0, 0)
geometryNode.physicsBody?.applyForce(force, at: position, asImpulse: false)
scnScene.rootNode.addChildNode(geometryNode)
My goal is to see the object stuck in the centre of my scene.
As read within SceneKit's documentation, SceneKit uses SI so Mass 1 means 1 kg.
Gravity force applied to the mass centre of this object is -9.8N ( 1kg * 9.8 m/s^2 ) on the Y-axis.
Applying 9.8N to the mass centre should bring the resultant force equal to 0 so no one force is applied and the object should be stuck in the centre but in my project, it falls down.
Where am I wrong?
It looks to me like you apply the force when you create the node.
From the developer docs on applyForce:
Discussion This method accelerates the body without imparting any
angular acceleration to it. The acceleration is applied for a single
simulation step (one frame).
I think you need to move your applyForce call to your update method in the scene. so that the force is constantly applied.

Swift 3 (SpriteKit): Making a projectile move

I was wondering how to apply a force or thrust to a projectile (specifically an SKSpriteNode) to make it continuously move until it hits something. I have tried some ways like setting the velocity like this:
let node = SKSpriteNode(imageNamed: "node")
node.physicsBody = SKPhysicsBody(rectangleOf: node.size)
node.physicsBody.velocity = CGVector(dx: 5, dy: 5)
or instead of changing the node's velocity value at the end, I tried:
node.physicsBody?.applyImpulse(CGVector(dx: 5, dy: 5))
or
node.physicsBody?.applyForce(CGVector(dx: 5, dy: 5))
None of these actually move the projectile. I have even tried adding the same impulse and force forever each frame with an SKAction and there is still no movement. I would really appreciate any help :) Thanks.
Try adding a sure fire dynamism to the object:
let node = SKSpriteNode(imageNamed: "node")
node.physicsBody = SKPhysicsBody(rectangleOf: node.size)
// add this, to ensure dynamism:
node.physicsBody.isDynamic = true
Now all forces and impulses should work. Although I'd suggest using much larger numbers. Depends on the size and mass of the object, but you might need numbers a couple of orders of magnitude higher to get rapid movement.

How do I make a node move in sprite kit swift

I have been wondering how to do this for a long time I am using Sprite Kit swift, my problem is that don't know how to make a node move with SKActions so basicly when the go on the scene that I put it on they see a node moving (name the node sprite) ,I do not understand how it works can someone please show me an explained example on how to do this, thank you in advance!
To move a Sprite in Sprite-Kit you can use SKActions.
For example:
let action = SKAction.moveByX(3, y: 2, duration: 10)
This will make the sprite move 3 units along the x-axis and 2 units along the y axis in 10 seconds.
If you want your sprite to move to a specific place, you can do:
let action2 = SKAction.moveTo(location: CGPoint, duration: NSTimeInterval)
Hope this helped!
As I understand you have a scene with some node (e.g. name="myNode").
First of all, you need to access this node:
override func didMoveToView(view: SKView) {
let myNode = childNodeWithName(homeButtonName)!
...
}
Now you have a reference to your node.
Next step is to add action to move this node.
For example, let's move this node +20 horizontally and -30 vertically in 3 seconds:
let dX = 20
let dY = -30
let moveAction = SKAction.moveByX(CGFloat(dX), y: CGFloat(dY), duration: 3.0)
myNode.runAction(moveAction)
You can change many node's properties, not only position, e.g. size, alpha, rotation etc.
You can give actions to a Node or Sprite in Swift 3.0... First, we will change the size of the Node, or Sprite.
let nodeSize = SKAction.scale(to: 0.5, duration: 2)
In two seconds, this will change the size of the object from whatever it is to half that size. Next, to move the Node or Sprite to a different place, use...
let nodeSet = SKAction.moveBy(x: -3.0, y: 2.0, duration: 2)
In two seconds, the object will move to the left 3 units, and up 2.
If you want to assign these actions to a specific node, you can first create a node var parentNode = SKShapeNode() and then you can tell them to run the action.
parentNode.run(nodeSize)
parentNode.run(nodeSet)
Hope that this helps.