Set<UITouch> not working in iOS Swift game - ios

I am making a game similar to Fruit Ninja using Swift 2.0 in Xcode v7.0. However, in the touchesBegan, touchesMoved, and touchesCancelled override functions, I am getting the three following errors:
"Value of type 'Set' has no member 'anyObject'" comes up twice and
"Value of optional type 'Set' not unwrapped; did you mean to use "!" or "?"?" comes once.
Here is the code
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.anyObject() as UITouch
let location = touch.locationInNode(self)
activeSlicePoints.append(location)
redrawActiveSlice()
activeSliceBG.removeAllActions()
activeSliceFG.removeAllActions()
activeSliceBG.alpha = 1
activeSliceFG.alpha = 1
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.anyObject() as UITouch
let location = touch.locationInNode(self)
activeSlicePoints.append(location)
redrawActiveSlice()
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
activeSliceBG.runAction(SKAction.fadeOutWithDuration(0.25))
activeSliceFG.runAction(SKAction.fadeOutWithDuration(0.25))
}
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
touchesEnded(touches, withEvent: event)
}
Here is an image of on what lines the errors appear
All help appreciated. Thanks in advance.

let touch = touches.first as? UITouch
This will get you the first touch object.
Use it like:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let touch = touches.first {
// ...
}
super.touchesBegan(touches, withEvent:event)
}

Related

Swift: record touch force, size, duration

For a data analysis project, I want to track the measurements for touch force, size and duration in a log-file for a simple app (I use the Foodtracker app from the Apple Documentation Website).
I know that I can get the force, size and duration from UITouch. But
how do I access UITouch to get these measurements?
and how do I write these measurements into a log-file?
1. How do I access UITouch to get these measurements?
You'll have to override the touch handlers in your view controller.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
let touch = touches.first!
print("\(touch.force)")
print("\(touch.majorRadius)")
print("\(touch.timestamp)")
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesMoved(touches, with: event)
let touch = touches.first!
print("\(touch.force)")
print("\(touch.majorRadius)")
print("\(touch.timestamp)")
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesCancelled(touches, with: event)
let touch = touches.first!
print("\(touch.force)")
print("\(touch.majorRadius)")
print("\(touch.timestamp)")
}
2. How do I write these measurements into a log-file?
For that checkout this post: Read and write a String from text file

SpriteKit: How to detect touches on node that began outside of node

SKNode A is a parent of SKNode B.
If touches begin inside of SKNode B, the touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) function gets called.
If, however, the touches begin outside of SKNode B but move into SKNode B, the touchesMoved function never gets called.
One option is to handle all touch events inside SKNode A.
However, there are many nodes contained inside SKNode A. Ideally, we could push touch functionality into each child, as opposed to handling everything from SKNode A.
Is it possible to capture touch events that occur inside SKNode B even if they began outside of SKNode B?
When you hit your touchesBegan method, your touch is limited to the coordinate system of that node until the point it is ended. Moving onto another node will not change the coordinate system to the new node. If B is the only node that requires the touch, then you can add a child to cover the entire scene to ensure that B gets fired.
class TouchNode : SKSpriteNode
{
//if you need to override other inits do it here
convenience init(withSize size:CGSize)
{
self.init(color:UIColor(red:0,green:0,blue:0,alpha:0.1),size: size)
isUserInteractionEnabled = true
}
override func touchesBegan(touches: Set<UITouches>, withEvent event: UIEvent?) {
parent!.touchesBegan(touches:touches, withEvent:event)
}
override func touchesMoved(touches: Set<UITouches>, withEvent event: UIEvent?) {
parent!.touchesMoved(touches:touches, withEvent:event)
}
override func touchesEnded(touches: Set<UITouches>, withEvent event: UIEvent?) {
parent!.touchesEnded(touches:touches, withEvent:event)
}
override func touchesCancelled(touches: Set<UITouches>, withEvent event: UIEvent?) {
parent!.touchesCancelled(touches:touches, withEvent:event)
}
}
Then in your NodeB class:
required init(coder aDecoder:NSCoder)
{
super.init(coder:aDecoder)
DispatchQueue.main.async{
self.addChild(TouchNode(withSize:self.scene!.size))
}
}
override func touchesBegan(touches: Set<UITouches>, withEvent event: UIEvent?) {
//do stuff
}
override func touchesMoved(touches: Set<UITouches>, withEvent event: UIEvent?) {
//do stuff
}
override func touchesEnded(touches: Set<UITouches>, withEvent event: UIEvent?) {
//do stuff
}
override func touchesCancelled(touches: Set<UITouches>, withEvent event: UIEvent?) {
//do stuff
}
Edit: Misread question, but leaving the answer in case somebody else needs to go from inside the node to outside.
Think about it, you want to touch nodeB outside of nodeB, this does not make sense. It is like me poking the air and you crying that I am poking you. But if you absolutely need to go outside of the bounds, then add a child node to the sprite when you touch it that extends beyond the node itself, and be sure to transfer the touch back up to the parent
class TouchNode : SKSpriteNode
{
//if you need to override other inits do it here
convenience init(withSize size:CGSize)
{
self.init(color:UIColor(red:0,green:0,blue:0,alpha:0.1),size: size)
isUserInteractionEnabled = true
}
override func touchesBegan(touches: Set<UITouches>, withEvent event: UIEvent?) {
parent!.touchesBegan(touches:touches, withEvent:event)
}
override func touchesMoved(touches: Set<UITouches>, withEvent event: UIEvent?) {
parent!.touchesMoved(touches:touches, withEvent:event)
}
override func touchesEnded(touches: Set<UITouches>, withEvent event: UIEvent?) {
parent!.touchesEnded(touches:touches, withEvent:event)
}
override func touchesCancelled(touches: Set<UITouches>, withEvent event: UIEvent?) {
parent!.touchesCancelled(touches:touches, withEvent:event)
}
}
Then in your NodeB class:
lazy var touchNode = TouchNode(withSize:self.scene!.size)
override func touchesBegan(touches: Set<UITouches>, withEvent event: UIEvent?) {
addChild(touchNode)
//do other stuff
}
override func touchesEnded(touches: Set<UITouches>, withEvent event: UIEvent?) {
touchNode.removeFromParent()
//do other stuff
}
override func touchesCancelled(touches: Set<UITouches>, withEvent event: UIEvent?) {
touchNode.removeFromParent()
//do other stuff
}

