Sprite Kit iOS7 - Add Slider - uislider

I thought you could add UIKit slider/or button to your sprite kit app.
But cannot figure out how to do this, the code to create a slider programatically is
if (self.view) {
CGRect frame = CGRectMake(0.0, 0.0, 200.0, 300);
UISlider *slider = [[UISlider alloc] initWithFrame:frame];
//[slider addTarget:self action:#selector(sliderAction:) forControlEvents:UIControlEventValueChanged];
[slider setBackgroundColor:[UIColor clearColor]];
slider.minimumValue = 0.0;
slider.maximumValue = 50.0;
slider.continuous = YES;
[self.view addSubview:slider];
NSLog(#"View is alive - look for slider...");
}
else {
NSLog(#"No View!!");
}
The above does not work, the number of subviews of the view remains the same
I assume I have to add it as a child to my layer (SKNode), however the addChild method will not work with a UISlider. It needs to be an SKNode itself.
I am calling this within the scene class here
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
// thought putting here would work
// but self.view is nil
}
return self;
}
Thanks to comment, I can get it to show - but I have to add in within the viewController class, like this
- (void)viewDidLoad
{
[super viewDidLoad];
// Configure the view.
SKView * skView = (SKView *)self.view;
skView.showsFPS = YES;
skView.showsNodeCount = YES;
// Create and configure the scene.
SKScene * scene = [XBLMyScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
// Present the scene.
[skView presentScene:scene];
if (self.view) {
CGRect frame = CGRectMake(0.0, 0.0, 200.0, 300);
UISlider *slider = [[UISlider alloc] initWithFrame:frame];
//[slider addTarget:self action:#selector(sliderAction:) forControlEvents:UIControlEventValueChanged];
[slider setBackgroundColor:[UIColor clearColor]];
slider.minimumValue = 0.0;
slider.maximumValue = 50.0;
slider.continuous = YES;
NSLog(#"View is alive - look for slider...");
[self.view addSubview:slider];
} else {
NSLog(#"No View!!");
}
}
Is there not away to do it within the actual scene class ....
Thanks

After some tinkering
My solution, thanks to #LearnCocos2D hint
My Scene Class needed this
- (void) didMoveToView:(SKView *)view
{
[self addSlider];
}
Then call your method to add the slider.... etc

I got the same question and i wasn't satisfied with the UISlider. So created my own classes for Sprite Kit. There are buttons, joysticks, dpads and sliders. Maybe they help you improving your apps. In my games they work really good.
Be aware they are written in Swift.
LESKSliderNode
//
// LESKSliderNode.swift
// LESKClasses
//
// Created by Cyrill Lippuner on 17.06.14.
// Copyright (c) 2014 legelite. All rights reserved.
//
import SpriteKit
class LESKSliderNode : SKNode
{
/**
Defines the Size of the LESKSliderNode.
*/
var size : CGSize = CGSize(width: 0, height: 0)
/**
Defines the AnchorPoint of the LESKSliderNode.
*/
//var anchorPoint : CGPoint = CGPoint(x:0.5,y:0.5)
/**
Defines frameInParent with the position of the superclass and the size of the LESKSliderNode.
*/
var frameInParent : CGRect
{
get {return CGRect(origin: CGPoint(x:self.position.x - 0.5 * self.size.width,y:self.position.y - 0.5 * self.size.height), size: self.size)}
set(newValue)
{
super.position = newValue.origin
self.size = newValue.size
//self.value = self.valueRange.startIndex + ((newPositionX + range.endIndex) / (range.endIndex - range.startIndex)) * (self.valueRange.endIndex - self.valueRange.startIndex)
}
}
/**
Enables the LESKSliderNode to interactions.
*/
var isEnabled : Bool = true
/**
Displays whether a touch is in progress.
*/
var isActive : Bool = false
/**
Defines the space between the thumb and the edges of the scale.
*/
var overlayThumb : Bool = false {didSet{calculateNewThumbRange()}}
/**
Displays the value of thumb on the slider.
*/
var value : Float
{
get
{
return self.valueRange.startIndex + ((thumbSprite.position.x + self.thumbRange.endIndex) / (self.thumbRange.endIndex - self.thumbRange.startIndex)) * (self.valueRange.endIndex - self.valueRange.startIndex)
}
set(newValue)
{
var val = newValue
if newValue < self.valueRange.startIndex {val = self.valueRange.startIndex}
else if newValue > self.valueRange.endIndex {val = self.valueRange.endIndex}
let newPositionX = (val - self.valueRange.startIndex) * (self.thumbRange.endIndex - self.thumbRange.startIndex) / (self.valueRange.endIndex - self.valueRange.startIndex) - self.thumbRange.endIndex
thumbSprite.position = CGPoint(x:newPositionX,y:thumbSprite.position.y)
if self.thumbSpriteActive {self.thumbSpriteActive!.position = CGPoint(x:newPositionX,y:self.thumbSpriteActive!.position.y)}
}
}
/**
Defines the range of the values.
*/
var valueRange : Range<Float> = Range(start: 0.0, end: 1.0)
/**
The range of the thumb's position.
*/
var thumbRange : Range<Float> = Range(start: 0.0, end: 0.0)
/**
The range of the thumb's position.
*/
var thumbOffset : Float = 0.0
{
didSet
{
self.thumbSprite.position = CGPoint(x:self.thumbSprite.position.x, y: self.thumbOffset)
if self.thumbSpriteActive {self.thumbSpriteActive!.position = CGPoint(x:self.thumbSpriteActive!.position.x, y: self.thumbOffset)}
}
}
/**
ScaleSprite is the scale for the LESKSliderNode.
*/
let scaleSprite : SKSpriteNode
/**
ThumbSprite is the thumb for the LESKSliderNode.
*/
let thumbSprite : SKSpriteNode
/**
ScaleSpriteActive is the active scale for the LESKSliderNode.
*/
let scaleSpriteActive : SKSpriteNode?
/**
ThumbSpriteActive is the active thumb for the LESKSliderNode.
*/
let thumbSpriteActive : SKSpriteNode?
/**
Description of the LESKSliderNode
*/
override var description : String
{
get
{
var string = "<LESKSliderNode> name: \(self.name) "
string += "scaleSprite: [\(scaleSprite.description)] "
string += "thumbSprites: [\(thumbSprite.description)] "
string += "frame: \(self.frameInParent) rotation: \(self.zRotation) "
string += "isEnabled: \(isEnabled) "
if isEnabled {string += "isActive: \(isActive) overlayThumb: \(overlayThumb) range: \(valueRange) value: \(value)"}
return string
}
}
/**
Typealiases
*/
typealias LESKSliderNodeCompletion = ((slider: LESKSliderNode, value: Float) -> ())
/**
Closure, which is executed when a touch begins
*/
var touchDown : LESKSliderNodeCompletion?
/**
Closure, which is executed when the thumb is dragged
*/
var touchMoved : LESKSliderNodeCompletion?
/**
Closure, which is executed when a touch ends
*/
var touchUp : LESKSliderNodeCompletion?
/**
Closure, which is executed when a touch ends inside the frame of the LESKSliderNode
*/
var touchUpInside : LESKSliderNodeCompletion?
/**
Closure, which is executed when a touch is cancelled
*/
var touchCancelled : LESKSliderNodeCompletion?
/**
Initializer
#param the string of the thumbSprite
#param the string of the scaleSprite
*/
convenience init(thumbString: String, scaleString: String)
{
self.init(thumbSprite: SKSpriteNode(imageNamed: thumbString), scaleSprite: SKSpriteNode(imageNamed: scaleString), thumbSpriteActive: nil, scaleSpriteActive: nil)
}
/**
Initializer
#param the string of the thumbSprite
#param the string of the scaleSprite
#param the string of the thumbSpriteActive
#param the string of the scaleSpriteActive
*/
convenience init(thumbString: String, scaleString: String, thumbStringActive: String?, scaleStringActive: String?)
{
self.init(thumbSprite: SKSpriteNode(imageNamed: thumbString), scaleSprite: SKSpriteNode(imageNamed: scaleString), thumbSpriteActive: SKSpriteNode(imageNamed: thumbStringActive), scaleSpriteActive: SKSpriteNode(imageNamed: scaleStringActive))
}
/**
Initializer
#param the texture of the thumbSprite
#param the texture of the scaleSprite
*/
convenience init(thumbTexture: SKTexture, scaleTexture: SKTexture)
{
self.init(thumbSprite: SKSpriteNode(texture: thumbTexture), scaleSprite: SKSpriteNode(texture: scaleTexture), thumbSpriteActive: nil, scaleSpriteActive: nil)
}
/**
Initializer
#param the texture of the thumbSprite
#param the texture of the scaleSprite
#param the texture of the thumbSpriteActive
#param the texture of the scaleSpriteActive
*/
convenience init(thumbTexture: SKTexture, scaleTexture: SKTexture, thumbTextureActive: SKTexture?, scaleTextureActive: SKTexture?)
{
self.init(thumbSprite: SKSpriteNode(texture: thumbTexture), scaleSprite: SKSpriteNode(texture: scaleTexture), thumbSpriteActive: SKSpriteNode(texture: thumbTextureActive), scaleSpriteActive: SKSpriteNode(texture: scaleTextureActive))
}
/**
Initializer
#param the sprite of the thumbSprite
#param the sprite of the scaleSprite
*/
convenience init(thumbSprite: SKSpriteNode, scaleSprite: SKSpriteNode)
{
self.init(thumbSprite: thumbSprite, scaleSprite: scaleSprite)
}
/**
Initializer
#param the sprite of the thumbSprite
#param the sprite of the scaleSprite
#param the sprite of the thumbSpriteActive
#param the sprite of the scaleSpriteActive
*/
init(thumbSprite: SKSpriteNode, scaleSprite: SKSpriteNode, thumbSpriteActive: SKSpriteNode?, scaleSpriteActive: SKSpriteNode?)
{
self.thumbSprite = thumbSprite
self.scaleSprite = scaleSprite
self.thumbSpriteActive = thumbSpriteActive
self.scaleSpriteActive = scaleSpriteActive
super.init()
self.userInteractionEnabled = true
self.addChild(self.scaleSprite)
self.addChild(self.thumbSprite)
if self.scaleSpriteActive?
{
self.addChild(self.scaleSpriteActive)
self.scaleSpriteActive!.hidden = true
}
if self.thumbSpriteActive?
{
self.addChild(self.thumbSpriteActive)
self.thumbSpriteActive!.hidden = true
}
calculateNewThumbRange()
self.size = scaleSprite.size
}
override func touchesBegan(touches: NSSet!, withEvent event: UIEvent!)
{
if isEnabled
{
isActive = true
if self.scaleSpriteActive?
{
self.scaleSprite.hidden = true
self.scaleSpriteActive!.hidden = false
}
if self.thumbSpriteActive?
{
self.thumbSprite.hidden = true
self.thumbSpriteActive!.hidden = false
}
moveThumbToValueAccordingToTouch(touches.anyObject() as UITouch)
if touchDown? {touchDown!(slider: self, value: self.value)}
}
}
override func touchesMoved(touches: NSSet!, withEvent event: UIEvent!)
{
if isEnabled
{
let touchPosition = (touches.anyObject() as UITouch).locationInNode(self.parent)
if CGRectContainsPoint(self.frameInParent, touchPosition)
{
if self.scaleSpriteActive?
{
self.scaleSprite.hidden = true
self.scaleSpriteActive!.hidden = false
}
}
else
{
if self.scaleSpriteActive?
{
self.scaleSprite.hidden = false
self.scaleSpriteActive!.hidden = true
}
}
moveThumbToValueAccordingToTouch(touches.anyObject() as UITouch)
if touchMoved? {touchMoved!(slider: self, value: self.value)}
}
}
override func touchesEnded(touches: NSSet!, withEvent event: UIEvent!)
{
if isEnabled
{
isActive = false
if self.scaleSpriteActive?
{
self.scaleSprite.hidden = false
self.scaleSpriteActive!.hidden = true
}
if self.thumbSpriteActive?
{
self.thumbSprite.hidden = false
self.thumbSpriteActive!.hidden = true
}
if touchUp? {touchUp!(slider: self, value: self.value)}
let touchPosition = (touches.anyObject() as UITouch).locationInNode(self.parent)
if CGRectContainsPoint(self.frameInParent, touchPosition) {if touchUpInside? {touchUpInside!(slider: self, value: self.value)}}
}
}
override func touchesCancelled(touches: NSSet!, withEvent event: UIEvent!)
{
if isEnabled
{
isActive = false
if self.scaleSpriteActive?
{
self.scaleSprite.hidden = false
self.scaleSpriteActive!.hidden = true
}
if self.thumbSpriteActive?
{
self.thumbSprite.hidden = false
self.thumbSpriteActive!.hidden = true
}
if touchCancelled? {touchCancelled!(slider: self, value: self.value)}
}
}
func moveThumbToValueAccordingToTouch(touch: UITouch)
{
let touchPosition = touch.locationInNode(self)
var newPositionX = touchPosition.x
if newPositionX < self.thumbRange.startIndex {newPositionX = self.thumbRange.startIndex}
else if newPositionX > self.thumbRange.endIndex {newPositionX = self.thumbRange.endIndex}
self.thumbSprite.position = CGPoint(x:newPositionX,y:self.thumbSprite.position.y)
if self.thumbSpriteActive {self.thumbSpriteActive!.position = CGPoint(x:newPositionX,y:self.thumbSpriteActive!.position.y)}
}
func calculateNewThumbRange()
{
self.thumbRange = (self.overlayThumb) ? Range(start: -scaleSprite.size.width/2, end: scaleSprite.size.width/2) : Range(start: -(scaleSprite.size.width / 2 - thumbSprite.size.width / 2), end: scaleSprite.size.width / 2 - thumbSprite.size.width / 2)
}
}

Related

Missing Type UIEvent?

I'm using XCode 10.2 with SpriteKit and swift 5 to create a Mac Application, and I cannot for the life of me find a working example of handling click events on a node.
The most updated info I can find suggests using the following:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { }
But XCode errors, saying
Use of undeclared type 'UIEvent'
Use of undeclared type 'UITouch'
I'm not sure how to proceed cause all the info I find suggests using the above code. Everything else is working OK so far though. Here is my GameScene Class:
import SpriteKit
class GameScene: SKScene {
var circle: SKShapeNode = SKShapeNode();
var label: SKLabelNode = SKLabelNode();
var ground: SKShapeNode = SKShapeNode();
/**
* Did Move Callback
*/
override func didMove(to view: SKView) {
initGround(view: view);
initLabel(view: view);
let recognizer = NSClickGestureRecognizer(target: self, action: #selector(tap));
view.addGestureRecognizer(recognizer);
}
/**
* Click Handler
*/
#objc func tap(recognizer: NSGestureRecognizer) {
let viewLocation = recognizer.location(in: view);
let sceneLocation = convertPoint(fromView: viewLocation);
addCircle(view: view!, position: sceneLocation);
}
// Not Working
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
}
/**
* Init Ground
*/
func initGround(view: SKView) {
let path = CGMutablePath();
path.move(to: CGPoint(x: 0, y: 30));
path.addLine(to: CGPoint(x: view.frame.width, y: 30));
path.addLine(to: CGPoint(x: view.frame.width, y: view.frame.height));
path.addLine(to: CGPoint(x: 0, y: view.frame.height));
path.addLine(to: CGPoint(x: 0, y: 30));
ground.path = path;
ground.lineWidth = 5;
ground.strokeColor = SKColor.brown;
let borderBody = SKPhysicsBody(edgeLoopFrom: path);
borderBody.friction = 5;
self.physicsBody = borderBody;
addChild(ground);
}
/**
* Add Label
*/
func initLabel(view: SKView) {
label = SKLabelNode(text: "No Gravity");
label.name = "no gravity button";
label.position = CGPoint(x: label.frame.width / 2, y: 5);
label.fontSize = 12;
label.fontColor = SKColor.yellow;
label.fontName = "Avenir";
label.isUserInteractionEnabled = true;
addChild(label);
}
/**
* Add Circle
*/
func addCircle(view: SKView, position: CGPoint) {
let size = Int.random(in: 1 ..< 50);
let color = getRandomColor();
circle = SKShapeNode(circleOfRadius: CGFloat(size));
// Set Position
circle.position = position;
// Set Physics
circle.physicsBody = SKPhysicsBody(circleOfRadius: CGFloat(size));
circle.physicsBody?.affectedByGravity = false;
circle.physicsBody?.usesPreciseCollisionDetection = true;
circle.physicsBody?.restitution = 1; //0.8
circle.physicsBody?.linearDamping = 0;
circle.physicsBody?.friction = 0; //0.2
circle.physicsBody?.isDynamic = true;
circle.physicsBody?.mass = CGFloat(size);
circle.physicsBody?.allowsRotation = true;
circle.physicsBody?.velocity = CGVector(dx: 0, dy: -1000);
circle.strokeColor = color;
circle.glowWidth = 1.0;
circle.fillColor = color;
addChild(circle)
}
func getRandomColor() -> SKColor {
return SKColor(red: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1),
alpha: 1.0)
}
}
Does anyone have experience with using Swift 5 and handling clicks / touches in SpriteKit? Or maybe just why XCode says that UIEvent and UITouch aren't real things?
Thanks!
On Mac, you’ll implement
-(void)mouseDown:(NSEvent *)theEvent {
}
- (void)mouseUp:(NSEvent *)theEvent {
}
- (void)mouseExited:(NSEvent *)theEvent {
}
In each case you will call
CGPoint loc = [theEvent locationInNode:self];
to learn where the click happened within the scene.
User Martin R pointed out the UIEvent and UITouch classes are included only in iOS projects. I'm creating a Mac Application, what I didn't realize was that I already had the click handler in my GameScene class:
override func didMove(to view: SKView) {
let recognizer = NSClickGestureRecognizer(target: self, action: #selector(click));
view.addGestureRecognizer(recognizer);
}
This registers a callback to a click handler, which I already had defined:
/**
* Click Handler
*/
#objc func tap(recognizer: NSGestureRecognizer) {
let viewLocation = recognizer.location(in: view);
let sceneLocation = convertPoint(fromView: viewLocation);
let touchedNode = self.atPoint(sceneLocation);
if let name = touchedNode.name {
if name == "no gravity button" {
print("Touched")
}
}
addCircle(view: view!, position: sceneLocation);
}
I was able to get the clicked node name and act upon it as I originally intended.

Line fading when drawing swift

UPDATE: This does not happen if I set only the board as the main view. Why would this happen when it is a subview?
I have a view that has a game board that you draw over to select characters. To do this I put a UIImageView over the game board and draw the line in touches moved using a helper function. It works, however, while drawing the line, everything that came before it slowly fades and also moves upwards.
It looks like this:
This is what the draw function looks like and it is called in touches moved:
//Helper function that draws a line which is used while the user is selecting letters
func drawLine(fromPoint: CGPoint, toPoint: CGPoint){
UIGraphicsBeginImageContext(drawingView.frame.size)
//get a context
guard let context: CGContext = UIGraphicsGetCurrentContext() else {
print("failed to get image context to draw line")
return
}
self.drawingView.image?.draw(in: CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height))
//set the line
context.move(to: fromPoint)
context.addLine(to: toPoint)
//customize line
context.setLineCap(CGLineCap.round)
context.setLineWidth(4)
context.setStrokeColor(UIColor.blue.cgColor)
context.setBlendMode(CGBlendMode.normal)
//draw the line
context.strokePath()
drawingView.image = UIGraphicsGetImageFromCurrentImageContext()
//close
UIGraphicsEndImageContext()
//print("Drew Line")
}
Heres all the code for the view:
/**
GameControllerDelegate is used to communicate when the user has chosen a word
*/
protocol GameControllerDelegate: AnyObject {
func wordPicked(letters: [String], moves: [(row: Int, column: Int)])
}
/**
GameViewDelegate is used to let the gameview know a user has picked a word using the board which is a subview
*/
protocol GameViewDelegate: AnyObject {
func wordPickedInBoard(letters: [String], moves: [(row: Int, column: Int)])
}
/**
Game view class holds all the subviews of the Game view as well as provides
getters and setters for each important data
*/
class GameView: UIView , GameViewDelegate{
//the board part
let boardView: BoardView = {
let boardView = BoardView()
boardView.backgroundColor = UIColor.white
boardView.translatesAutoresizingMaskIntoConstraints = true
return boardView
}()
//the score part
let scoreView: ScoreView = {
let scoreView = ScoreView()
scoreView.backgroundColor = UIColor.white
scoreView.translatesAutoresizingMaskIntoConstraints = true
return scoreView
}()
//two other vairables to assist in sizing the subviews
var minusTop: CGFloat = 0
var minusBottom: CGFloat = 0
//the board for the game
var board: [[String]] {
set
{
boardView.boardStrings = newValue
boardView.generateLabels()
setNeedsDisplay()
}
get { return boardView.boardStrings }
}
//the score
var score: Int {
set
{
scoreView.gameScore.text = " Score: " + String(newValue)
}
get
{
let indexStartOfNumber = scoreView.gameScore.text!.index((scoreView.gameScore.text!.startIndex), offsetBy: 9)
let numString = scoreView.gameScore.text?[indexStartOfNumber...]
return Int(String(describing: numString))!
}
}
//delegate for alerting the controller that a word was picked
var delegate: GameControllerDelegate? = nil
init(frame: CGRect, minusTop: CGFloat, minusBottom: CGFloat){
super.init(frame: frame)
boardView.delegate = self
self.minusTop = minusTop
self.minusBottom = minusBottom
addSubview(boardView)
addSubview(scoreView)
}
override init(frame: CGRect){
super.init(frame: frame)
boardView.delegate = self
addSubview(boardView)
addSubview(scoreView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("It's Apple. What did you expect?")
}
//manually layout the alarmpreview
override func layoutSubviews() {
var cursor: CGPoint = .zero
let scoreViewHeight = bounds.height/10
let boardHeight = bounds.height - minusTop - minusBottom - scoreViewHeight
cursor.y += minusTop
boardView.frame = CGRect(x: cursor.x, y: cursor.y, width: bounds.width, height: boardHeight)
cursor.y += boardHeight
scoreView.frame = CGRect(x: cursor.x, y: cursor.y, width: bounds.width, height: scoreViewHeight)
}
//function to catch when a word is picked in the board
func wordPickedInBoard(letters: [String], moves: [(row: Int, column: Int)]) {
//forward the info via the delegate
delegate?.wordPicked(letters: letters, moves: moves)
}
}
/**
Score view shows the users current score
*/
class ScoreView: UIView {
/*var scoreTitle: UILabel = {
let scoreTitle = UILabel()
scoreTitle.backgroundColor = UIColor.white
scoreTitle.text = "Score: "
return scoreTitle
}()*/
var gameScore: UILabel = {
let gameScore = UILabel()
gameScore.backgroundColor = UIColor.white
gameScore.text = " Score: 0"
return gameScore
}()
//init
override init(frame: CGRect){
super.init(frame: frame)
addSubview(gameScore)
//addSubview(scoreTitle)
}
required init?(coder aDecoder: NSCoder) {
fatalError("It's Apple. What did you expect?")
}
override func layoutSubviews() {
let cursor: CGPoint = .zero
gameScore.frame = CGRect(x: cursor.x, y: cursor.y, width: bounds.width, height: bounds.height)
}
}
/**
VoardView holds all the cells of the board and communicates when a user draws on it
*/
class BoardView: UIView {
var drawingView: UIImageView = {
let drawingView = UIImageView()
drawingView.backgroundColor = UIColor.white.withAlphaComponent(0.0)
return drawingView
}()
//delegate to communicate with the superview
var delegate: GameViewDelegate? = nil
//variables to aid in tracking the user moves
var lastPoint = CGPoint.zero
var looped = false
var boardStrings:[[String]] = []
var board:[[UILabel]] = Array(repeating: Array(repeating: UILabel(), count: 9), count: 12)
var curMoves: [(row: Int, column: Int)] = []
var highlightedArea: [(row: Int, column: Int)] = []
//centralized colors
let unHighlightedColor = UIColor.lightGray
let highlightedColor = UIColor.yellow
//Initialize this view
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = UIColor.white
initBoard()
//self.boardStrings = generateBoard()
//generateLabels(boardStrings: self.boardStrings)
for i in 0...11 {
for j in 0...8 {
addSubview(board[i][j])
}
}
addSubview(drawingView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("It's Apple. What did you expect?")
}
//override the draw function, we draw the grid as well as the letters here
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let context: CGContext = UIGraphicsGetCurrentContext() else {
print("failed to attain draw context")
return
}
//8 verticle lines
for i in 1 ... 9 {
let fromPoint = CGPoint(x: bounds.width * CGFloat(Double(i) * 1.0/9.0), y: 0)
let toPoint = CGPoint(x: bounds.width * CGFloat(Double(i) * 1.0/9.0), y: bounds.height)
context.move(to: fromPoint)
context.addLine(to: toPoint)
context.strokePath()
}
//draw 11 horizontal lines
for i in 1 ... 12 {
let fromPoint = CGPoint(x: 0, y: bounds.height * CGFloat(Double(i) * 1.0/12.0))
let toPoint = CGPoint(x: bounds.width, y: bounds.height * CGFloat(Double(i) * 1.0/12.0))
context.move(to: fromPoint)
context.addLine(to: toPoint)
context.strokePath()
}
}
//here we manually layout all the subviews that go into the preview
override func layoutSubviews() {
var cursor: CGPoint = .zero
let width = bounds.width/9
let height = bounds.height/12
for i in 0 ... 11 {
for j in 0 ... 8 {
board[i][j].frame = CGRect(x: cursor.x, y: cursor.y, width: width, height: height)
cursor.x += bounds.width * 1.0/9.0
}
cursor.x = 0
cursor.y += bounds.height * 1.0/12.0
}
drawingView.frame = self.bounds
}
//handle the beginning of a user move
override func touchesBegan(_ touches: Set<UITouch>, with: UIEvent?) {
looped = false
if let touch = touches.first as? UITouch {
lastPoint = touch.location(in: self)
//find what row we are in
let buttonHeight = bounds.height/12
let buttonWidth = bounds.width/9
let row: Int = Int(lastPoint.y/buttonHeight)
let column: Int = Int(lastPoint.x/buttonWidth)
curMoves.append((row: row, column: column))
highlightLabel(row: row, column: column)
setNeedsDisplay()
}
}
//handle when the user is moving. Calculate coordintes to drive the move the player is making
override func touchesMoved(_ touches: Set<UITouch>, with: UIEvent?) {
if !looped {
if let touch = touches.first as? UITouch {
let currentPoint = touch.location(in: self)
drawLine(fromPoint: lastPoint, toPoint: currentPoint)
//find what row we are in
let buttonHeight = bounds.height/12
let buttonWidth = bounds.width/9
let row: Int = Int(lastPoint.y/buttonHeight)
let column: Int = Int(lastPoint.x/buttonWidth)
if curMoves[curMoves.count - 1] != (row: row, column: column) {
//if the user is backstepping
if curMoves.count > 1 {
if curMoves[curMoves.count - 2] == (row: row, column: column) {
let pos = curMoves.remove(at: curMoves.count - 1)
unHeighlightLabel(row: pos.row, column: pos.column)
}
//if the user tried to make a loop
else if curMoves.contains(where: {$0 == (row: row, column: column)}){
for pos in curMoves {
unHeighlightLabel(row: pos.row, column: pos.column)
}
print("User tried to make a loop")
looped = true
}
else {
curMoves.append((row: row, column: column))
if board[row][column].backgroundColor != UIColor.green{
highlightLabel(row: row, column: column)
}
}
}
//if the user tried to make a loop
/*else if curMoves.contains(where: {$0 == (row: row, column: column)}){
for pos in curMoves {
unHeighlightLabel(row: pos.row, column: pos.column)
}
print("User tried to make a loop")
looped = true
}*/
else {
curMoves.append((row: row, column: column))
if board[row][column].backgroundColor != UIColor.green{
highlightLabel(row: row, column: column)
}
}
}
lastPoint = currentPoint
}
}
setNeedsDisplay()
}
//handle the end of a player move
override func touchesEnded(_ touches: Set<UITouch>, with: UIEvent?) {
if !looped {
//derive word
var word: [String] = []
for move in curMoves {
//if it contains blank put some garbage in there
if !boardStrings[move.row][move.column].contains("Blank") {
word.append(board[move.row][move.column].text!)
}
else {
word.append("###")
}
}
//let superview know
delegate?.wordPickedInBoard(letters: word, moves: curMoves)
}
//reset
for move in curMoves {
if board[move.row][move.column].backgroundColor != UIColor.green{
unHeighlightLabel(row: move.row, column: move.column)
}
}
curMoves = []
looped = false
drawingView.image = nil
setNeedsDisplay()
}
//Helper functions that changes the background color of the specified label to a centralized color
func highlightLabel(row: Int, column: Int){
board[row][column].backgroundColor = highlightedColor
}
func unHeighlightLabel(row: Int, column: Int) {
board[row][column].backgroundColor = unHighlightedColor
}
//Helper function that draws a line which is used while the user is selecting letters
func drawLine(fromPoint: CGPoint, toPoint: CGPoint){
UIGraphicsBeginImageContext(drawingView.frame.size)
//get a context
guard let context: CGContext = UIGraphicsGetCurrentContext() else {
print("failed to get image context to draw line")
return
}
self.drawingView.image?.draw(in: CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height))
//set the line
context.move(to: fromPoint)
context.addLine(to: toPoint)
//customize line
context.setLineCap(CGLineCap.round)
context.setLineWidth(4)
context.setStrokeColor(UIColor.blue.cgColor)
context.setBlendMode(CGBlendMode.normal)
//draw the line
context.strokePath()
drawingView.image = UIGraphicsGetImageFromCurrentImageContext()
//close
UIGraphicsEndImageContext()
//print("Drew Line")
}
//helper function that initilizes the board layout
func initBoard() {
for i in 0 ... 11 {
for j in 0 ... 8 {
board[i][j] = UILabel()
board[i][j].text = ""
}
}
}
/**
This function takes the generated board strings and converts them into their proper labels
*/
func generateLabels() {
highlightedArea = []
for i in 0 ... 11 {
for j in 0 ... 8 {
//board[i][j] = UILabel()
board[i][j].textAlignment = .center
board[i][j].layer.borderColor = UIColor.black.cgColor
board[i][j].layer.borderWidth = 1.0;
if boardStrings[i][j].hasSuffix("^") {//.characters.contains("^"){
//highlight the label
board[i][j].backgroundColor = UIColor.green
//set the text
let index = boardStrings[i][j].index(boardStrings[i][j].startIndex, offsetBy: boardStrings[i][j].count - 1)
let range = boardStrings[i][j].startIndex..<index
let letter = String(boardStrings[i][j][range])
board[i][j].backgroundColor = UIColor.green
board[i][j].text = letter
highlightedArea.append((row: i, column: j))
}
else if boardStrings[i][j] != "Blank" {
board[i][j].backgroundColor = unHighlightedColor
board[i][j].text = boardStrings[i][j]
}
else {
//leave it blank
board[i][j].backgroundColor = unHighlightedColor
board[i][j].text = ""
}
}
}
}
}
Recently experienced the same problem. It might be too late to help you out, but hopefully someone finds this useful someday.
Using floor() for height and width when setting the image view's bounds(image view you want to draw into) worked for me. Did this in objective C... don't know the floor() equivalent for swift.

