How do you update something in an SKAction while using repeat repeatForever? - ios

As you'll see below, I'm trying to update the durationNumber, so that the colorSwitch object turns faster. The durationNumber does update, but colorSwitch doesn't rotate faster. How do I accomplish this?
func turnWheel() {
var durationNumber = 2.0
let rotateAction = SKAction.rotate(byAngle: .pi/2, duration: durationNumber)
let switchAction = SKAction.run {
if let newState = SwitchState(rawValue: self.switchState.rawValue + 1) {
self.switchState = newState
} else {
self.switchState = .green
}
if self.score > self.scoreCheck {
self.scoreCheck += 1
durationNumber *= 0.5
}
}
colorSwitch.run(SKAction.repeatForever(SKAction.sequence([rotateAction, switchAction])))
}

You're changing the value of the local variable, but not changing the SKAction object itself. You need to change rotateAction.duration to have any effect on the action itself.
if self.score > self.scoreCheck {
self.scoreCheck += 1
durationNumber *= 0.5
rotateAction.duration = durationNumber
}

Do not update your duration, instead update your speed
func turnWheel() {
var durationNumber = 2.0
let rotateAction = SKAction.rotate(byAngle: .pi/2, duration: durationNumber)
let switchAction = SKAction.run {
if let newState = SwitchState(rawValue: self.switchState.rawValue + 1) {
self.switchState = newState
} else {
self.switchState = .green
}
if self.score > self.scoreCheck {
self.scoreCheck += 1
colorSwitch.speed *= 2
}
}
colorSwitch.run(SKAction.repeatForever(SKAction.sequence([rotateAction, switchAction])))
}

Related

SceneKit. Place nodes in one "surface"

