I want calculate user touch's point area - ios

I want to check the area of User's touch using touch.location()
how can i divide circe with equal 10 parts and user detect area of touch's position
if user touch that area then i want display "1" at label
(image have 4 pieces but I want 10 pieces)

Following example divide a view's touch area into sectors like cutting pizzas pieces. The view's center point is considered as an original point of the coordinate. Then we calculate the radians of the line between touch point and center point to find out which piece it's in.
class ExampleView: UIView {
let numberOfPieces = 10
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
let touch = touches.first
if let location = touch?.location(in: self) {
let centerPoint = CGPoint(x:self.bounds.midX,y:self.bounds.midY)
let radians = atan2(location.y - centerPoint.y,location.x - centerPoint.x)
var degrees = radians * (180.0 / CGFloat.pi) + 180.0 // adding 180 for making the first piece at left side.
degrees = (degrees > 0.0 ? degrees : (360 + degrees))
let piece = Int(degrees / (360.0 / CGFloat(numberOfPieces))) + 1
print("piece \(piece) touched.")
}
}
}
The default UIView's coordinate system is:
270
180 0
90
So we add 180 degree to rotate it to:
90
0 180
270
Then the first piece is at left side as needed in the diagram.

Related

Rotate sprite node with moving touch

I am new to Swift and SpriteKit and am learning to understand the control in the game "Fish & Trip". The sprite node is always at the center of the view and it will rotate according to moving your touch, no matter where you touch and move (hold) it will rotate correspondingly.
The difficulty here is that it is different from the Pan Gesture and simple touch location as I noted in the picture 1 and 2.
For the 1st pic, the touch location is processed by atan2f and then sent to SKAction.rotate and it is done, I can make this working.
For the 2nd pic, I can get this by setup a UIPanGestureRecognizer and it works, but you can only rotate the node when you move your finger around the initial point (touchesBegan).
My question is for the 3rd pic, which is the same as the Fish & Trip game, you can touch anywhere on the screen and then move (hold) to anywhere and the node still rotate as you move, you don't have to move your finger around the initial point to let the node rotate and the rotation is smooth and accurate.
My code is as follow, it doesn't work very well and it is with some jittering, my question is how can I implement this in a better way? and How can I make the rotation smooth?
Is there a way to filter the previousLocation in the touchesMoved function? I always encountered jittering when I use this property, I think it reports too fast. I haven't had any issue when I used UIPanGestureRecoginzer and it is very smooth, so I guess I must did something wrong with the previousLocation.
func mtoRad(x: CGFloat, y: CGFloat) -> CGFloat {
let Radian3 = atan2f(Float(y), Float(x))
return CGFloat(Radian3)
}
func moveplayer(radian: CGFloat){
let rotateaction = SKAction.rotate(toAngle: radian, duration: 0.1, shortestUnitArc: true)
thePlayer.run(rotateaction)
}
var touchpoint = CGPoint.zero
var R2 : CGFloat? = 0.0
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches{
let previousPointOfTouch = t.previousLocation(in: self)
touchpoint = t.location(in: self)
if touchpoint.x != previousPointOfTouch.x && touchpoint.y != previousPointOfTouch.y {
let delta_y = touchpoint.y - previousPointOfTouch.y
let delta_x = touchpoint.x - previousPointOfTouch.x
let R1 = mtoRad(x: delta_x, y: delta_y)
if R2! != R1 {
moveplayer(radiant: R1)
}
R2 = R1
}
}
}
This is not an answer (yet - hoping to post one/edit this into one later), but you can make your code a bit more 'Swifty' by changing the definition for movePlayer() from:
func moveplayer(radian: CGFloat)
to
rotatePlayerTo(angle targetAngle: CGFloat) {
let rotateaction = SKAction.rotate(toAngle: targetAngle, duration: 0.1, shortestUnitArc: true)
thePlayer.run(rotateaction)
}
then, to call it, instead of:
moveplayer(radiant: R1)
use
rotatePlayerTo(angle: R1)
which is more readable as it describes what you are doing better.
Also, your rotation to the new angle is constant at 0.1s - so if the player has to rotate further, it will rotate faster. it would be better to keep the rotational speed constant (in terms of radians per second). we can do this as follows:
Add the following property:
let playerRotationSpeed = CGFloat((2 *Double.pi) / 2.0) //Radian per second; 2 second for full rotation
change your moveShip to:
func rotatePlayerTo(angle targetAngle: CGFloat) {
let angleToRotateBy = abs(targetAngle - thePlayer.zRotation)
let rotationTime = TimeInterval(angleToRotateBy / shipRotationSpeed)
let rotateAction = SKAction.rotate(toAngle: targetAngle, duration: rotationTime , shortestUnitArc: true)
thePlayer.run(rotateAction)
}
this may help smooth the rotation too.

Making UIImageView (Image of an arrow) pointing where I touch on the screen

