Turning Object with SkSpriteNode - sprite-kit

I have an image named "Ghost" and it moves throughout the screen. I want to have the SpriteNode constantly turning without being pressed on.
Ghost = SKSpriteNode(imageNamed: "Ghost1")
Ghost.size = CGSize(width: 50, height: 50)
Ghost.position = CGPoint(x: self.frame.width / 2 - Ghost.frame.width, y: self.frame.height / 2)
Ghost.physicsBody = SKPhysicsBody(circleOfRadius: Ghost.frame.height / 1.4)
Ghost.physicsBody?.categoryBitMask = PhysicsCatagory.Ghost
Ghost.physicsBody?.collisionBitMask = PhysicsCatagory.Ground | PhysicsCatagory.Wall
Ghost.physicsBody?.contactTestBitMask = PhysicsCatagory.Ground | PhysicsCatagory.Wall | PhysicsCatagory.Score
Ghost.physicsBody?.affectedByGravity = false
Ghost.physicsBody?.isDynamic = true
Ghost.zPosition = 2
self.addChild(Ghost)
I have looked for some answers on Stack Overflow but I can't seem to find any one with this same question, please help.

To have the SKSpriteNode constantly rotating, add this to wherever you want to start the rotating:
let rotate = SKAction.rotate(byAngle: CGFloat.pi * 2.0, duration: 2)
Ghost.run(SKAction.repeatForever(rotate), withKey: "rotateGhost")
To rotate in the opposite direction, change CGFloat.pi to -CGFloat.pi
You can fidget with the duration to change the duration for a complete rotation.
If you wish to remove the action, call:
removeAction(forKey: "rotateGhost")
Or you can just pause the action instead.

You could apply a force of an angular type, so as to rotate the body, and turn off damping so it continues to rotate forever:
https://developer.apple.com/reference/spritekit/skaction/1417775-applyangularimpulse
Or, apply torque:
Firstly, make sure it’s able to rotate by setting this to true:
https://developer.apple.com/reference/spritekit/skphysicsbody/1519986-allowsrotation
Make sure there’s no angular damping so that it doesn’t slow in rotation rate:
https://developer.apple.com/reference/spritekit/skphysicsbody/1519913-angulardamping
Now make it spin by applying a torque:
https://developer.apple.com/reference/spritekit/skphysicsbody/1519588-applytorque
Or, set a spin rate:
https://developer.apple.com/reference/spritekit/skphysicsbody/1519766-angularvelocity

Related

Fast-paced SpriteKit game has irregular CPU activity and is jittery/lags despite frame rate staying high - Swift