touchesBegin not being called on Sprit Node

I have SpritNodes that are in my scene and I want a method to be called when I touch it. I have isUserInteractionEnabled set to true for my node, but touchesBegan still does not get called when I touch the nodes. (Note: I am using Swift 3.0)
Code:
import SpriteKit
class MainScene: SKScene, SKPhysicsContactDelegate {
var didStart = false
var background = SKSpriteNode(imageNamed: "background")
var backDrop = SKShapeNode()
var emailNodes: [SKSpriteNode] = []
let emailCatagory: UInt32 = 0x1 << 0
let dropCatagory: UInt32 = 0x1 << 1
override func sceneDidLoad() {
startCountDown()
}
override func didMove(to view: SKView) {
self.physicsWorld.contactDelegate = self
background.position = CGPoint(x: frame.midX, y:frame.midY)
}
public func startCountDown(){
var times = 4
let countdownTimer = SKLabelNode()
countdownTimer.text = "3"
countdownTimer.position = CGPoint(x: frame.midX, y: frame.midY)
countdownTimer.fontSize = 120.0
countdownTimer.fontName = "Lao MN"
countdownTimer.fontColor = UIColor.black()
backDrop = SKShapeNode()
backDrop = SKShapeNode(rectOf: CGSize(width: frame.width, height: 100))
backDrop.position = CGPoint(x: frame.midX, y: 10)
backDrop.physicsBody = SKPhysicsBody(rectangleOf: backDrop.frame.size)
//backDrop.size = CGSize(width: 1000, height: 2)
backDrop.physicsBody?.affectedByGravity = false
backDrop.physicsBody?.usesPreciseCollisionDetection = true
backDrop.name = "backDrop"
backDrop.physicsBody?.collisionBitMask = 0
backDrop.physicsBody?.categoryBitMask = dropCatagory
addChild(countdownTimer)
addChild(backDrop)
//addChild(background)
Timer.every(1.2.seconds) { (timer: Timer) in
if(times<=0){
timer.invalidate()
countdownTimer.removeFromParent()
self.didStart = true
self.startDropping()
}else{
print("\(times)")
times = times - 1
countdownTimer.text = "\(times)"
}
}
}
func startDropping(){
Timer.every(1.2.seconds) { (timer: Timer) in
let which = Int(arc4random_uniform(2) + 1)
let ee = self.getEmailNode(type: which)
self.addChild(ee)
ee.physicsBody?.applyImpulse(CGVector(dx: 0.0, dy: -5.0))
}
}
func getEmailNode(type: Int) -> SKSpriteNode{
var email = SKSpriteNode()
if(type == 1){
email = SKSpriteNode(imageNamed: "normal_email")
email.name = "normal_email"
}
if(type == 2){
email = SKSpriteNode(imageNamed: "classified_email")
email.name = "classified_email"
}
email.setScale(3)
email.position = CGPoint(x: getRandomColumn(), y: frame.height)
email.physicsBody = SKPhysicsBody(rectangleOf: email.frame.size)
email.physicsBody?.usesPreciseCollisionDetection = true
email.physicsBody?.categoryBitMask = emailCatagory
email.isUserInteractionEnabled = true
email.physicsBody?.affectedByGravity = false
email.physicsBody?.collisionBitMask = 0
email.physicsBody?.contactTestBitMask = emailCatagory | dropCatagory
emailNodes.append(email)
return email
}
func getRandomColumn() -> CGFloat{
let which = Int(arc4random_uniform(3) + 1)
let gg = frame.size.width/3
switch(which){
case 1:
return gg / 2
case 2:
return frame.midX
case 3:
return (gg * 3) - gg / 2
default:
return (gg * 3) + gg / 2
}
}
func didBegin(_ contact: SKPhysicsContact) {
if (contact.bodyA.categoryBitMask == dropCatagory) &&
(contact.bodyB.categoryBitMask == emailCatagory) {
let node = contact.bodyB.node as! SKSpriteNode
node.removeFromParent()
while emailNodes.contains(node) {
if let itemToRemoveIndex = emailNodes.index(of: node) {
emailNodes.remove(at: itemToRemoveIndex)
}
}
}
}
func doesContainNode(sk: SKSpriteNode) -> Bool {
for it in emailNodes{
if(it == sk){
return true
}
}
return false
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
enumerateChildNodes(withName: "//*", using:
{ (node, stop) -> Void in
print("\(node.name)")
print("\(node)")
if((node.name?.contains("email")) != nil){
print("Touched!")
}
})
}
}
You should try the following in order to be able to get the user's position and know when the sprite has been touched. Add the following inside the touchesEnabled function.
for touch in touches {
let userTouch = touch.locationInNode(self)
}
And then check if the sprite was touched by using:
node.containsPoint(userTouch)
See if that works. The way you have your code setup, you might need to nest the above function right after checking if it's nil. As for the userInteractionEnabled, I don't use it at all when using the above code.
You do not want userInteractionEnabled set on any of your nodes, you want that only on the scene. Use userInteractionEnabled only when you are subclassing your node, this way you can use touchesBegan inside your subclassed file. What is happening is your touch is going into your node and being absorbed, which does nothing, and is being ignored by the scene since the node absorbed it.
Edit: Sorry #MarkBrownsword I did not see your comment, if you post it as an answer, I will upvote and delete my answer.
I found a solution. I removed isUserInteractionEnabled and touchesBegan was still not being called. So I went through each of the properties of the "email" node and for some reason the following properties made it where touchesBegan would not be called.
email.physicsBody?.affectedByGravity = false
email.physicsBody?.collisionBitMask = 0
So I removed those and now touchesBegan is being properly called.