The users draw a line on drawing views and then I need to translate these points into 3d world, but place these points in one "surface". For this, I map the array of points into vectors (I use hitTest with .featurePoint) and then filter this array for the further one
func didEndDrawing(with points: [CGPoint]) {
guard let transform = sceneView.pointOfView?.transform else { return }
let cameraVectror = SCNVector3(transform.m31, transform.m32, transform.m33)
let farthestVector = points
.reduce((vector: SCNVector3(0, 0, 0), distance: CGFloat.zero)) { result, point in
guard let vector = getVector(for: point) else { return result }
let distance: CGFloat = cameraVectror.distance(to: vector)
return distance > result.distance ? (vector, distance) : result
}
.vector
}
let parentNode = SCNNode()
parentNode.position = farthestVector
How can I adjust coordinates (I guess z position) to have all the child nodes at the same distance from the point of view?
The idea of the app is freehand drawing in AR.
Update
With Voltan's help I was able to solve it
points.forEach { point in
let scenePoint = sceneView.unprojectPoint(SCNVector3(point.x, point.y, CGFloat(projectedPoint.z)))
let sphere = SCNSphere(radius: 0.01)
let material = SCNMaterial()
material.diffuse.contents = UIColor.green
sphere.materials = [material]
let node = SCNNode(geometry: sphere)
node.position = scenePoint
sceneView.scene.rootNode.addChildNode(node)
}
If I'm understanding correctly, you want some kind of tap/drag combination - get the points from the 2D world and translate to a 3D world. This is some game code for a missile command type game, maybe it will help you with unprojectPoint stuff. There are some timers that aren't included, but hopefully you will get the idea.
#objc func handleTap(recognizer: UITapGestureRecognizer)
{
if(data.gameState == .endGame)
{
endGameAnimates.stop()
let _ = Timer.scheduledTimer(withTimeInterval: 1, repeats: false, block: { _ in self.dismiss(animated: false, completion: nil) })
return
}
if(gameControl.isWaveComplete == true || gNodes.gameNodes.isPaused == true) { return }
currentLocation = recognizer.location(in: gameScene)
let projectedPoint = gameScene.projectPoint(SCNVector3(0, 0, 0))
let scenePoint = gameScene.unprojectPoint(SCNVector3(currentLocation.x, currentLocation.y, CGFloat(projectedPoint.z)))
if(data.gameState == .endGame) // Allow animations to finish, otherwise they will show up next round
{
DispatchQueue.main.async { self.endGameAnimates.stop() }
let _ = Timer.scheduledTimer(withTimeInterval: 1, repeats: false, block: { _ in self.dismiss(animated: false, completion: nil) })
return
}
if(data.missilesAvailable <= 0)
{
sound.playSoundType(vSoundType: .defenseFails)
hudControl.notify()
}
else
{
gameControl.defenseMissileShoot(vPosition: scenePoint, soundType: 0)
sound.playSoundType(vSoundType: .defenseFires)
}
}
//**************************************************************************
#objc func handlePan(recognizer: UIPanGestureRecognizer)
{
currentLocation = recognizer.location(in: gameScene)
let projectedPoint = gameScene.projectPoint(SCNVector3(0, 0, 0))
let scenePoint = gameScene.unprojectPoint(SCNVector3(currentLocation.x, currentLocation.y, CGFloat(projectedPoint.z)))
if(gameControl.isWaveComplete == true || gNodes.gameNodes.isPaused == true) { return }
switch recognizer.state
{
case UIGestureRecognizer.State.began:
gameControl.defenseMissileShoot(vPosition: scenePoint, soundType: 1)
SNDdefenseSoundCount = 0
if(data.missilesAvailable <= 0) { sound.playSoundType(vSoundType: .defenseFails); hudControl.notify() }
beginLocation.x = currentLocation.x
break
case UIGestureRecognizer.State.changed:
if(currentLocation.x > beginLocation.x + dragDistance)
{
beginLocation.x = currentLocation.x
if(data.missilesAvailable > 0) { gameControl.defenseMissileShoot(vPosition: scenePoint, soundType: 2) }
SNDdefenseSoundCount += 1
}
if(currentLocation.x < beginLocation.x - dragDistance)
{
beginLocation.x = currentLocation.x
if(data.missilesAvailable > 0) { gameControl.defenseMissileShoot(vPosition: scenePoint, soundType: 2) }
SNDdefenseSoundCount += 1
}
break
case UIGestureRecognizer.State.ended:
if(data.missilesAvailable > 0)
{
if(SNDdefenseSoundCount < 2) { sound.playSoundType(vSoundType: .defenseFires) }
else { sound.playSoundType(vSoundType: .defensePans) }
}
break
default:
break
}

How can I create an onscreen controller that works in multiple scenes in SpriteKit?

Working on a game in SpriteKit to learn. Its a platformer with an onscreen controller. I have this all working using touchesBegan and touchesEnded to know when the player is pushing the buttons or not. This works fine, however when i want to load the next scene for 'level 2' i need to implement the controller all over again. I could do a lot of copy and pasting but I feel this will lead to a lot of duplication of code. Every tutorial I've ever read said to try to adhere to the DRY principle.
Im sorry if this is simple, but I have <6 months programming experience and am trying to learn and improve. Im assuming I would need to create a separate class for the onscreen controller so it can be reused, but Im a little lost on where to start.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let location = (touch.location(in: playerCamera))
print("LocationX: \(location.x), LocationY: \(location.y)")
let objects = nodes(at: location)
print("\(objects)")
if rightButton.frame.contains(location) {
rightButtonPressed = true
playerFacingRight = true
playerFacingLeft = false
thePlayer.xScale = 1
let animation = SKAction(named: "running")!
let loopingAnimation = SKAction.repeatForever(animation)
thePlayer.run(loopingAnimation, withKey: "moveRight")
moveRight()
} else if leftButton.frame.contains(location) {
leftButtonPressed = true
playerFacingLeft = true
playerFacingRight = false
thePlayer.xScale = -1
let leftAnimation = SKAction(named: "running")!
let leftLoopingAnimation = SKAction.repeatForever(leftAnimation)
thePlayer.run(leftLoopingAnimation, withKey: "moveLeft")
moveLeft()
} else if upButton.frame.contains(location) {
upButtonPressed = true
print("upButton is pressed")
if playerAndButtonContact == true {
print("contact - player + button + upButtonPressed=true")
print("\(movingPlatform.position)")
button.texture = SKTexture(imageNamed: "switchGreen")
let moveRight = SKAction.moveTo(x: -150, duration: 3)
if movingPlatform.position == CGPoint(x: -355, y: movingPlatform.position.y) {
movingPlatform.run(moveRight)
thePlayer.run(moveRight)
button.run(moveRight)
}
}
if playerAndDoorSwitchContact == true {
let switchPressed = SKAction.run{
self.switchPressedSound()
self.doorSwitch.texture = SKTexture(imageNamed: "switchGreen")
self.door.texture = SKTexture(imageNamed: "DoorUnlocked")
}
let wait = SKAction.wait(forDuration: 2)
let doorOpen = SKAction.run {
let doorOpen = SKSpriteNode(imageNamed: "DoorOpen")
doorOpen.alpha = 0
doorOpen.position = self.door.position
doorOpen.size = self.door.size
doorOpen.size = self.door.size
self.door.zPosition = -2
doorOpen.zPosition = -1
let fadeIn = SKAction.fadeIn(withDuration: 0.5)
let start = SKAction.run {
self.addChild(doorOpen)
doorOpen.run(fadeIn)
}
let sound = SKAction.run {
self.doorOpeningSound()
}
let opening = SKAction.group([sound, start])
self.door.run(opening)
}
let sequence = SKAction.sequence([switchPressed, wait, doorOpen])
self.doorSwitch.run(sequence)
}
if playerAndDoorContact == true {
self.view?.presentScene(level1, transition: transition)
}
} else if downButton.frame.contains(location) {
}
else if shoot.frame.contains(location) {
shoot()
} else if jumpButton.frame.contains(location) {
self.pressed = true
let timerAction = SKAction.wait(forDuration: 0.05)
let update = SKAction.run {
if(self.force < Constants.maximumJumpForce) {
self.force += 2.0
} else {
self.jump(force: Constants.maximumJumpForce)
self.force = Constants.maximumJumpForce
}
}
let sequence = SKAction.sequence([timerAction, update])
let repeat_seq = SKAction.repeatForever(sequence)
self.run(repeat_seq, withKey: "repeatAction")
}
}
}