Exceeding the maximum number of touches makes the program not to call the touchesEnded method?

Ive just started learning programming in general and ran into a problem:
I have read some articles about that the iPhones are only capable of tracking 5 touches or so... But I realised that when I touch the screen with e.g. 7 fingers at once, my program-let stops working.
So, anyone knows, which parts of the code malfunctions when I am touching the screen way too many times at once?
(I am a newbie.)
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first!
touchLocation = touch.locationInNode(self)
nrTouches += touches.count
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
nrTouches -= touches.count
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first!
touchLocation = touch.locationInNode(self)
}
override func update(currentTime: CFTimeInterval) {
if nrTouches > 0 {
touchingLabel.text = "touching"
} else {
touchingLabel.text = "not touching"
}
}
So, in the case I am touching with 7 fingers at once, "touching" will be displayed all the time.
tankyuu
You're missing touchesCancelled, which gets called when the 6th finger is put down:
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
if let touches = touches {
nrTouches -= touches.count // same logic as touchesEnded
}
}
An interesting note: The iPad can handle 11 touch events. More on that here.

how to override touch functions properly in iOS 9, swift 2

Well, I says on the lines changeColorTo(touch: touches.anyObject() as? UITouch)
this error "value of type "Set" has no member "anyObject"
How can I fix the problem?
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
changeColorTo(touch: touches.anyObject() as? UITouch)
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
changeColorTo(touch: touches.anyObject() as? UITouch)
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
changeColorTo(touch: touches.anyObject() as? UITouch)
}
func changeColorTo(touch touch: UITouch? ) {
if let contact = touch {
changeColorTo(point: contact.locationInView(self))
}
}
func changeColorTo(point point: CGPoint ) {
// Change the color model to the color displayed at the given view coordinate
if let color = colorModel {
let bounds = self.bounds
if bounds.contains(point) {
color.hue = Float((point.x-bounds.minX)/bounds.width*360)
color.saturation = Float((point.y-bounds.minY)/bounds.height*100)
}
}
}
Thanks in advance!
You should not pass UITouch set to CGPoint.
Try the below to solve the issues,
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
let touch = touches.anyObject()! as UITouch
let location = touch.locationInView(self)
changeColorTo(location)
}
func changeColorTo(point: CGPoint ) {
}

Overriding touchesBegan in Swift

I am overriding:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent)
in Swift.
I am wondering, is this correct for getting one touch point:
var touchPoint: CGPoint! = event.touchesForView(self)?.anyObject()?.locationInView(self)
Thanks in advance!
As of iOS 8.3, touchesBegan takes a touches parameter which is a Set<NSObject>. It's now Set<UITouch>. So, you would:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let point = touches.first?.location(in: view) else { return }
// use `point` here
}
In previous iOS versions, touchesBegan was defined as a NSSet parameter, as outlined in the question, so you would:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
if let touch = touches.anyObject() as? UITouch {
let touchPoint = touch.locationInView(view)
...
}
}

Resources