moving pacman in swift

i am brand new to swift and i am trying to program a pacman. i am trying to move the pacman to the direction of the swipe, so far i have managed to move it to the edges of the screen, the problem is that when i try to move it not from the edge of the screen but in the middle of the swipe action, it just goes to the edge of the screen and moves to the swipe direction, here is the code for one direction:
var x = view.center.x
for var i = x; i > 17; i--
{
var origin: CGPoint = self.view.center
var move = CABasicAnimation(keyPath:"position.x")
move.speed = 0.13
move.fromValue = NSValue(nonretainedObject: view.center.x)
move.toValue = NSValue(nonretainedObject: i)
view.layer.addAnimation(move, forKey: "position")
view.center.x = i
}
the thing is that i know the problem which is when i swipe to the direction that i want the for loop will not wait for the animation to stop but it will finish the loop in less than a second and i need sort of delay here or other code.
This was an interesting question, so I decided to make an example in SpriteKit. There isn't any collision detection, path finding or indeed even paths. It is merely an example of how to make 'Pac-Man' change direction when a swipe occurs.
I have included the GameScene below:
class GameScene: SKScene {
enum Direction {
case Left
case Right
case Up
case Down
}
lazy var openDirectionPaths = [Direction: UIBezierPath]()
lazy var closedDirectionPaths = [Direction: UIBezierPath]()
lazy var wasClosedPath = false
lazy var needsToUpdateDirection = false
lazy var direction = Direction.Right
lazy var lastChange: NSTimeInterval = NSDate().timeIntervalSince1970
var touchBeganPoint: CGPoint?
let pacmanSprite = SKShapeNode(circleOfRadius: 15)
override func didMoveToView(view: SKView) {
let radius: CGFloat = 15, diameter: CGFloat = 30, center = CGPoint(x:radius, y:radius)
func createPaths(startDegrees: CGFloat, endDegrees: CGFloat, inout dictionary dic: [Direction: UIBezierPath]) {
var path = UIBezierPath(arcCenter: center, radius: radius, startAngle: startDegrees.toRadians(), endAngle: endDegrees.toRadians(), clockwise: true)
path.addLineToPoint(center)
path.closePath()
dic[.Right] = path
for d: Direction in [.Up, .Left, .Down] {
path = path.pathByRotating(90)
dic[d] = path
}
}
createPaths(35, 315, dictionary: &openDirectionPaths)
createPaths(1, 359, dictionary: &closedDirectionPaths)
pacmanSprite.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
pacmanSprite.fillColor = UIColor.yellowColor()
pacmanSprite.lineWidth = 2
if let path = openDirectionPaths[.Right] {
pacmanSprite.path = path.CGPath
}
pacmanSprite.strokeColor = UIColor.blackColor()
self.addChild(pacmanSprite)
updateDirection()
// Blocks to stop 'Pacman' changing direction outside of a defined path?
//375/25 = 15 width
//666/37 = 18 height
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
touchBeganPoint = positionOfTouch(inTouches: touches)
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
if let touchStartPoint = touchBeganPoint,
touchEndPoint = positionOfTouch(inTouches: touches) {
if touchStartPoint == touchEndPoint {
return
}
let degrees = atan2(touchStartPoint.x - touchEndPoint.x,
touchStartPoint.y - touchEndPoint.y).toDegrees()
var oldDirection = direction
switch Int(degrees) {
case -135...(-45): direction = .Right
case -45...45: direction = .Down
case 45...135: direction = .Left
default: direction = .Up
}
if (oldDirection != direction) {
needsToUpdateDirection = true
}
}
}
override func touchesCancelled(touches: Set<NSObject>!, withEvent event: UIEvent!) {
touchBeganPoint = nil
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
if let nodes = self.children as? [SKShapeNode] {
for node in nodes {
let p = node.position
let s = node.frame.size
//let s = node.size
if p.x - s.width > self.size.width {
node.position.x = -s.width
}
if p.y - s.height > self.size.height {
node.position.y = -s.height
}
if p.x < -s.width {
node.position.x = self.size.width + (s.width / 2)
}
if p.y < -s.height {
node.position.y = self.size.height + (s.height / 2)
}
if needsToUpdateDirection || NSDate().timeIntervalSince1970 - lastChange > 0.25 {
if let path = wasClosedPath ? openDirectionPaths[direction]?.CGPath : closedDirectionPaths[direction]?.CGPath {
node.path = path
}
wasClosedPath = !wasClosedPath
lastChange = NSDate().timeIntervalSince1970
}
updateDirection()
}
}
}
// MARK:- Helpers
func positionOfTouch(inTouches touches: Set<NSObject>) -> CGPoint? {
for touch in (touches as! Set<UITouch>) {
let location = touch.locationInNode(self)
return location
}
return nil
}
func updateDirection() {
if !needsToUpdateDirection {
return
}
pacmanSprite.removeActionForKey("Move")
func actionForDirection() -> SKAction {
let Delta: CGFloat = 25
switch (direction) {
case .Up:
return SKAction.moveByX(0.0, y: Delta, duration: 0.1)
case .Down:
return SKAction.moveByX(0.0, y: -Delta, duration: 0.1)
case .Right:
return SKAction.moveByX(Delta, y: 0.0, duration: 0.1)
default:
return SKAction.moveByX(-Delta, y: 0.0, duration: 0.1)
}
}
let action = SKAction.repeatActionForever(actionForDirection())
pacmanSprite.runAction(action, withKey: "Move")
needsToUpdateDirection = false
}
}
The repository can be found here
I have added the MIT license, so you can fork this repository if you wish. I hope this helps.

