Reputation: 23
I've been researching, and definitely trying for a while, to find a way to activate a function when you tap a sprite. For example: If you tap the blue sprite, it activates blue()
. Tap the red sprite, it activates red()
. I have been searching for a while now and all the answers are either for older versions, or downright just don't work for me. Anybody have any ideas?
EDIT: Here is some of my code that I am using.
class GameScene: SKScene {
var blue = SKSpriteNode()
var red = SKSpriteNode()
var green = SKSpriteNode()
var help = SKLabelNode()
var score = SKLabelNode()
var points = 0
var loseAmount = 1.0
var firstAdvance = 0
var loseTimer = Timer()
override func didMove(to view: SKView) {
self.physicsWorld.contactDelegate = self
blue = self.childNode(withName: "blue") as! SKSpriteNode
blue.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2)
blue.name = "blue"
blue.isUserInteractionEnabled = true
red = self.childNode(withName: "red") as! SKSpriteNode
red.position = CGPoint(x: self.frame.width / 2 + 100, y: self.frame.height / 2)
red.name = "red"
red.isUserInteractionEnabled = true
green = self.childNode(withName: "green") as! SKSpriteNode
green.position = CGPoint(x: self.frame.width / 2 - 100, y: self.frame.height / 2)
green.name = "green"
green.isUserInteractionEnabled = true
help = self.childNode(withName: "help") as! SKLabelNode
help.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 4 * 3)
help.name = "help"
help.isUserInteractionEnabled = false
score = self.childNode(withName: "score") as! SKLabelNode
score.position = CGPoint(x: self.frame.width / 2, y: self.frame.height - 40)
score.name = "score"
score.text = "\(points)"
score.isUserInteractionEnabled = false
}
func randomMove() {
blue.position = CGPoint(x:Int(arc4random_uniform(244)+38),y:Int(arc4random_uniform(404)+38))
red.position = CGPoint(x:Int(arc4random_uniform(244)+38),y:Int(arc4random_uniform(404)+38))
green.position = CGPoint(x:Int(arc4random_uniform(244)+38),y:Int(arc4random_uniform(404)+38))
}
func advance() {
if (firstAdvance == 0) {
firstAdvance = 1
help.removeFromParent()
points += 1
playPointSound()
randomMove()
loseTimer = Timer.scheduledTimer(timeInterval: loseAmount, target: self, selector: #selector(GameScene.lose), userInfo: nil, repeats: true)
} else if (firstAdvance == 1) {
points += 1
loseAmount -= 0.01
playPointSound()
self.loseTimer.invalidate()
loseTimer = Timer.scheduledTimer(timeInterval: loseAmount, target: self, selector: #selector(GameScene.lose), userInfo: nil, repeats: true)
}
}
func lose() {
playLoseSound()
let endSceneTemp = EndScene(fileNamed: "EndScene")
self.scene?.view?.presentScene(endSceneTemp!, transition: SKTransition.crossFade(withDuration: 0.1))
}
func playPointSound() {
let path = Bundle.main.path(forResource: "", ofType:nil)!
let url = URL(fileURLWithPath: path)
do {
let sound = try AVAudioPlayer(contentsOf: url)
pointSound = sound
sound.play()
} catch {
// couldn't load file :(
}
}
func playLoseSound() {
let path = Bundle.main.path(forResource: "", ofType:nil)!
let url = URL(fileURLWithPath: path)
do {
let sound = try AVAudioPlayer(contentsOf: url)
loseSound = sound
sound.play()
} catch {
// couldn't load file
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in (touches) {
let positionInScene = touch.location(in: self)
let touchedNode = self.atPoint(positionInScene)
if let name = touchedNode.name {
if name == "blue" {
advance()
}
if name == "red" || name == "green"{
lose()
}
}
}
}
override func update(_ currentTime: TimeInterval) {
}
}
Upvotes: 2
Views: 1181
Reputation: 2641
What worked best for me was to add a UITapGestureRecognizer to the SKView and then handle tap gestures on that within the scene.
When the taps are made you can get the location in view and then convert that to the location in the scene. With that you can look for the nodeAtPoint:
for the tap location.
When you have that node you then check its name and perform an action on that SKSpriteNode if its name is one you want to do something on a tap.
While you can do this with overriding touchesBegan:
, touchesMoved:
and such you save a little effort when you are attempting to capture more complex touches such as a pinch as you don't need to figure out what is a tap vs. long press vs. pinch first.
Upvotes: 0
Reputation: 2212
you just need to assign a name for your sprites:
let redSpriteNode = SKSpriteNode(imageNamed: "red") // add sprite by code
//let redSpriteNode = self.childNode(withName: "red") as! SKSpriteNode // for adding from .sks file
redSpriteNode.name = "red"
let blueSpriteNode = SKSpriteNode(imageNamed: "blue")
redSpriteNode.name = "blue"
and in touches began method activate the desire function.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in (touches) {
let positionInScene = touch.location(in: self)
let touchedNode = self.atPoint(positionInScene)
if let name = touchedNode.name {
if name == "red" {
red()
}
if name == "blue" {
blue()
}
}
}
}
you can find all nodes with the same name like this: (reference)
self.enumerateChildNodes(withName: "red") {_,_ in
print(count)
count = count + 1
}
Upvotes: 2