I'm new in Swift and I'm trying to let the user draw a rectangle (touching and dragging) to select an area of an image just like when cropping but I don't want to crop I just want to know the CGRect the user created.
So far I have a .xib with a UIImage inside and its ViewController. I want to draw above the image but every tutorial I found about drawing is about subclassing UIView, override drawRect and put that as the xib class.
I figured it out. I just created a uiview and change its frame depending on the touches events
let overlay = UIView()
var lastPoint = CGPointZero
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
overlay.layer.borderColor = UIColor.blackColor().CGColor
overlay.backgroundColor = UIColor.clearColor().colorWithAlphaComponent(0.5)
overlay.hidden = true
self.view.addSubview(overlay)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
//Save original tap Point
if let touch = touches.first {
lastPoint = touch.locationInView(self.view)
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
//Get the current known point and redraw
if let touch = touches.first {
let currentPoint = touch.locationInView(view)
reDrawSelectionArea(lastPoint, toPoint: currentPoint)
}
}
func reDrawSelectionArea(fromPoint: CGPoint, toPoint: CGPoint) {
overlay.hidden = false
//Calculate rect from the original point and last known point
let rect = CGRectMake(min(fromPoint.x, toPoint.x),
min(fromPoint.y, toPoint.y),
fabs(fromPoint.x - toPoint.x),
fabs(fromPoint.y - toPoint.y));
overlay.frame = rect
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
overlay.hidden = true
//User has lift his finger, use the rect
applyFilterToSelectedArea(overlay.frame)
overlay.frame = CGRectZero //reset overlay for next tap
}
Related
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)
}
}
I'm trying to write a "normalizing offset function" to give the effect that when the user touches/moves the sprite, that it does not snap to the center of the touch (the default behavior). The offset function should probably address the anchor point during "touches began, and touches move", and then revert back to the center when touches ended.enter link description here
class GameScene: SKScene {
private var redSquare : SKSpriteNode?
private var originalAnchorPoint: CGPoint = CGPoint(x: 0.5, y: 0.5)
override func didMove(to view: SKView) {
// Get label node from scene and store it for use later
self.redSquare = self.childNode(withName: "redSquare") as? SKSpriteNode
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in (touches ) {
let location = touch.location(in: self)
redSquare?.position = location
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in (touches ) {
let location = touch.location(in: self)
if (self.redSquare?.contains(location))!{
redSquare?.position = location
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
// set red sprite anchor position to originalAnchorPoint
}
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'm currently working on a game in swift using spritekit. I've got my joystick working using this library, and thats all good. I'm also moving the joystick to where the user taps using this code:
func updateJoystickPosition(pos: CGPoint) {
let posX = -(self.sceneSize.width/2) + pos.x
let posY = (self.sceneSize.height/2) - pos.y
let newJoystickPos = CGPoint(x: posX, y: posY);
self.joystick.position = newJoystickPos
}
which also works just fine, however, the joystick doesn't engage on that one tap. You have to tap on the actual joystick node for the joystick to engage, so obviously, i'd want the user to put their finger down on the screen and immediately be able to start moving it around to move the player.
the joystick it's self starts tracking with this function
open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print(touches)
if let touch = touches.first, stick == atPoint(touch.location(in: self)) {
tracking = true
startHandler?()
}
}
Question: Is there anyway i can modify the touchesBegan function or any of my other functions to achieve the desired results?
You have to override touchesMoved(_ touches: ,with event:) and in this method just processing all touches.
For example:
var startTouchingPoint = CGPoint.zero // property
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
startTouchingPoint = touch.location(in: self.camera!))
yourControllerPlace.position = startTouchingPoint
stickOnYourJoystick.position = CGPoint.zero
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let point = touch.location(in: self.camera!))
let convertedPoint = CGPoint(x: point.x - startTouchingPoint.x,
y: point.y - startTouchingPoint.y)
stickOnYourJoystick.position = convertedPoint
}
}
So I have created a button with a border in my storyboard.
and then I rounded its corners and added a border color:
button.layer.cornerRadius = button.bounds.size.width / 2
button.layer.borderColor = greenColor
So the runtime result looks like this:
However the user can tap slightly outside the area of the button (where the corners used to be) and still call the button function. Is there a way to restrict the enabled area of the button to just be the circle?
With other answers you block the touch, I needed it to fall through.
And its even easier:
1) Setup your preferred path (for me circle)
private var touchPath: UIBezierPath {return UIBezierPath(ovalIn: self.bounds)}
2) Override point inside function
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return touchPath.contains(point)
}
All inside you UIButton subclass.
So I figured it out. Basically I have to detect the touch on the button, and then calculate the distance between the touch and the center of the button. If that distance is less than the radius of the circle (the width of the button / 2) then the tap was inside the circle.
Here's my code:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let radius:CGFloat = (self.frame.width / 2)
var point:CGPoint = CGPoint()
if let touch = touches.first {
point = touch.locationInView(self.superview)
}
let distance:CGFloat = sqrt(CGFloat(powf((Float(self.center.x - point.x)), 2) + powf((Float(self.center.y - point.y)), 2)))
if(distance < radius) {
super.touchesBegan(touches, withEvent: event)
}
}
(SWIFT 3) This solution works with all the buttons not just with round. Before we have to create path as a private property of the button class and after we can easily write this:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let location = touch.location(in: self)
if path.contains(location) {
print("This print is shown only in case of button location tap")
}
}
}