I have sprites moving across the screen, and if they are clicked then they disappear (i.e deleted).
I have overridden the touchesBegan func as follows:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("touch")
let touch = touches.first!
let location = touch.location(in: self)
for child in self.children {
if child.position == location {
child.removeFromParent()
}
}
}
This doesn't seem to have any effect, can someone tell me where I am going wrong?
In which class did you implement this method?
If it was in SKNode itself, you simply do:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.removeFromParent()
}
However, if this method is in SKScene, this way that was implemented would probably not work. Because child.position returns a point (x, y) where the touch was made. And you're trying to compare the touch point and position of the SKNode (center point), it's unlikely to work.
Instead of using this way, try using .nodeAtPoint, a method of SKScene.
For this you will need to put a value in the 'name' property of your SKNode:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("touch")
let touch = touches.first!
let positionInScene = touch.locationInNode(self)
let touchedNode = self.nodeAtPoint(positionInScene)
if let name = touchedNode.name
{
if name == "your-node-name"
{
touchedNode.removeFromParent()
}
}
}
Font: How do I detect if an SKSpriteNode has been touched
Related
Essentially, what I want is for when I touch a node, I want to be able to move it across the screen. The problem is that whenever I move my finger too fast, the node just stops following it.
The spriteNodes in particular that I'm trying to do this with have physics bodies and animating textures so I tried to do the same code with a completely plain spriteNode and I've encountered the same problem.
The code that I have here is pretty simple so I'm not sure if this is a problem with what I've written or if it's just a lag problem that I can't fix. It's also basically the same all throughout touchesBegan, touchesMoved and touchesEnded
for touch in touches {
let pos = touch.location(in: self)
let node = self.atPoint(pos)
if node.name == "activeRedBomb"{
node.position = pos
}
if node.name == "activeBlackBomb"{
node.position = pos
}
if node.name == "test"{
node.position.x = pos.x
node.position.y = pos.y
}
}
What's happening is that if you move your finger too fast, then at some point, the touch location will no longer be on the sprite, so you code to move the node won't fire.
What you need to do is set a flag in touchesBegan() to indicate that this sprite is touched, move the sprite to the location of the touch in touchesMoved() if the flag is set and then reset the flag in touchesEnded().
Here's roughly what you need to add for this:
import SpriteKit
class GameScene: SKScene {
var bombIsTouched = false
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
if activeRedBomb.contains(touch.location(in: self)) {
bombIsTouched = true
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if bombIsTouched {
activeRedBomb.position = (touches.first?.location(in: self))!
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if bombIsTouched {
bombIsTouched = false
}
}
I want to be able to determine the x,y location where the user clicked a UIImageView in Swift.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let position = touch.location(in: imageView)
print(position.x)
print(position.y)
}
}
So I've been messing around trying to get the coordinates of touches on the screen. So far I can get the coordinates of one touch with this:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
let touch = touches.anyObject()! as UITouch
let location = touch.locationInView(self.view)
println(location)
}
But when touching with two fingers I only get the coordinates of the first touch. Multi-touch works (I tested with this little tutorial: http://www.techotopia.com/index.php/An_Example_Swift_iOS_8_Touch,_Multitouch_and_Tap_Application). So my question is, how do I get the coordinates of the second (and third, fourth...) touch?
** Updated to Swift 4 and Xcode 9 (8 Oct 2017) **
First of all, remember to enable multi-touch events by setting
self.view.isMultipleTouchEnabled = true
in your UIViewController's code, or using the appropriate storyboard option in Xcode:
Otherwise you'll always get a single touch in touchesBegan (see documentation here).
Then, inside touchesBegan, iterate over the set of touches to get their coordinates:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self.view)
print(location)
}
}
the given touches argument is a set of detected touches.
You only see one touch because you select one of the touches with :
touches.anyObject() // Selects a random object (touch) from the set
In order to get all touches iterate the given set
for obj in touches.allObjects {
let touch = obj as UITouch
let location = touch.locationInView(self.view)
println(location)
}
You have to iterate over the different touches. That way you can access every touch.
for touch in touches{
//Handle touch
let touchLocation = touch.locationInView(self.view)
}
In Swift 1.2 this has changed, and touchesBegan now provides a Set of NSObjects.
To iterate through them, cast the touches collection as a Set of UITouch objects as follows:
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
var touchSet = touches as! Set<UITouch>
for touch in touchSet{
let location = touch.locationInView(self.view)
println(location)
}
}
For Swift 3, based on #Andrew's answer :
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touchSet = touches
for touch in touchSet{
let location = touch.location(in: self.view)
print(location)
}
}
EDIT, My bad, that's not answering your question, had the same problem and someone linked me to this previous answer :
Anyway, I had to change few things to make it works in swift 3, here is my current code :
var fingers = [String?](repeating: nil, count:5)
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
for touch in touches{
let point = touch.location(in: self.view)
for (index,finger) in fingers.enumerated() {
if finger == nil {
fingers[index] = String(format: "%p", touch)
print("finger \(index+1): x=\(point.x) , y=\(point.y)")
break
}
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesMoved(touches, with: event)
for touch in touches {
let point = touch.location(in: self.view)
for (index,finger) in fingers.enumerated() {
if let finger = finger, finger == String(format: "%p", touch) {
print("finger \(index+1): x=\(point.x) , y=\(point.y)")
break
}
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
for touch in touches {
for (index,finger) in fingers.enumerated() {
if let finger = finger, finger == String(format: "%p", touch) {
fingers[index] = nil
break
}
}
}
}
I still have a little problem but I think it's linked to my GestureRecognizer in my code.
But that should do the trick.
It will print you the coordinate of each point in your consol.
In Swift 3,4
Identify touch pointer by its hash:
// SmallDraw
func pointerHashFromTouch(_ touch:UITouch) -> Int {
return Unmanaged.passUnretained(touch).toOpaque().hashValue
}
Ok so currently in my game I have a ball that can be thrown. However, I want to make so that the user can only throw the ball past a certain point. I have been trying this for a while but I can't figure it out. How can I do this?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first as! UITouch?
let location = touch?.location(in: self)
if ball.frame.contains(location!) {
touchPoint = location!
touching = true
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first as! UITouch?
let location = touch?.location(in: self)
touchPoint = location!
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
touching = false
}
override func update(_ currentTime: TimeInterval) {
if touching {
let dt:CGFloat = 2.8/60.0
let distance = CGVector(dx: touchPoint.x-ball.position.x, dy: touchPoint.y-ball.position.y)
let velocity = CGVector(dx: distance.dx/dt, dy: distance.dy/dt)
ball.physicsBody!.velocity=velocity
}
}
Here, I have an image of my game so far. Currently, the ball can be dragged, thrown, or swiped anywhere on the screen. However, I want to make so the ball can only be touched, thrown, or dragged below the middle of the screen. But I want the ball to continue being thrown if the user's finger accidently goes about the limit.
you will have to adjust the coordinates for your bottom area based on actual size and game scene anchorPoint. for example "100" in the sample assumes that your scene has an anchorPoint of (0,0) and the size of the bottom scroll area is 100.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first as UITouch! {
let location = touch.location(in: self)
guard location < 100 else { return }
//if ball.frame.contains(location!) {
touchPoint = location!
touching = true
//}
}
}
I have a custom class that is an SKNode, which in turn has several SKSpriteNodes in it. Is there a way I can detect touches on these child SKSpriteNodes from my game scene?
I'm working in swift
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
let touch = touches.anyObject() as UITouch
let touchLocation = touch.locationInNode(self)
if([yourSprite containsPoint: touchLocation])
{
//sprite contains touch
}
}
Source: http://www.raywenderlich.com/84434/sprite-kit-swift-tutorial-beginners
Examine Apple's SceneKitVehicle demo. Someone kindly ported it to Swift.
The code you want is in the GameView.swift file. In the GameView you'll see the touchesBegan override. Here's my version of it for Swift 2.1:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
guard let scene = self.overlaySKScene else {
return
}
let touch = touches.first!
let viewTouchLocation = touch.locationInView(self)
let sceneTouchPoint = scene .convertPointFromView(viewTouchLocation)
let touchedNode = scene.nodeAtPoint(sceneTouchPoint)
if (touchedNode.name == "Play") {
print("play")
}
}
If it's not clear; the GameView is set as the app's view class by way of the Storyboard.
You'll need to compare the location of your Touch to the location of your SKNode
You can get the location of your touch at one of the following methods, using locationInNode():
touchesBegan()
touchesMoved()
touchesEnded()
Swift 5+
If you wish to encapsulate touch logic in a node and deal with it locally, you can simply set interaction to true in the corresponding node.
isUserInteractionEnabled = true
And then, of course, override touchesBegan to your desire.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {}
If you still wish to receive touches in the scene when touches occur inside a child node, you can, for instance, define a protocol and property for the child node's delegate and set the scene to be it.
e.g:
final class GameScene: SKScene {
private let childNode = ChildNode()
override func didMove(to view: SKView) {
addChild(childNode)
childNode.delegate = self
}
}
extension GameScene: TouchDelegate {}
protocol TouchDelegate {
func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
}
final class ChildNode: SKSpriteNode {
var delegate: TouchDelegate?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
delegate?.touchesBegan(touches, with: event)
}
}