How would I save a label using NSUserDefaults in swift? - ios

I have these two UITextFields and the first texField subtracts the number from the second textField. It then takes the answer and puts it in my SKLabelNode. That works fine. But the problem Im having is that it doesn't save the label. When I quit the app and go back to it it doesnt save the value. What am I doing wrong with my code?
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch in (touches as! Set<UITouch>) {
var defaults=NSUserDefaults.standardUserDefaults()
var save=defaults.integerForKey("saveCalories")
var touch: UITouch = touches.first as! UITouch
var location = touch.locationInNode(self)
var node = self.nodeAtPoint(location)
if let number1 = textFieldCaloriesIntake.text.toInt() {
if let number2 = textFieldCaloriesBurned.text.toInt() {
let subtract = number1 - number2
defaults.setInteger(subtract, forKey: "saveCalories")
var showTotalCalories = defaults.integerForKey("saveCalories")
totalCaloriesLabel.text = String(showTotalCalories)
NSUserDefaults.standardUserDefaults().synchronize()
}
}
}
}

Use this code for Swift
NSUserDefaults.standardUserDefaults().setValue(value, forKey:key)
Save example:
NSUserDefaults.standardUserDefaults().setValue(positionTextField.text!, forKey: "position")
Retrieve example:-
position!.text=NSUserDefaults.standardUserDefaults().stringForKey("position")
Note: remember the key for further retrievals

Save the text of the label in NSUserDefaultinstead

I got it to work by putting the code in the didMoveToView; it saves the label now.

Related

How do I check if the same key exists in an Array?

