I have a square = SKSpriteNode() that turns that rotates 360° when you touch it. I want to stop the spinning when you touch it again.
Now I would make square rotate through the SKAction.rotate but how can I stop the spinning realisticly meaning that I want the sprite to spin slower and slower until it stands still.
Did you try and ease out curve for the timingMode? If you don't like this effect you can provide your own custom timingFunction. There are several websites where you can explore animation curves online. I like this one.
You may want to consider using a physicsbody and applying an angular force.
let square = SKSpriteNode(color:.white,size:CGSize(10,10))
if let physicsBody = SKPhysicsBody(rectangleOf:square.frame.size)
{
physicsBody.isDynamic = true
physicsBody.allowsRotation = true
physicsBody.affectedByGravity = false
physicsBody.angularDamping = 0.1 //Adjust this to speed up or slow down the resistance of the spin
square.physicsBody = physicsBody
}
...
When you need to spin:
square.physicsBody!.angularImpulse(1) //Adjust this to change the amount of force applied to the spin
Related
I am making a game with sprites that move and obstacles to learn SpriteKit. I want the sprites that move to collide with the obstacles and bounce off of them but I want the obstacles to stay fixed. How do I do this? I have tried the following with no success:
Setting obstacle.physicsBody?.isDynamic = true. This made the sprites go through the obstacle.
Fixing the movement and rotation of the object with SKConstraint. When I do this they just go through each other.
Setting the mass of the body to be really high as follows obstacle.physicsBody?.mass = CGPoint.maxFiniteMagnitude but this freezes the game. When I set it really high it doesn't seem to do anything.
Setting obstacle?.physicsBody.velocity = CGVector(dx: 0, dy: 0) when the objects collide. I know that the contact.bodyA and contact.bodyB are passed by value and not reference so I loop through an array with the obstacles and set the velocity this way. The obstacles are still pushed by the other sprites.
Update:
- Setting obstacle.physicsBody?.collisionBitMask = PhysicsCategory.none so the sprite collides with the obstacle but not the other way around.
The object is setup as follows, with fish being the other sprite:
obstacle.position = location
obstacle.physicsBody = SKPhysicsBody(rectangleOf: obstacle.size)
obstacle.physicsBody?.isDynamic = true
obstacle.physicsBody?.categoryBitMask = PhysicsCategory.obstacle
obstacle.physicsBody?.contactTestBitMask = PhysicsCategory.fish
obstacle.physicsBody?.collisionBitMask = PhysicsCategory.fish
obstacle.physicsBody?.usesPreciseCollisionDetection = true
self.obstacles.append(obstacle)
super.addChild(obstacle)
Please let me know if there is something I am doing wrong / misunderstanding. Thanks.
Found the answer here. One of the objects needs to have .physicsBody?.isDynamic = true. In this case I set the obstacle to false so it is stationary.
I'm trying to make a game where the sprite will always move to the right when hit by an object. However since the Sprite rotates constantly and the zero radians rotates with the Sprite causes my calculated magnitude to go the opposite direction if the sprite is facing left and hits the object. Is there a way to keep the direction of the magnitude always pointing to the right even if the zero is facing left?
// referencePoint = upper right corner of the frame
let rightTriangleFinalPoint:CGPoint = CGPoint(x: referencePoint.x, y: theSprite.position.y)
let theSpriteToReferenceDistance = distanceBetweenCGPoints(theSprite.position, b: referencePoint)
let theSpriteToFinalPointDistance = distanceBetweenCGPoints(theSprite.position, b: rightTriangleFinalPoint)
let arcCosineValue = theSpriteToFinalPointDistance / theSpriteToReferenceDistance
let angle = Double(acos(arcCosineValue))
let xMagnitude = magnitude * cos(angle)
let yMagnitude = (magnitude * sin(angle)) / 1.5
Not sure if this works for you:
I would use an orientation constraint to rotate the sprite. The movement can be done independent from the orientation in that case.
I made an tutorial some time ago: http://stefansdevplayground.blogspot.de/2014/09/howto-implement-targeting-or-follow.html
So I figured out what was going on.
It seems like the angle doesn't rotate with the Sprite like I originally thought and the vector that I am making is working with the code above. THE problem that I had was that I also set the collision bit for the objects which is wrong. If I only set the contact bit for the objects against the sprite the my desired outcome comes true.
I need to fire a "shot" from a static SKSpriteNode towards another dynamic node. I've created a shot as a sprite node as the shot and moved it to by SKAction to the main sprite node, like so:
let node = info["node"] as SKSpriteNode // The static node
let shot = SKSpriteNode(color: UIColor.blueColor(), size: CGSize(width:node.frame.width / 3, height: node.frame.height / 1.2))
shot.physicsBody = SKPhysicsBody(edgeLoopFromRect: shot.frame)
shot.position = node.position
shot.physicsBody?.categoryBitMask = shotMask
shot.physicsBody?.contactTestBitMask = spriteMask
shot.physicsBody?.collisionBitMask = 0
shot.physicsBody?.usesPreciseCollisionDetection = true
self.addChild(shot)
shot.runAction(SKAction.moveTo(sprite.position, duration: 1.0))
My problem is that the shot stops after it reaches the point. Is there a way to make the shot continue moving in it's direction, or is there another way of doing what I need? Thanks!
Don't use a SKAction to move the shot. Instead change the shot's position by directly modifying it's position.
shot.position = CGPointMake(shot.position.x+1, shot.position.y);
Run the above in your update method. To speed up the shot, change the +1 to whatever value you need. Obviously you will need to remove the shot node from parent once it leaves the screen, hits the target, etc...
You'll need to calculate the vector from the shot's origin to it's destination. Then extend the vector until the shot will be off screen, possibly by finding the unit vector (a vector of length 1) and multiplying it by 3000 or so. As you have a definite endpoint now, you could still use an SKAction.
I'm currently working on a game using Spritekit. The game has objects which spawn at the top of the screen and fall towards the player character, and the game ends when the player character collides with any of the objects. I am trying to find a way to gradually speed up gameplay over time to make the game more difficult (i.e. objects fall at normal speed when the game begins, after 5 seconds speed up 50%, after 5 more seconds speed up another 50%, ad infinitum.)
Would I need to use NSTimer to make a countdown to increase the gravity applied to the falling objects? Sorry if this is a basic thing, I'm kind of new to programming.
Thanks, Jake
EDIT:
My spawn method for enemies-
let spawn = SKAction.runBlock({() in self.spawnEnemy()})
let delay = SKAction.waitForDuration(NSTimeInterval(2.0))
let spawnThenDelay = SKAction.sequence([spawn, delay])
let spawnThenDelayForever = SKAction.repeatActionForever(spawnThenDelay)
self.runAction(spawnThenDelayForever)
And my method for making the enemies fall-
func spawnEnemy() {
let enemy = SKNode()
let x = arc4random()
fallSprite.physicsBody = SKPhysicsBody(rectangleOfSize: fallSprite.size)
fallSprite.physicsBody.dynamic = true
self.physicsWorld.gravity = CGVectorMake(0.0, -0.50)
enemy.addChild(fallSprite)
}
In spawnEnemy(), you set self.physicsWorld.gravity. Move this line to your update: method.
If you are not keeping track of the game's duration right now, you will want to implement that. You can use the parameter of the update: method to accomplish this.
You can then use the game duration to change the gravity.
For example,
override func update(currentTime: CFTimeInterval) {
if gameState == Playing{
//update "duration" using "currentTime"
self.physicsWorld.physicsBody = CGVectorMake(0.0, -0.50 * (duration / 10.0))
}
}
10.0 can be changed depending on how fast you want the gravity to increase. A higher number makes it change less drastically, and a smaller number makes the gravity increase quite rapidly.
Hopefully this answers your question.
I want to slow down the animations that are generated by my UIDynamicAnimator so that I can fine-tune my UIDynamicBehaviors.
In the ios simulator, there is a menu option under the Debug menu labeled "Toggle slow animations in frontmost app".
However, this option seems to have no effect on the animations produced by UIDynamicAnimator. Is there some other way to achieve my goal?
You could change the forces you specify in the animation to result in slower movement. For example, you could change the gravity magnitude to slow down the acceleration:
self.animator = UIDynamicAnimator(referenceView: self.view)
var gravity = UIGravityBehavior(items: [animatedView])
gravity.magnitude = 0.5
If you have collisions going on, you might also increase the friction and/or elasticity to slow things down, though in some cases this could affect trajectories:
let bounceProperties = UIDynamicItemBehavior(items: [animatedView])
bounceProperties.elasticity = 0.5
bounceProperties.friction = 0.2
var collision = UICollisionBehavior(items: [animatedView])
var boundaryId: NSMutableString = NSMutableString(string: "bottomBoundary")
let boundaryPath = UIBezierPath(rect: boundaryFrame)
collision.addBoundaryWithIdentifier(boundaryId, forPath: boundaryPath)
// Start animating
animator.addBehavior(gravity)
animator.addBehavior(collision)
animator.addBehavior(bounceProperties)