Get Index on UIslider

I have radar chart with data.I want to give index for slider Based on data count.If i am moving slider the graph value should move.If suppose i am at bellow of middle value slider thumb should go to near index.
for _ in 0..<3 {
let mind = arc4random_uniform(mult) + min
let bre = arc4random_uniform(mult) + min
let rel = arc4random_uniform(mult) + min
dataPoints.append(GraphDataPoints(mindfulness: Double(mind), breathing: Double(bre), relaxation: Double(rel)))
}
self.setChartData(mindfulness: dataPoints[0].mindfulness, breathing: dataPoints[0].breathing, relaxation: dataPoints[0].relaxation)
numberofPointsOnSlider = Float(100 / (dataPoints.count - 1))
numberofPointsOnSlider is percent to move.In lastSliderValue i am storing the slider value.pointIndex have index.
#objc func sliderTouchEvents(slider:UISlider,event: UIEvent){
slider.isContinuous = true
if let touchEvent = event.allTouches?.first{
switch touchEvent.phase{
case .began:
lastSliderValue = slider.value
break
case .moved:
if slider.value.truncatingRemainder(dividingBy: numberofPointsOnSlider) == 0{
if lastSliderValue < slider.value || lastSliderValue > slider.value{
pointIndex = Int(slider.value / numberofPointsOnSlider)
self.isIncrement = false
}
lastSliderValue = slider.value
}
if !animation {
if pointIndex >= 0 && pointIndex < dataPoints.count {
var percentToMove:Float = 0
if lastSliderValue > slider.value && pointIndex > 0 {
percentToMove = (100 * (numberofPointsOnSlider - (slider.value.truncatingRemainder(dividingBy: numberofPointsOnSlider) ))) / numberofPointsOnSlider
mindfulDiff = Float(dataPoints[pointIndex].mindfulness - dataPoints[pointIndex - 1].mindfulness)
relaxationDiff = Float(dataPoints[pointIndex].relaxation - dataPoints[pointIndex - 1].relaxation)
breathingDiff = Float(dataPoints[pointIndex].breathing - dataPoints[pointIndex - 1].breathing)
}else if lastSliderValue < slider.value && pointIndex < dataPoints.count - 1 {
percentToMove = (100 * (slider.value.truncatingRemainder(dividingBy: numberofPointsOnSlider) )) / numberofPointsOnSlider
mindfulDiff = Float(dataPoints[pointIndex].mindfulness - dataPoints[pointIndex + 1].mindfulness)
relaxationDiff = Float(dataPoints[pointIndex].relaxation - dataPoints[pointIndex + 1].relaxation)
breathingDiff = Float(dataPoints[pointIndex].breathing - dataPoints[pointIndex + 1].breathing)
}
mp = Float(dataPoints[pointIndex].mindfulness) - (mindfulDiff / 100 ) * percentToMove
rp = Float(dataPoints[pointIndex].relaxation) - (relaxationDiff / 100 ) * percentToMove
bp = Float(dataPoints[pointIndex].breathing) - (breathingDiff / 100) * percentToMove
UIView.animate(withDuration: 10, animations: {
self.setChartData(mindfulness: Double(self.mp) , breathing: Double(self.bp) , relaxation: Double(self.rp) )
})
}
else {
if (pointIndex < 0) {
pointIndex = 0
}
}
}
break
case .ended:
let progDiff = lastSliderValue - slider.value
print("End movie, \(pointIndex) , \(slider.value) ,progDiff: \(progDiff)")
if progDiff < 0{
if (progDiff * -1) >= numberofPointsOnSlider / 2 {
animation = true
UIView.animate(withDuration: 10, animations: {
slider.value += self.numberofPointsOnSlider + progDiff
})
pointIndex = Int(slider.value / numberofPointsOnSlider)+1
// if isIncrement {
// pointIndex += pointIndex
// }else {
// isIncrement = true
//
// }
mindfulDiff = Float(dataPoints[pointIndex].mindfulness - Double(mp))
relaxationDiff = Float(dataPoints[pointIndex].relaxation - Double(rp))
breathingDiff = Float(dataPoints[pointIndex].breathing - Double(bp))
doGraphAnimate()
}else {
animation = true
UIView.animate(withDuration: 10, animations: {
slider.value = self.lastSliderValue
})
mindfulDiff = Float(dataPoints[pointIndex].mindfulness - Double(mp))
relaxationDiff = Float(dataPoints[pointIndex].relaxation - Double(rp))
breathingDiff = Float(dataPoints[pointIndex].breathing - Double(bp))
doGraphAnimate()
}
}else if progDiff > 0{
if progDiff >= numberofPointsOnSlider / 2 {
animation = true
// if isIncrement {
// print("pointIndex : \(pointIndex)")
// pointIndex += pointIndex
// print("pointIndex Incremented : \(pointIndex)")
// }else{
// isIncrement = true
// }
pointIndex = Int(slider.value / numberofPointsOnSlider)
UIView.animate(withDuration: 10, animations: {
slider.value -= self.numberofPointsOnSlider - (self.lastSliderValue - slider.value)
})
mindfulDiff = Float(dataPoints[pointIndex].mindfulness - Double(mp))
relaxationDiff = Float(dataPoints[pointIndex].relaxation - Double(rp))
breathingDiff = Float(dataPoints[pointIndex].breathing - Double(bp))
doGraphAnimate()
}
else {
animation = true
UIView.animate(withDuration: 10, animations: {
slider.value = self.lastSliderValue
})
mindfulDiff = Float(dataPoints[pointIndex].mindfulness - Double(mp))
relaxationDiff = Float(dataPoints[pointIndex].relaxation - Double(rp))
breathingDiff = Float(dataPoints[pointIndex].breathing - Double(bp))
doGraphAnimate()
}
}
default :
break
}
}
}
Help me, Thankyou .
DO you mean you want slider to move only at certain discrete positions when you move it ? But your spec is not totally clear.
If so, this is how I, so that if slider moves from 0 to 14 it will show 14, from 15 to 85, it will show 85. I let you adapt to get the exact working you want.
I use this IBAction for the slider
#IBAction fileprivate func changeRowSlider(_ sender: NSSlider) {
let movedPosition = Int(sender.doubleValue)
if movedPosition == 0 {
sender.integerValue = 0
return
}
if movedPosition <= 14 {
sender.integerValue = 14
return
}
if movedPosition <= 85 {
sender.integerValue = 85
return
}
sender.integerValue = 100 // last case: move to maxValue
}