SpriteKit: Having trouble updating text of a SKLabelNode during runtime (2 approaches)

I want to set the text of a label based on a User's tapping on a Node. I've tried two approaches, neither of which have worked as intended.
Approach #1: Declare the SKLabelNode globally, update sklabelnode.text at runtime.
Code:
import SpriteKit
class GameScene: SKScene {
//Level 0
var q0Label:SKLabelNode!
var q1Label:SKLabelNode!
let gem = SKSpriteNode(imageNamed:"Destiny_Gem")
let energy = SKSpriteNode(imageNamed: "Destiny_Energy")
let money = SKSpriteNode(imageNamed: "Destiny_Money")
override func didMoveToView(view: SKView) {
//Level 0 - Choose your Destiny
//Add a label to the scene
q0Label = SKLabelNode(fontNamed: "Courier")
q0Label.text = "Why do you want to be a Doctor?"
q0Label.fontSize = 30
q0Label.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
self.addChild(q0Label)
q1Label = SKLabelNode(fontNamed: "Courier")
q1Label.fontSize = 25
q1Label.position = CGPoint(x:frame.size.width * 0.5, y: frame.size.height * 0.3)
//Position the sprites
gem.position = CGPoint(x:frame.size.width * 0.2, y: frame.size.height * 0.4)
gem.zPosition = 2
[gem.setScale(0.5)]
gem.name = "gem"
energy.position = CGPoint(x:frame.size.width * 0.5, y: frame.size.height * 0.4)
energy.zPosition = 2
[energy.setScale(0.5)]
energy.name = "energy"
money.position = CGPoint(x:frame.size.width * 0.8, y: frame.size.height * 0.4)
money.zPosition = 2
[money.setScale(0.25)]
money.name = "money"
//Add sprites to scene
addChild(gem)
addChild(energy)
addChild(money)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location = (touch as! UITouch).locationInNode(self)
if let theName = self.nodeAtPoint(location).name {
if theName == "gem" {
q1Label.text = "Like my parents before me, it is my destiny."
self.addChild(q1Label)
}
else if theName == "energy" {
q1Label.text = "The people of the world need my help."
self.addChild(q1Label)
}
else if theName == "money" {
q1Label.text = "I want to be rich and famous."
self.addChild(q1Label)
}
}
}
}
}
Problem: This will work the first time you click a Node, however the very next click, the application will crash, with this error message:
"Attemped to add a SKNode which already has a parent error"
I then read various solutions on SO about not declaring the object globally. That lead to Approach #2.
Approach #2: Declare the label conditionally.
Code:
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location = (touch as! UITouch).locationInNode(self)
if let theName = self.nodeAtPoint(location).name {
if theName == "gem" {
var q1Label:SKLabelNode!
q1Label = SKLabelNode(fontNamed: "Courier")
q1Label.fontSize = 25
q1Label.position = CGPoint(x:frame.size.width * 0.5, y: frame.size.height * 0.3)
q1Label.text = "Like my parents before me, it is my destiny."
//set destiny variable = gem
self.addChild(q1Label)
}
else if theName == "energy" {
var q1Label:SKLabelNode!
q1Label = SKLabelNode(fontNamed: "Courier")
q1Label.fontSize = 25
q1Label.position = CGPoint(x:frame.size.width * 0.5, y: frame.size.height * 0.3)
q1Label.text = "The people of the world need my help."
//set destiny variable = energy
self.addChild(q1Label)
}
else if theName == "money" {
var q1Label:SKLabelNode!
q1Label = SKLabelNode(fontNamed: "Courier")
q1Label.fontSize = 25
q1Label.position = CGPoint(x:frame.size.width * 0.5, y: frame.size.height * 0.3)
q1Label.text = "I want to be rich and famous."
//set destiny variable = money
self.addChild(q1Label)
}
}
}
}
}
Problem: This just creates the labels over the top of each other; I don't know how to clean up any that were created earlier.
Re-creating labels in this case is really unnecessary. You only want to update a label based on which button is clicked. The only thing you need to do is to create those two labels once in didMoveToView method and update them accordingly, like this (just copy/past this code to try):
import SpriteKit
class GameScene: SKScene {
//Level 0
var q0Label:SKLabelNode!
var q1Label:SKLabelNode!
let gem = SKSpriteNode(imageNamed:"Destiny_Gem")
let energy = SKSpriteNode(imageNamed: "Destiny_Energy")
let money = SKSpriteNode(imageNamed: "Destiny_Money")
override func didMoveToView(view: SKView) {
//Level 0 - Choose your Destiny
//Add a label to the scene
q0Label = SKLabelNode(fontNamed: "Courier")
q0Label.text = "Why do you want to be a Doctor?"
q0Label.fontSize = 30
q0Label.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
self.addChild(q0Label)
q1Label = SKLabelNode(fontNamed: "Courier")
q1Label.fontSize = 25
q1Label.position = CGPoint(x:frame.size.width * 0.5, y: frame.size.height * 0.3)
q1Label.text = ""
self.addChild(q1Label)
//Position the sprites
gem.position = CGPoint(x:frame.size.width * 0.35, y: frame.size.height * 0.4)
gem.zPosition = 2
[gem.setScale(0.5)]
gem.name = "gem"
energy.position = CGPoint(x:frame.size.width * 0.3, y: frame.size.height * 0.4)
energy.zPosition = 2
[energy.setScale(0.5)]
energy.name = "energy"
money.position = CGPoint(x:frame.size.width * 0.4, y: frame.size.height * 0.4)
money.zPosition = 2
[money.setScale(0.25)]
money.name = "money"
//Add sprites to scene
addChild(gem)
addChild(energy)
addChild(money)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location = (touch as UITouch).locationInNode(self)
if let theName = self.nodeAtPoint(location).name {
if theName == "gem" {
q1Label.text = "Like my parents before me, it is my destiny."
}
else if theName == "energy" {
q1Label.text = "The people of the world need my help."
}
else if theName == "money" {
q1Label.text = "I want to be rich and famous."
}
}
}
}
}
Just don't re-add those labels multiple times. And about the error you are getting...Keep in mind that node can have only one parent at the time, and that's why you are getting the error which saying that certain label already has a parent.