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.
Related
I'm trying to create a chain-like structure in SpriteKit and I'm having trouble understanding the behavior of SKPhysicsJointLimit's maxLength property. It seems not to do anything at all.
This question didn't solve my problem.
According to the documentation, maxLength is The maximum distance allowed between the two physics bodies connected by the limit joint.
However, my two nodes become oriented much farther apart than their maxLength value. It's true that I'm setting their initial positions to be farther apart than maxLength -- but I would expect the nodes to pull together during the simulation, as if tied together by a stretchy rope. Instead, the nodes remain far apart.
So, here's some code that sets a joint between two SKSpriteNodes.
let screen = UIScreen.main.bounds
let bodyA = SKSpriteNode(imageNamed: "box.png")
let bodyB = SKSpriteNode(imageNamed: "box.png")
bodyA.size = CGSize(width: 20, height: 20)
bodyB.size = CGSize(width: 20, height: 20)
bodyA.position = CGPoint(x: screen.width*0.4, y: screen.height*0.8)
bodyB.position = CGPoint(x: screen.width*0.6, y: screen.height*0.8)
bodyA.physicsBody = SKPhysicsBody(circleOfRadius: 20)
bodyB.physicsBody = SKPhysicsBody(circleOfRadius: 20)
addChild(bodyA)
addChild(bodyB)
let pinJoint = SKPhysicsJointLimit.joint(withBodyA: bodyA.physicsBody!, bodyB: bodyB.physicsBody!, anchorA: CGPoint(x: 0.5, y: 0.5), anchorB: CGPoint(x: 0.5, y: 0.5))
//This doesn't seem to do anything:
pinJoint.maxLength = 5.0
scene?.physicsWorld.add(pinJoint)
In the simulation, it's clear that there is a physics joint connecting the two nodes -- it's just that the nodes are much farther apart than they should be.
Why doesn't my maxLength value change the behavior of my two nodes, and how do I fix the problem? What am I not understanding?
Thanks for your input!
Be sure that the anchor points are in scene coordinates, as described in the documentation. The (0.5, 0.5) is likely intended to be "center of the sprite" or something like that, but that's not correct for a joint.
So let's say I have this rectangular SKNode. Can I add SKPhysicsBody to only one side of the rectangle i.e. only the top side, so that only the top side could detect collision and not the other sides (then the physics indicator blue line would only appear on the top and not anywhere else)?
I wanted to create a game, but I don't know whether something like this could work.
So if I could, how?
If I can't, is there a way around this issue?
I wanted to add a normal rectangle with physicsBody on only one side.
See the rectangle image here, the blue part is the place where I want the physicsBody
So I've tried adding an edgeBased physicsBody, but it doesn't seem to work (either the physicsBody didn't get created or it is in the wrong position).
let rectangle = SKSpriteNode(imageNamed: "Rectangle")
rectangle.size = CGSize(width: 128, height: 128)
rectangle.position = CGPoint(x: frame.midX, y: frame.midY)
rectangle.physicsBody = SKPhysicsBody(edgeFrom: CGPoint(x: rectangle.position.x - rectangle.size.width/2, y: rectangle.position.y + rectangle.size.width/2), to: CGPoint(x: rectangle.position.x + rectangle.size.width/2, y: rectangle.position.y + rectangle.size.width/2))
rectangle.physicsBody!.restitution = 0.0
rectangle.physicsBody!.categoryBitMask = physicsCategories.groundCategory
rectangle.physicsBody!.collisionBitMask = physicsCategories.squareCategory
addChild(rectangle)
Thanks!
You could, but it would also detect collision coming from the 'wrong' side i.e. with an object that has traveled through the node.
Physics bodies can be volume or edge based, but even an edge-based one that was only a pixel thick still has 4 sides.
If you could supply a drawing of exactly what you want, we could help better as there are probably several different approaches.
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])
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.
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.