Swift | I am trying to rotate a sprite and change the direction of rotation when I click
I want to rotate one sprite indefinitely, and every time I press the button, I want the sprite to rotate in the opposite direction (back and forth from clockwise to counterclockwise, etc.)
Below is the code I have:
class GameScene: SKScene {
var center = SKSpriteNode()
var bg = SKSpriteNode()
var bigCircle = SKSpriteNode()
let counterClockwise = SKAction.rotateByAngle(CGFloat(3.14), duration:1)
let clockwise = SKAction.rotateByAngle(CGFloat(-3.14), duration:1)
var spin = SKAction()
override func didMoveToView(view: SKView) {
//Background
var bgTexture = SKTexture(imageNamed: "images/bg.png")
bg = SKSpriteNode(texture:bgTexture)
bg.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
self.addChild(center)
//Center Circle
var bigCircleTexture = SKTexture(imageNamed: "images/bigCircle.png")
bigCircle = SKSpriteNode(texture:bigCircleTexture)
bigCircle.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
self.addChild(bigCircle)
//Center Triangle
var centerTexture = SKTexture(imageNamed: "images/center.png")
center = SKSpriteNode(texture:centerTexture)
center.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
self.addChild(center)
spin = clockwise
center.runAction(SKAction.repeatActionForever(spin))
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
if spin == clockwise {
spin = counterClockwise
}
else {
spin = clockwise
}
center.runAction(SKAction.repeatActionForever(spin))
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
source to share
Your problem is that you are not deleting the old SKAction
one trying to rotate yours SKSpriteNode
. To do this, you need to keep track of how your sprite rotates. If I was going to implement this, I would subclass SKSpriteNode
, for example:
class RotatingSprite: SKSpriteNode {
// This is used to keep track of which way the sprite is rotating.
enum Direction {
case Left, Right
mutating func inverse() {
switch self {
case .Left : self = .Right
case .Right: self = .Left
}
}
}
// These names will be the keys used when running an action.
// This will allow you to stop the rotate-left or rotate-right actions.
static let rotateLeftName = "RotateLeftAction"
static let rotateRightName = "RotateRightAction"
var rotationDirection: Direction? {
didSet {
if let r = rotationDirection {
switch r {
// Checks the sprite isn't already rotating to the left.
// If it isn't, make the sprite rotate to the left.
case .Left where oldValue != .Left:
rotateLeft()
case .Right where oldValue != .Right:
rotateRight()
default:
break
}
}
}
}
private func rotateLeft() {
// Remove the action rotating the sprite to the right.
self.removeActionForKey(RotatingSprite.rotateRightName)
// And start the action rotating the sprite to the left.
let rotateAction = SKAction.rotateByAngle(-CGFloat(M_PI), duration: 1.0)
self.runAction(SKAction.repeatActionForever(rotateAction), withKey: RotatingSprite.rotateLeftName)
}
private func rotateRight() {
self.removeActionForKey(RotatingSprite.rotateLeftName)
let rotateAction = SKAction.rotateByAngle(CGFloat(M_PI), duration: 1.0)
self.runAction(SKAction.repeatActionForever(rotateAction), withKey: RotatingSprite.rotateRightName)
}
}
Now you can use RotatingSprite
like this:
class GameScene: SKScene {
let rotatingSprite = RotatingSprite(texture:bgTexture)
override func didMoveToView(view: SKView) {
rotatingSprite.position = CGPoint(x: frame.midX, y: frame.midY)
self.addChild(rotatingSprite)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
// If the sprite isn't turning you've got to set it off.
if rotatingSprite.rotationDirection == nil {
rotatingSprite.rotationDirection = .Left
// If it is turning, change its direction.
} else {
rotatingSprite.rotationDirection!.inverse()
}
}
}
Hope it helps!
source to share
This is very easy to achieve. Try it,
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
[sprite removeAllActions];
SKAction *action;
if (isClockWise)
{
action = [SKAction rotateByAngle:M_PI duration:1];
}
else
{
action = [SKAction rotateByAngle:-M_PI duration:1];
}
isClockWise = !isClockWise;
[sprite runAction:[SKAction repeatActionForever:action]];
}
Where sprite is SKSpriteNode and will initiate isClockWise for yes or no depending on your starting direction.
source to share
A quick and dirty way to do it:
import SpriteKit
class GameScene: SKScene {
var center = SKSpriteNode()
var bg = SKSpriteNode()
var bigCircle = SKSpriteNode()
let counterClockwise = SKAction.rotateByAngle(CGFloat(3.14), duration:1)
let clockwise = SKAction.rotateByAngle(CGFloat(-3.14), duration:1)
var spin = SKAction()
// this is used to identify which direction we are going in. When we change it spin is changed as well
var isClockwise: Bool = true {
didSet {
if isClockwise {
spin = clockwise
} else {
spin = counterClockwise
}
}
}
let actionKey = "spin" // this is used to identify the SKAction
override func didMoveToView(view: SKView) {
//Background
var bgTexture = SKTexture(imageNamed: "images/bg.png")
bg = SKSpriteNode(texture:bgTexture)
bg.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
self.addChild(center)
//Center Circle
var bigCircleTexture = SKTexture(imageNamed: "images/bigCircle.png")
bigCircle = SKSpriteNode(texture:bigCircleTexture)
bigCircle.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
self.addChild(bigCircle)
//Center Triangle
var centerTexture = SKTexture(imageNamed: "images/center.png")
center = SKSpriteNode(texture:centerTexture)
center.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
self.addChild(center)
isClockwise = true // set the initial direction to clockwise
center.runAction(SKAction.repeatActionForever(spin), withKey: actionKey)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
// remove the existing spin action
center.removeActionForKey(actionKey)
// reset the direction (this will automatically switch the SKAction)
isClockwise = !isClockwise
center.runAction(SKAction.repeatActionForever(spin), withKey: actionKey)
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
You need to remove the action before applying the new one - you can selectively remove the action by calling runAction (action :, withKey :). This allows you to remove the same action using the same key. Change logic spin
is in didSet
for isClockwise
var declaration .
source to share