I am trying to make a RPG game in IOS, with a similar dialogue system in Baldurs Gate. I have created two arrays in a plist file. Like this:
As you can see I have two arrays: PlayerMessage; a list (it will be) of multiple choices that the player can touch and NPCMessages; the text that is displayed when the PlayerMessage is touched
I am at the stage where I can touch on the NPC and it will display a black box (NPCMessageer node) with text from the array (PlayerMessage via the plist file).
However, I don't know how to connect Item 0 in PlayerMessage and NPC Message and if they exist change the Message: SKLabelNode! text to one in NPCMessage. Does anyone know how to compare if another item exist in another array?
Here is the code that I have used:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
{
for touch in (touches) {
NPC.name = "NPC"
let Location = touch.location(in: self)
var CorrectedLocation = CGPoint()
CorrectedLocation.x = Location.x - LocalCamera.position.x
CorrectedLocation.y = Location.y - LocalCamera.position.y
let node = self.atPoint(CorrectedLocation)
var Message: SKLabelNode!
Message = SKLabelNode(fontNamed: "Trebuchet MS")
if (node.name == "NPC") {
let NPCMessageer = SKSpriteNode (color: UIColor.black, size: CGSize(width:1000, height:1000))
NPCMessageer.zPosition = 99
NPCMessageer.position = CGPoint(x:-500, y:-200)
Message.fontSize = 50
Message.color = UIColor.white; Message.position = CGPoint(x:-500, y:-100)
Message.zPosition = 100
addChild(NPCMessageer)
self.addChild(Message)
for PlayerMessage in NPC.PlayerMessage {
Message.text = PlayerMessage as?String}
let label = self.atPoint(CorrectedLocation)
if label.name == "Message"
{
if NPC.PlayerMessage == NPC.NPCMessage
{
Message.text = NPC.NPCMessage as?String
}
If I understand correctly you want to find a given element from one array in another array.
You can then use firstIdex(of:) and if an element exist use the returned index to set the Message object
let item = PlayerMessage[0] //assuming this is what you want to find
if let index = NPCMessage.firstIndex(of: item) {
let Message.text = NPCMessage[index]
}

Casting as a sksprite node

I keep getting a SIGBRT error on this line of code:
let spriteTapped : SKSpriteNode = (nodeTapped as? SKSpriteNode)!
I am using it to check if my sprite is tapped and which one is tapped, I get this error whenever anything other than a SKSpriteNode is tapped, any ideas on how I might fix this?
If nodeTapped is not a SKSpriteNode then the conditional cast
nodeTapped as? SKSpriteNode
evaluates to nil, and the forced unwrapping with ! crashes.
Better use optional binding:
if let spriteTapped = nodeTapped as? SKSpriteNode {
// ... do something with spriteTapped ...
} else {
// tapped node is not a SKSpriteNode
}
or
guard let spriteTapped = nodeTapped as? SKSpriteNode else {
return // tapped node is not a SKSpriteNode
}
// ... do something with spriteTapped ...
If you have an array of nodes then
for case let spriteTapped as SKSpriteNode in nodesTapped {
// ... do something with spriteTapped ...
}
can be used to iterate over all sprite nodes in the list (and
silently ignore other nodes).
Answer by #Martin R is totally correct.
Let me add more details about detecting which nodes or sprites have been tapped.
If you add this to your scene
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
let location = touch.location(in: self)
let tappedNodes = nodes(at: location)
let tappedSprites = tappedNodes.compactMap { $0 as? SKSpriteNode }
}
you can easily get the list of all the nodes (tappedNodes) and the sprites (tappedSprites) having the same coordinates of your touch.

Why is my music not playing in reverse when using the property canPlayReverse in Swift?

Im trying to play my music in reverse by using the canPlayReverse property but that is not working. When I try to play it in reverse it goes forward. Here is the code I have below: Thank you!
class GameScene: SKScene, MPMediaPickerControllerDelegate, AVAudioPlayerDelegate {
private var player:AVPlayer! = AVPlayer()
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches {
let location = touch.locationInNode(self)
let node = self.nodeAtPoint(location)
//this is for the left turntable
if node.name == "lefttt" {
//lets user rotate left turntable when there is one finger on turntable.
let dy = leftTurntable.position.y - location.y
let dx = leftTurntable.position.x - location.x
let angle2 = atan2(dy, dx)
leftTurntable.zRotation = angle2
let delta = (angle2 - previousAngle); M_PI
if delta > 0 {
print("rotateleft")
if musicPlayer == player.currentItem?.canPlayReverse {
musicPlayer.rate = -1.0
}
} else {
print("rotateright")
musicPlayer.rate = 3.0
musicPlayer.play()
}
previousAngle = angle2
}
When you use asset!, you're telling the compiler that the variable will point to a valid object but your code isn't setting asset to anything non-nil.
In general, avoid '!' whenever possible and test your optionals instead.

HighScore resets to 0

I have been working on my xcode project for a couple of weeks now using Xcode and swift. Today when I started running the simulator my highScore was set to 0. This was the first time, it had always kept score. Does this have anything to do with the simulator or is something wrong with my code. I of course don't want the user to use my app if the highScore can reset to 0 at any given time.
class GameScene: SKScene {
let labelHighScore = SKLabelNode()
var highScore = 0
override func didMoveToView(view: SKView) {
var HighscoreDefault = NSUserDefaults.standardUserDefaults()
if(HighscoreDefault.valueForKey("Highscore") != nil) {
highScore = HighscoreDefault.valueForKey("Highscore") as! NSInteger
labelHighScore.text = NSString(format: "%i", highScore) as String
}
labelHighScore.fontSize = 70
labelHighScore.position = CGPointMake(frame.midX, frame.midY + 305)
labelHighScore.fontColor = UIColor.blackColor()
self.addChild(labelHighScore)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
if ball != blackB && ball.texture == blackB.texture {
score += 1
labelScore.text = String(score)
if(score > highScore) {
highScore = score
labelHighScore.text = String(highScore)
var HighscoreDefault = NSUserDefaults.standardUserDefaults()
HighscoreDefault.setValue(highScore, forKey: "Highscore")
HighscoreDefault.synchronize()
}
}
Unless your using the same device it would not keep the same user defaults. If you have always used the simulator they are known to reset from time to time. My suggestions would be to explicitly set the high score's default and run. comment out the code that sets the default and re run. It should maintain that value.

Different results between iOS 7.1 and 8 while using Swift

I am practicing swift by writing a simple game. However, I noticed something weird happening. I am getting different results when I run my app on iOS 7.1 compared to iOS 8. I am trying to downcast an SKNode to a custom class that I wrote called CircleNode, which inherits from SKSpriteNode. Here is the class:
import UIKit
import SpriteKit
class CircleNode: SKSpriteNode {
var _hasMoved = false
var _touchingCircles:NSMutableArray = NSMutableArray()
var _isTouchingObject = false
var _selectedForDeletion = false
var _isBeingTouched = false
var _xOffset:CGFloat = 0
var _yOffset:CGFloat = 0
func addTouchingCircle(touchingCircle:CircleNode) {
_touchingCircles.addObject(touchingCircle)
_isTouchingObject = true
}
func removeAllCircles(){
self._selectedForDeletion = true
for circ :CircleNode! in _touchingCircles {
if circ._selectedForDeletion == false {
circ.removeAllCircles()
}
}
self.removeFromParent()
}
}
The code that is resulting in weird results is :
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let locationInScene = touch.locationInNode(self)
var selectedNode = self.nodeAtPoint(locationInScene)
let node = selectedNode as? CircleNode
if node {
println("NODE FOUND:circle")
} else {
println("NULL")
}
}
}
In iOS 8, when I click on one of the on screen circles, it prints "NODE FOUND:circle". However, when I do the same on iOS 7.1 it prints "NULL". I have been trying to figure out why this is happening for days, but I can't seem to figure it out. It seems like in iOS 8, var selectedNode = self.nodeAtPoint(locationInScene) actually returns my CircleNode, but in iOS 7.1, it doesn't recognize the node. Any help? Thanks in advance!
There seems to be an issue with the way the XCode templates have changed between XCode 6.0 and 6.1 that causes problems when working with SpriteKit scenes in Swift.
The problem is actually with the initialization of the SKScene from your controller, not the node itself: XCode 6.1 implements the 'unarchiveFromFile' extension method which doesn't appear to work well with Swift on iOS7.1
I got round this by using the following extension:
import UIKit
import SpriteKit
extension SKNode {
class func unarchiveFromFile<T: SKScene>(file : NSString) -> T {
let path = NSBundle.mainBundle().pathForResource(file, ofType: "sks")
var sceneData = NSData(contentsOfFile: path!, options: .DataReadingMappedIfSafe, error: nil)
var archiver = NSKeyedUnarchiver(forReadingWithData: sceneData!)
archiver.setClass(self.classForKeyedUnarchiver(), forClassName: "SKScene")
let scene = archiver.decodeObjectForKey(NSKeyedArchiveRootObjectKey) as T
archiver.finishDecoding()
return scene
}
class func safeInit<T: SKScene>(size: CGSize, _ skFile: NSString) -> T {
let currentVersion = UIDevice.currentDevice().systemVersion
let isIOS8 = currentVersion.compare("8.0", options: NSStringCompareOptions.NumericSearch) != NSComparisonResult.OrderedAscending
if isIOS8 {
let scene = T.unarchiveFromFile(skFile)
scene.size = size
return scene as T
} else {
return T(size: size)
}
}
}
And then calling this from your controller using the following code:
let skView = self.view as SKView
let scene = GameScene.safeInit(skView.bounds.size, "GameScene") as GameScene
That seems to work for me. It feels like a bit of a hack but I can't see any alternative option that actually works.

Resources