how to add a delay when you tap when firing a bullet on my game

i need help on this issue, in my game when a node is tapped a bullet is fired, but the problem is that i can tap continually and a lot of bullets fire, i would like to add some kind of delay to the shot.
here is my touches began code
for touch: AnyObject in touches{
let pointOfTouch = touch.location(in:self)
if player1.contains(pointOfTouch) {
fireBullet1()
}
if player2.contains(pointOfTouch) {
fireBullet2()
}
if player3.contains(pointOfTouch) {
fireBullet3()
}
}
}
}
func fireBullet1() {
let bullet = SKSpriteNode(imageNamed: "b")
bullet.position = player1.position
bullet.zPosition = 1
self.addChild(bullet)
let moveBullet = SKAction.moveTo(y: self.size.height + bullet.size.height, duration: 1)
let deleteBullet = SKAction.removeFromParent()
let bulletSequence = SKAction.sequence([moveBullet, deleteBullet])
bullet.run(bulletSequence)
}
func fireBullet2 () {
let bullet2 = SKSpriteNode(imageNamed: "b")
bullet2.position = player2.position
bullet2.zPosition = 1
self.addChild(bullet2)
let moveBullet = SKAction.moveTo(y: self.size.height + bullet2.size.height, duration: 1)
let deleteBullet = SKAction.removeFromParent()
let bulletSequence = SKAction.sequence([moveBullet, deleteBullet])
bullet2.run(bulletSequence)
}
func fireBullet3() {
let bullet3 = SKSpriteNode(imageNamed: "b")
bullet3.position = player3.position
bullet3.zPosition = 1
self.addChild(bullet3)
let moveBullet = SKAction.moveTo(y: self.size.height + bullet3.size.height, duration: 1)
let deleteBullet = SKAction.removeFromParent()
let bulletSequence = SKAction.sequence([moveBullet, deleteBullet])
bullet3.run(bulletSequence)
}
Declare flags to disable multiple firing immediatly
let minFireDelay = 0.5
var allowsFire1 = true
var allowsFire2 = true
var allowsFire3 = true
Update touches began
for touch: AnyObject in touches {
let pointOfTouch = touch.location(in:self)
if allowsFire1 && player1.contains(pointOfTouch) {
fireBullet1()
// disable firing temporarily
allowsFire1 = false
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + minFireDelay) {
allowsFire1 = true
}
}
if allowsFire2 && player2.contains(pointOfTouch) {
fireBullet2()
// disable firing temporarily
allowsFire2 = false
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + minFireDelay) {
allowsFire2 = true
}
}
if allowsFire3 && player3.contains(pointOfTouch) {
fireBullet3()
// disable firing temporarily
allowsFire3 = false
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + minFireDelay) {
allowsFire3 = true
}
}
}
Look up Timer (NSTimer in Swift 2 and Objective-C.)
The idea is as follows:
Have a gunXEnabled Bool for each player's gun. Set each Bool to true initially.
Have your fireBullet1() method check gun1Enabled. If false, do nothing.
If gun1Enabled == true, fire the gun, set gun1Enabled = false, and start a timer that will re-enable the gun once it fires:
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) {
(timer) -> Void) in
gun1Enabled = true
}
I gave you the unfamiliar part, creating the timer. See if you can work out the rest, and if not, post your code with info about what's not working.