I have tried too many equations to get the right answer, maybe something wrong with the code or my understanding of the idea. However, here is my code:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let coord = touch.location(in:view)
self.linegu.transform = CGAffineTransform.init(rotationAngle: atan((coord.y - (self.view.center.y + (self.view.center.y)/2.5)) / (coord.x - self.view.center.x)))
}
}
linegu is the UIImageView I'm using and I position it in the middle of the view by using this code:
let Ypos = (self.view.center.y/2.5);
self.linegu.center = self.view.center
self.linegu.center.y = (self.view.center.y + Ypos)
It doesn't matter where the image view is located. And you should throw away your "magic number" 2.5. You are way overthinking this.
Assume arrow is the image view, and that it starts out life horizontal with the arrow pointing to the right. And assume that the background view has a tap gesture recognizer on it. (We use a tap gesture recognizer for simplicity; it looks like you might eventually want to use a pan gesture recognizer. But for now, let's just get this thing working.)
Then here is how the tap gesture's action handler would look:
let c = self.arrow.center
let p = t.location(in: self.arrow.superview)
let angle = atan2(p.y - c.y, p.x - c.x)
self.arrow.transform = CGAffineTransform(rotationAngle:angle)
It's as simple as that.
Why do you use this weird formula?
CGAffineTransform.init(rotationAngle: atan((coord.y - (self.view.center.y + (self.view.center.y)/2.5)) / (coord.x - self.view.center.x)))
And where does this 2.5 divider come from?
What about just using .center or .frame to position the UIImageView?
Like:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let location = touch.location(in: view)
imageView.center = location // may need to apply some offset here, depending on where exactly the arrow points in the arrow image
}
}

How do I make an if statement for my rotating circle in Swift?

I have this circle and it can rotate 360 degrees to the left and right when the user has their finger on the node and is rotating. I need to figure out how to make an if statement so when it rotates to the left I can add an action and when it rotates to the right I can add another action. Here is the code I have:
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches {
let location = touch.locationInNode(self)
let node = self.nodeAtPoint(location)
if node.name == "rotatecircle" {
//lets user rotate circle like a knob when there is one finger on node.
let dy = circle.position.y - location.y
let dx = circle.position.x - location.x
let angle2 = atan2(dy, dx)
circle.zRotation = angle2
}
}
}
One approach would be to compare the angle2 value to the angle value from the previous touch. You can then create an if statement that does what you want based on the direction of the rotation.
Some pseudo-code:
In your class:
var previousAngle:Double
In touchesMoved
let delta = (angle2 - previousAngle) mod M_PI
if delta > 0 {
// do action 1
}
else {
// do action 2
}
previousAngle = angle2
You will need some logic to check if this is the first touch. In that case you don't have a previousAngle yet, so you don't want to take an action.

Detecting tap outside/away from a sprite

I have a game where there is a green circle that spawns randomly at random locations on a scene, and every time the circle is tapped it changes location, with a slight possibility to change to red. When the circle is red, I want the user to tap away screen real estate that is not the red circle. How do I detect a tap not on the circle? My circle is a SKShapeNode. I handle touches with the touchesBegan function.
To determine if the user's touch is inside or outside of a circle, 1) compute the distance between the touch and the center of the circle and 2) compare if that distance is less than or equal to the radius of the circle. Here's an example of how to do that:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches {
let location = touch.locationInNode(self)
let dx = location.x - circle.position.x
let dy = location.y - circle.position.y
let distance = sqrt(dx*dx + dy*dy)
if (distance <= CGFloat(radius)) {
print ("inside of circle")
}
else {
print ("outside of circle")
}
}
}

Rotating SKNode to point at touch contact point

Context: I'm using Xcode, Swift, and SpriteKit
I've created a separate class file "Ship.swift" and within it I've got:
let RAD_PER_SEC: CGFloat = 0.1
var direction = 0
//Updates object value for determining how much to rotate object
func spin {
}
Ideally I want to make an app sort of like the old game Astroids. For now, I just a ship that rotates in the center of the screen and points towards the touch-contact point.
If you want to rotate node towards the touch location you need to know the angle to rotate to. Because in Spritekit angles are measured in radians there are some conversions that have to be done:
let Pi = CGFloat(M_PI)
let DegreesToRadians = Pi / 180
After that you have to use atan2() to calculate the angle...Here is simple example which rotates sprite using touchesMoved method:
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
let curTouch = touches.anyObject() as UITouch
let curPoint = curTouch.locationInNode(self)
let deltaX = self.yourNode.position.x - curPoint.x
let deltaY = self.yourNode.position.y - curPoint.y
let angle = atan2(deltaY, deltaX)
self.yourNode.zRotation = angle + 90 * DegreesToRadians
}
As of iOS8 Apple added SKConstraints which can be added to SKNodes. Here's the documentation: https://developer.apple.com/library/mac/documentation/SpriteKit/Reference/SKConstraint_Ref/index.html#//apple_ref/occ/cl/SKConstraint
In your case you'll want to create the constraint when the user touches the screen - SKConstraint.orientToPoint(touchLocation, offset: SKRange.rangeWithConstantValue(0))
And the add it to your sprite node using the constraints property.

Resources