I'm having the issue on a simple but fast-paced SpriteKit game, but I've reduced my code just to a bouncing ball and still get the issue to a lesser extent:
override func didMove(to view: SKView) {
super.didMove(to: view)
physicsWorld.contactDelegate = self
physicsWorld.speed = 1
physicsWorld.gravity = CGVector(dx: 0.0, dy: 0.0)
let borderBody = SKPhysicsBody(edgeLoopFrom: self.frame)
borderBody.friction = 0
self.physicsBody = borderBody
borderBody.contactTestBitMask = BallCategory
addBall()
}
func addBall() {
let size = CGSize(width: 20, height: 20)
let position = CGPoint(x: frame.width / 2, y: 50)
let texture = SKTexture(image: #imageLiteral(resourceName: "whiteCircle"))
let ball = SKSpriteNode(texture: texture, size: size)
ball.position = position
ball.physicsBody = SKPhysicsBody(circleOfRadius: size.width / 2)
ball.fillColor = .white
ball.lineWidth = 0
addStandardProperties(node: ball, name: "ball", z: 5, contactTest: 0, category: BallCategory)
ball.physicsBody?.isDynamic = true
addChild(ball)
launchBall()
}
func addStandardProperties(node: SKNode, name: String, z: CGFloat, contactTest: UInt32, category: UInt32) {
node.name = name
node.zPosition = z
node.physicsBody?.isDynamic = false
node.physicsBody?.affectedByGravity = false
node.physicsBody?.mass = 0
node.physicsBody?.restitution = 1
node.physicsBody?.friction = 0
node.physicsBody?.linearDamping = 0
node.physicsBody?.angularDamping = 0
node.physicsBody?.angularVelocity = 0
node.physicsBody?.contactTestBitMask = contactTest
node.physicsBody?.categoryBitMask = category
}
func launchBall() {
let ball = childNode(withName: "ball")!
ball.physicsBody?.velocity = CGVector(dx: 0, dy: 500)
}
This code results in a ball (SKSpriteNode) bouncing up and down. When I run this, CPU usage starts at around 10% on my iPhone 6s and then after increases to around 25-30% after maybe 30-60 seconds (no idea why it's increasing). Throughout all of this, the frame rate stays very close to 60 FPS, usually going no lower than 58 FPS (it's the same way when I run the full game).
Almost any time an alert pops up (e.g., text messages, logging into Game Center, etc.), the lag shows up and shows up at random times when I'm running the full game.
I've also tried deleting and re-running the app, cleaning the project, deleting derived data and running in Release mode. None of these worked permanently.
Should I give up on SpriteKit and try another framework? If so, which? Cocos2D?
Any help is appreciated.
This is the result of Apple prioritising system calls over just about everything else.
When the system wants to know something, check something or otherwise do its thing it does so at the mercy of everything else.
No other engine will be able to help with this, there's no way to silence the system's constant activities through code.
You can get a slight improvement by putting on Flight Mode and turning off WIFI and Bluetooth. The system seems to be somewhat aware that it's in a quieter mode and does less because it's got no 4G or other connectivity it can go communicating with.
Further, there's been some pretty big changes to palm rejection in iOS 11 that's played havoc with the first round of iPad Pro models and creative software, creating multi-second rejection of all touch input. When this kind of thing can make it through to a GM you can be pretty sure they're slipping other messiness through.
Here's some complaints about iOS 11 performance: https://www.macrumors.com/2017/09/25/ios-11-app-slowdowns-performance-issues/
Turns out I had 2 SKViews in my view controller. By default, when you start a project as a SpriteKit game, Xcode sets the view controller root/superview of the GameViewController as an SKView. At some point, I had added a second SKView because I didn't intend for the scene to take up the entire screen and I apparently didn't realize that the VC root view was still set as an SKView. So every time GameViewController loaded, it was loading two SKViews, which is why I saw 120 FPS in Xcode.
I fixed the issue by simply removing the SKView class designation from the VC root view.

Swift 2: Rotating tires

Looking for a method to rotate two sprites that are tires for a car.
Tried to use RotateByAngle, but that makes the tire go out of it's position to go in a circle much bigger then the car. I want the tire to stay in the exact same position and rotate 360 degrees forever. Like a normal tire should.
let wheel = SKAction.rotateByAngle(CGFloat(M_PI), duration:1)
playerWheelleft.runAction(SKAction.repeatActionForever(wheelSpeed))
If there are better solutions to this problem then to use rotateByAngle please let me know.
The reason the tire sprite is not the center is because i use SKPhysicsJoint to connect the two tires to the rest of the car
var playerJoint = SKPhysicsJointPin.jointWithBodyA(player.physicsBody!, bodyB:playerWheelleft.physicsBody!, anchor:player.position)
self.physicsWorld.addJoint(playerJoint)
playerJoint = SKPhysicsJointPin.jointWithBodyA(player.physicsBody!, bodyB:playerWheelright.physicsBody!, anchor:player.position)
self.physicsWorld.addJoint(playerJoint)
I tried to remove the code that connects the tires with the rest of the car and then the rotation works great?
How can I make the tires the center rotation point?
let playerWheelsTexture = SKTexture(imageNamed: "playerWheel")
playerWheelleft = SKSpriteNode(texture: playerWheelsTexture)
playerWheelleft.position = CGPoint(x: CGRectGetMidX(self.frame) - 50, y: CGRectGetMidY(self.frame) - 320)
playerWheelleft.physicsBody = SKPhysicsBody(texture: playerWheelsTexture, size: playerWheelsTexture.size())
let wheelSpeed = SKAction.rotateByAngle(CGFloat(M_PI), duration:0.5)
playerWheelleft.runAction(SKAction.repeatActionForever(wheelSpeed))
playerWheelright.runAction(SKAction.repeatActionForever(wheelSpeed))

Swift : Animate SKEmitterNode

I am trying to create an explosion effect using SKEmitterNode, I followed some of this tutorial (http://www.waveworks.de/kill-your-characters-animating-explosions-with-skanimations-in-sprite-kit/), but it didn't seem to work. Here is what i have:
var superDabParticle = SKEmitterNode(fileNamed: "superDabParticle.sks")
func setUpEmiterNode(){
superDabParticle?.position = CGPoint(x: self.size.width * 0.5, y: self.size.height * 0.5)
let superDabParticleEffectNode = SKEffectNode()
superDabParticle?.zPosition = 1
superDabParticle?.setScale(0)
superDabParticleEffectNode.addChild(superDabParticle!)
self.addChild(superDabParticleEffectNode)
}
func animateEmiterNode(){
let birth = SKAction.runBlock { self.superDabParticle?.particleBirthRate = 0 }
superDabParticle!.runAction(SKAction.sequence([SKAction.waitForDuration(0.1), SKAction.scaleBy(1.5, duration: 0.1), birth]))
}
So i need to call setUpEmiterNode() when the app first launches up, then when the user taps a button, call animateEmiterNode to have the particles fly from the bottom of the screen up to about 75% of the screen, then fall back down; giving a sort of explosion under water effect. Im using the SPARK emitter effect. If you know my issue or have any other ways that are better to do this, please assist!!

Ball shot too fast the first time

I have a sprite that represents a cannon ball, and I shoot it in this method:
func shoot() {
let ball = Ball(radius: 8.0)
ball.position = CGPointMake(size.width / 2.0, 72.0)
self.addChild(ball)
// Explosion is just a simple particle system
let explosion = Explosion()
explosion.position = CGPointMake(size.width / 2.0, 64.0)
self.addChild(explosion)
let force = CGVectorMake(0.0, 20000.0)
ball.physicsBody!.applyForce(force)
}
Ball is a body with mass 1.0, created this way:
init(radius: CGFloat) {
super.init()
let path = UIBezierPath(arcCenter: CGPointZero, radius: radius, startAngle: 0.0, endAngle: 2.0 * PI, clockwise: false)
self.path = path.CGPath
self.strokeColor = SKColor.blackColor()
self.fillColor = SKColor.blackColor()
self.name = "Ball \(self)"
let body = SKPhysicsBody(circleOfRadius: radius)
body.dynamic = true
body.categoryBitMask = BallCategory
body.contactTestBitMask = EnemyCategory
body.collisionBitMask = EnemyCategory
body.mass = 1.0
body.affectedByGravity = false
physicsBody = body
}
The problem is that the first time (and only the first time) that I shoot the ball it's super-fast. All the other times they have a different, lower speed, why?
It looks like you are using applyForce in the wrong way. From the docs :
A force is applied for a length of time based on the amount of
simulation time that passes between when you apply the force and when
the next frame of the simulation is processed. So, to apply a
continuous force to an body, you need to make the appropriate method
calls each time a new frame is processed. Forces are usually used for
continuous effects
Means that you have to call applyForce: inside update: method. And from your code, it can be seen that you are not doing that (shoot() method is probably called inside touchesBegan).
Also from the docs related to applyForce method:
The acceleration is applied for a single simulation step (one frame).
About super-fast ball issue... I have a theory, but can't say for sure whats going on, especially because you are not using applyForce like its meant, which I think is the main problem.
So, here is the theory:
A time difference between each frame can vary, especially when you are starting an app and things are loading for the first time, and because force is multiplied by that time difference you are getting weird results.
On the other hand, applyImpulse: is perfect for your situation. Shooting a ball is an instantaneous action, and applyImpulse is not dependant on the simulation time like applyForce (see quote from docs I've posted).
Solution:
Use applyImpulse to shoot a ball. This is sanctioned way. If you want to move a ball with applyForce, do that through update method in each frame.
Also consider resource preloading (preloading sounds, emitters, textures) before starting an actual gameplay which will save you from fps drops when game starts.
Hope this helps!

Swift making sksprite node move faster with time

I have a sprite node that spawns in via a function:
let NBrick1 = SKSpriteNode(texture: Brick1)
NBrick1.setScale(0.04)
NBrick1.position = CGPointMake(0.0, CGFloat(y1 + bounds/2))
NBrick1.physicsBody = SKPhysicsBody(rectangleOfSize: NBrick1.size)
NBrick1.physicsBody?.dynamic = true
BrickPairs.addChild(NBrick1)
I am using this SKAction to move the bricks:
let moveBricks = SKAction.moveByX(-distanceToMove, y: 0.0, duration: NSTimeInterval(0.01 * distanceToMove))
let removeBricks = SKAction.removeFromParent()
BricksMoveAndRemove = SKAction.sequence([moveBricks,removeBricks])
I was wondering if there was a way to make the brick move faster as time goes on.
Its actually quite simply and you do not need to get involved with SKActions. The code will below will speed up the movement of a sprite, or multiple sprites, (if you apply the same code.) What it is doing is changing the position of the sprite every frame by a little bit more each time. This is the moveFactor variable. To change the start speed and rate that it speeds up, change the value that I put in.
var moveFactor:CGFloat = 0.5
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
sprite.position = CGPoint(x: sprite.position.x + moveFactor, y: sprite.position.y)
moveFactor *= 1.005
}