ios Swift - Group separated sprites with syncronized animation

I am trying to make a synchronized animation (a large video decomposed by frames on separated and smaller puzzle jigsaw parts). This game is a video puzzle. Here is the code I use in three parts by way of example:
func Anim_Puzzle13 (Node13 : SKPuzzle) {
let puzzle13 = SKAction.animateWithTextures(sheet_puzzle13.Puzzle13_(), timePerFrame: 0.066)
NPuzzle13 = Node13
NPuzzle13.runAction(SKAction.repeatActionForever(puzzle13))
NPuzzle13.position = CGPoint(x: 500, y: 400)
NPuzzle13.zPosition = 1
}
func Anim_Puzzle19 (Node19 : SKPuzzle) {
let puzzle19 = SKAction.animateWithTextures(sheet_puzzle19.Puzzle19_(), timePerFrame: 0.066)
NPuzzle19 = Node19
NPuzzle19.runAction(SKAction.repeatActionForever(puzzle19))
NPuzzle19.position = CGPoint(x: 600, y: 500)
NPuzzle19.zPosition = 1
}
func Anim_Puzzle30 (Node30 : SKPuzzle) {
let puzzle30 = SKAction.animateWithTextures(sheet_puzzle30.Puzzle30_(), timePerFrame: 0.066)
NPuzzle30 = Node30
NPuzzle30.runAction(SKAction.repeatActionForever(puzzle30))
NPuzzle30.position = CGPoint(x: 700, y: 600)
NPuzzle30.zPosition = 1
}
It works well but it does not synchronize between the animations and the video has no integrity. I searched for a long time for a solution to make the animations synchronize; I see two possibilities: first is to create a unique SKNode() with all the jigsaw parts inside, but I want to be able to move each jigsaw part independently and have had no success getting a synchronized animation with this method.
The other way seem to be to create a group with all the animations together but this doesn't work, and causes the application to stop.
Here is all the code I use:
import SpriteKit
import UIKit
import AVFoundation
import AVKit
import CoreFoundation
private let kpuzzleNodeName = "puzzle"
private let kdancing = "dancing"
class SKPuzzle: SKSpriteNode {
var name2:String = "";
}
class GameScene: SKScene {
var background = SKVideoNode(videoFileNamed: "Video_Socle.mov")
var selectedNode = SKPuzzle()
var player:AVPlayer?
var videoNode:SKVideoNode?
var NPuzzle13 = SKPuzzle()
var NPuzzle19 = SKPuzzle()
var NPuzzle30 = SKPuzzle()
var NPuzzle11 = SKPuzzle()
var NPuzzle29 = SKPuzzle()
var NPuzzle35 = SKPuzzle()
var puzzle13 = SKAction()
var puzzle19 = SKAction()
var puzzle30 = SKAction()
var puzzle11 = SKAction()
var puzzle29 = SKAction()
var puzzle35 = SKAction()
let sheet_puzzle13 = Puzzle13()
let sheet_puzzle19 = Puzzle19()
let sheet_puzzle30 = Puzzle30()
let sheet_puzzle11 = Puzzle11()
let sheet_puzzle29 = Puzzle29()
let sheet_puzzle35 = Puzzle35()
override init(size: CGSize) {
super.init(size: size)
// 1
self.background.name = kdancing
self.background.anchorPoint = CGPointZero
background.zPosition = 0
self.addChild(background)
// 2
let sheet = Statiques()
let sprite_dancing1 = SKSpriteNode(texture: sheet.Dancing1())
let sprite_dancing2 = SKSpriteNode(texture: sheet.Dancing2())
sprite_dancing1.name = kdancing
sprite_dancing2.name = kdancing
sprite_dancing1.position = CGPoint(x: 837, y: 752)
sprite_dancing1.zPosition = 2
sprite_dancing2.position = CGPoint(x: 1241, y: 752)
sprite_dancing2.zPosition = 2
background.addChild(sprite_dancing1)
background.addChild(sprite_dancing2)
let imageNames = [sheet.Puzzle13() , sheet.Puzzle19(), sheet.Puzzle30(), sheet.Puzzle11(), sheet.Puzzle29(), sheet.Puzzle35() ]
for i in 0..<imageNames.count {
let imageName = imageNames[i]
let sprite = SKPuzzle(texture: imageName)
sprite.name = kpuzzleNodeName
sprite.name2 = "\(i)"
let offsetFraction = (CGFloat(i) + 1.0)/(CGFloat(imageNames.count) + 1.0)
sprite.position = CGPoint(x: size.width * offsetFraction, y: size.height / 2)
sprite.zPosition = 3
background.addChild(sprite)
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch: AnyObject in touches {
let positionInScene = touch.locationInNode(self)
selectNodeForTouch(positionInScene)
}
}
override func didMoveToView(view: SKView) {
let urlStr = NSBundle.mainBundle().pathForResource("Video_Socle", ofType: "mov")
let url = NSURL(fileURLWithPath: urlStr!)
player = AVPlayer(URL: url)
NSNotificationCenter.defaultCenter().addObserverForName(AVPlayerItemDidPlayToEndTimeNotification, object: player!.currentItem, queue: nil)
{ notification in
let t1 = CMTimeMake(5, 100);
self.player!.seekToTime(t1)
self.player!.play()
}
videoNode = SKVideoNode(AVPlayer: player!)
videoNode!.position = CGPointMake(frame.size.width/2, frame.size.height/2)
videoNode!.size = CGSize(width: 2048, height: 1536)
videoNode!.zPosition = 0
background.addChild(videoNode!)
videoNode!.play()
let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(GameScene.handlePanFrom(_:)))
self.view!.addGestureRecognizer(gestureRecognizer)
}
func handlePanFrom(recognizer : UIPanGestureRecognizer) {
if recognizer.state == .Began {
var touchLocation = recognizer.locationInView(recognizer.view)
touchLocation = self.convertPointFromView(touchLocation)
self.selectNodeForTouch(touchLocation)
} else if recognizer.state == .Changed {
var translation = recognizer.translationInView(recognizer.view!)
translation = CGPoint(x: translation.x, y: -translation.y)
self.panForTranslation(translation)
recognizer.setTranslation(CGPointZero, inView: recognizer.view)
} else if recognizer.state == .Ended {
}
}
func degToRad(degree: Double) -> CGFloat {
return CGFloat(degree / 180.0 * M_PI)
}
func selectNodeForTouch(touchLocation : CGPoint) {
// 1
let touchedNode = self.nodeAtPoint(touchLocation)
if touchedNode is SKPuzzle {
// 2
if !selectedNode.isEqual(touchedNode) {
selectedNode.runAction(SKAction.rotateToAngle(0.0, duration: 0.1))
selectedNode = touchedNode as! SKPuzzle
// 3
if touchedNode.name! == kpuzzleNodeName {
let sequence = SKAction.sequence([SKAction.rotateByAngle(degToRad(-4.0), duration: 0.1),
SKAction.rotateByAngle(0.0, duration: 0.1),
SKAction.rotateByAngle(degToRad(4.0), duration: 0.1)])
selectedNode.runAction(SKAction.repeatActionForever(sequence))
}
}
}
}
func panForTranslation(translation : CGPoint) {
let position = selectedNode.position
if selectedNode.name! == kpuzzleNodeName {
selectedNode.position = CGPoint(x: position.x + translation.x * 2, y: position.y + translation.y * 2)
print (selectedNode.name)
print (selectedNode.name2)
if selectedNode.name2 == "0" {
Anim_Puzzle13(selectedNode)
}
print (selectedNode.name2)
if selectedNode.name2 == "1" {
Anim_Puzzle19(selectedNode)
}
print (selectedNode.name2)
if selectedNode.name2 == "2" {
Anim_Puzzle30(selectedNode)
}
print (selectedNode.name2)
if selectedNode.name2 == "3" {
Anim_Puzzle11(selectedNode)
}
print (selectedNode.name2)
if selectedNode.name2 == "4" {
Anim_Puzzle29(selectedNode)
}
print (selectedNode.name2)
if selectedNode.name2 == "5" {
Anim_Puzzle35(selectedNode)
}
}
}
func Anim_Puzzle13 (Node13 : SKPuzzle) {
let puzzle13 = SKAction.animateWithTextures(sheet_puzzle13.Puzzle13_(), timePerFrame: 0.066)
NPuzzle13 = Node13
NPuzzle13.runAction(SKAction.repeatActionForever(puzzle13))
NPuzzle13.position = CGPoint(x: 500, y: 400)
NPuzzle13.zPosition = 1
}
func Anim_Puzzle19 (Node19 : SKPuzzle) {
let puzzle19 = SKAction.animateWithTextures(sheet_puzzle19.Puzzle19_(), timePerFrame: 0.066)
NPuzzle19 = Node19
NPuzzle19.runAction(SKAction.repeatActionForever(puzzle19))
NPuzzle19.position = CGPoint(x: 600, y: 500)
NPuzzle19.zPosition = 1
}
func Anim_Puzzle30 (Node30 : SKPuzzle) {
let puzzle30 = SKAction.animateWithTextures(sheet_puzzle30.Puzzle30_(), timePerFrame: 0.066)
NPuzzle30 = Node30
NPuzzle30.runAction(SKAction.repeatActionForever(puzzle30))
NPuzzle30.position = CGPoint(x: 700, y: 600)
NPuzzle30.zPosition = 1
}
func Anim_Puzzle11 (Node11 : SKPuzzle) {
let puzzle11 = SKAction.animateWithTextures(sheet_puzzle11.Puzzle11_(), timePerFrame: 0.066)
NPuzzle11 = Node11
NPuzzle11.runAction(SKAction.repeatActionForever(puzzle11))
NPuzzle11.position = CGPoint(x: 800, y: 700)
NPuzzle11.zPosition = 1
}
func Anim_Puzzle29 (Node29 : SKPuzzle) {
let puzzle29 = SKAction.animateWithTextures(sheet_puzzle29.Puzzle29_(), timePerFrame: 0.066)
NPuzzle29 = Node29
NPuzzle29.runAction(SKAction.repeatActionForever(puzzle29))
NPuzzle29.position = CGPoint(x: 900, y: 800)
NPuzzle29.zPosition = 1
}
func Anim_Puzzle35 (Node35 : SKPuzzle) {
let puzzle35 = SKAction.animateWithTextures(sheet_puzzle35.Puzzle35_(), timePerFrame: 0.066)
NPuzzle35 = Node35
NPuzzle35.runAction(SKAction.repeatActionForever(puzzle35))
NPuzzle35.position = CGPoint(x: 1000, y: 900)
NPuzzle35.zPosition = 1
}
}
I'm not sure if it's possible to synchronize animations like this: with SKAction() in several separated parts, because it's necessary to be able to select them individually.
UPDATE: I've tried to follow the action group way but I have the same animation playing on each sprite instead of a different animation synchronized for each sprite (6 different animations synchronized: 6 different sprites):
let sheet13 = Puzzle13()
let sheet19 = Puzzle19()
let sheet30 = Puzzle30()
let sheet11 = Puzzle11()
let sheet29 = Puzzle29()
let sheet35 = Puzzle35()
let imageAnims = [sheet13.Puzzle13_0000() , sheet19.Puzzle19_0000(), sheet30.Puzzle30_0000(), sheet11.Puzzle11_0000(), sheet29.Puzzle29_0000(), sheet35.Puzzle35_0000() ]
let puzzle13 = SKAction.animateWithTextures(sheet13.Puzzle13_(), timePerFrame: 0.066)
let puzzle19 = SKAction.animateWithTextures(sheet19.Puzzle19_(), timePerFrame: 0.066)
let puzzle30 = SKAction.animateWithTextures(sheet30.Puzzle30_(), timePerFrame: 0.066)
let puzzle11 = SKAction.animateWithTextures(sheet11.Puzzle11_(), timePerFrame: 0.066)
let puzzle29 = SKAction.animateWithTextures(sheet29.Puzzle29_(), timePerFrame: 0.066)
let puzzle35 = SKAction.animateWithTextures(sheet35.Puzzle35_(), timePerFrame: 0.066)
let group = SKAction.group([puzzle13,puzzle19,puzzle30,puzzle11,puzzle29,puzzle35])
for i in 0..<imageAnims.count {
let imageAnim = imageAnims[i]
let spriteAnim = SKPuzzle(texture: imageAnim)
spriteAnim.name = kanimNodeName
spriteAnim.name2 = "\(i)"
let offsetFraction = (CGFloat(i) + 1.0)/(CGFloat(imageAnims.count) + 1.0)
spriteAnim.position = CGPoint(x: ((size.width)*2) * offsetFraction, y: size.height * 1.5)
spriteAnim.zPosition = 3
spriteAnim.runAction(SKAction.repeatActionForever(group))
background.addChild(spriteAnim)
}
First of all I want to list two differents method to create your SKAction:
Starting with parallel actions by using SKAction.group:
let sprite = SKSpriteNode(imageNamed:"Spaceship")
let scale = SKAction.scaleTo(0.1, duration: 0.5)
let fade = SKAction.fadeOutWithDuration(0.5)
let group = SKAction.group([scale, fade])
sprite.runAction(group)
Another useful method can be the completion , so you can know when an SKAction was finished:
extension SKNode
{
func runAction( action: SKAction!, withKey: String!, optionalCompletion: dispatch_block_t? )
{
if let completion = optionalCompletion
{
let completionAction = SKAction.runBlock( completion )
let compositeAction = SKAction.sequence([ action, completionAction ])
runAction( compositeAction, withKey: withKey )
}
else
{
runAction( action, withKey: withKey )
}
}
}
Usage:
node.runAction(move,withKey:"swipeMove",optionalCompletion: {
// here the action is finished, do whatever you want
})
After that, about your project, I've seen many node.runAction.., you can also adopt this strategy to sinchronize your actions:
var myAction30 :SKAction!
var myAction31 :SKAction!
self.myAction30 = SKAction.repeatActionForever(puzzle30)
self.myAction31 = SKAction.repeatActionForever(puzzle31)
let group = SKAction.group([self.myAction30, self.myAction31])
self.runAction(group)
UPDATE: I've seen your update part, when you speak about "synchronize" probably you don't means the "running in parallel" actions.
So, if you want to run an action after another there is also:
self.myAction30 = SKAction.repeatActionForever(puzzle30)
self.myAction31 = SKAction.repeatActionForever(puzzle31)
let sequence = SKAction.sequence([self.myAction30, self.myAction31])
self.runAction(sequence)

Resources