get line to remain a perfect 90 degrees when create - swift

My swift code's goal is to get every line to only be able to be place at a 90 degree angle. Right now the code has two points a start and end where the start point is fixed upon touching the uiview. I would the user to be able to touch a point and only be able to extend the line at a 90 degree angle. Look at the gif below for more info. The bottom line is what i am trying to acheive. I think you have to use guard in touches began.
import UIKit
class ViewController2: UIViewController {
#IBOutlet weak var drawingPlace: UIImageView!
var startTouch : CGPoint?
var secondTouch : CGPoint?
var currentContext : CGContext?
var prevImage : UIImage?
override func viewDidLoad() {
super.viewDidLoad()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
startTouch = touch?.location(in: drawingPlace)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
secondTouch = touch.location(in: drawingPlace)
if(self.currentContext == nil){
UIGraphicsBeginImageContext(drawingPlace.frame.size)
self.currentContext = UIGraphicsGetCurrentContext()
}else{
self.currentContext?.clear(CGRect(x: 0, y: 0, width: drawingPlace.frame.width, height: drawingPlace.frame.height))
}
self.prevImage?.draw(in: self.drawingPlace.bounds)
let bezier = UIBezierPath()
bezier.move(to: startTouch!)
bezier.addLine(to: secondTouch!)
bezier.close()
UIColor.blue.set()
self.currentContext?.setLineWidth(4)
self.currentContext?.addPath(bezier.cgPath)
self.currentContext?.strokePath()
let img2 = self.currentContext?.makeImage()
drawingPlace.image = UIImage.init(cgImage: img2!)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
self.currentContext = nil
self.prevImage = self.drawingPlace.image
}
}

The problem is this line:
bezier.addLine(to: secondTouch!)
This causes the line to follow the position of the touch, wherever it is. Instead, drop a perpendicular to the horizontal (I presume that is what you mean by 90 degrees) and add the line to that point on the horizontal. In other words, use the x component of secondTouch, but use as the y component the y component of startTouch.
bezier.addLine(to: CGPoint(x:secondTouch!.x, y:startTouch!.y)

Related

draw line using uibezierPath in a vertical way

My swift code below draws a horiziontal way the horizontal line is at a angle that does not change. Think like a x axis. I want to draw a line in the exact opposite way. Think of the y axis. The line is drawn at
bezier.addLine(to: CGPoint(x: point.x, y: startPoint!.y))
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
var startPoint: CGPoint?
let shapeLayer: CAShapeLayer = {
let shapeLayer = CAShapeLayer()
shapeLayer.lineWidth = 4
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor.blue.cgColor
return shapeLayer
}()
override func viewDidLoad() {
super.viewDidLoad()
imageView.backgroundColor = .systemOrange
imageView.layer.addSublayer(shapeLayer)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
startPoint = touch?.location(in: imageView)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard var touch = touches.first else { return }
if let predicted = event?.predictedTouches(for: touch)?.last {
touch = predicted
}
updatePath(in: imageView, to: touch)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
updatePath(in: imageView, to: touch)
let image = UIGraphicsImageRenderer(bounds: imageView.bounds).image { _ in
imageView.drawHierarchy(in: imageView.bounds, afterScreenUpdates: true)
}
shapeLayer.path = nil
imageView.image = image
}
}
private extension ViewController {
func updatePath(in view: UIView, to touch: UITouch) {
let point = touch.location(in: view)
guard view.bounds.contains(point) else { return }
let bezier = UIBezierPath()
bezier.move(to: startPoint!)
bezier.addLine(to: CGPoint(x: point.x, y: startPoint!.y))
shapeLayer.path = bezier.cgPath
}
}
Actually you move on to startPoint and trying to add line to the same static point ... how it can add line to the same point on which you are currently residing ... add some value to Y while static X position position to add line
bezier.move(to: startPoint!)
bezier.addLine(to: CGPoint(x: startPoint!.x, y: point.y))

In Xcode how would I get a SkSpriteNode to move up when clicked on?

How do I get the SkSpriteNode to move up when clicked?
-Thanks
https://i.stack.imgur.com/fcOvr.png
lets say your node is called box
use the touches began function
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for _ in touches{
let touch:UITouch = touches.first!
let touchLocation = touch.location(in: self)
box.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
box.physicsBody?.applyImpulse(CGVector(dx: 0, dy:300))
}
}
the applyImpusle method takes an x value to move along the x axis(left or right) and takes a y value to move along the y axis (up or down). set dy accordingly.
rest of it depends on your scene properties like gravity , friction , mass of the box and so on
Without using a physicsBody you can use this code and just change how you move it up (I do it manually just to keep it simple).
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if sprite.contains(location){
sprite.position = CGPoint(x: 0, y: 10)
}

Touch corner rectangle using sprite kit in swift. The code will run, but no rectangle appears

I want to add a rectangle with a corner where the user first touches, and with its other corner where the user lifts off. I would also like the rectangle to show while the user is dragging their finger.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let position1 = touch.location(in: self)
var x1 = position1.x
var y1 = position1.y
func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let position2 = touch.location(in: self)
var x2 = position2.x
var y2 = position2.y
var originX = min(x1,x2)
var originY = min(y1,y2)
var cornerX = max(x1,x2)
var cornerY = max(y1,y2)
var rect_width = cornerX - originX
var rect_height = cornerY - originY
var rect_con = CGRect(x: originX, y:originY, width: rect_width, height: rect_height)
var box = SKShapeNode(rect: rect_con)
}
}
First up, if you're only after a rectangle, you're better off doing this with just a SKSpriteNode, and scaling it, with this:
https://developer.apple.com/reference/spritekit/skspritenode/1645445-scale
Secondly, for future reference, SKShapeNode is a half (or less) complete conversion of CAShapeLayer into a VERY primitive drawing tool. It's not good at dynamic drawing, at all.
Set the anchor point of the SKSpriteNode rectangle at the touch point, and scale to the x and y of the touchesMoved. You might have to do a bit of conversion for negative values, since this is operating from an origin in cartesian coordinates.
It seem to me that your touchesEnded function is declared from within the touchesStart function and because of that is not visible from the class scope and then never gets called. It should look more like this (not tested):
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let position1 = touch.location(in: self)
var x1 = position1.x
var y1 = position1.y
}
}
func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let position2 = touch.location(in: self)
var x2 = position2.x
var y2 = position2.y
var originX = min(x1,x2)
var originY = min(y1,y2)
var cornerX = max(x1,x2)
var cornerY = max(y1,y2)
var rect_width = cornerX - originX
var rect_height = cornerY - originY
var rect_con = CGRect(x: originX, y:originY, width: rect_width, height: rect_height)
var box = SKShapeNode(rect: rect_con)
}
}

How to detect UITouch location visible in Swift 3

I am trying to detect a UITouch event visible.When touch event begins.Currently, I am using below code to detect the touch location.From below code,I can able to print the touch location.Any,help would be greatly appreciated.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
{
if let touch = touches.first {
let position :CGPoint = touch.location(in: view)
print(position.x)
print(position.y)
}
}
Note: I am not trying to draw a line or anything like a drawing app.I,Just want to see the touch event visibly.When happens.
Thanks in advance.
If you want a circle or something to appear when the user taps the screen, try this:
var touchIndicators: [UIView] = []
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: view)
let touchIndicator = UIView(frame: CGRect(x: location.x - 10, y: location.y - 10, width: 20, height: 20))
touchIndicator.alpha = 0.5
touchIndicator.backgroundColor = UIColor.red
touchIndicator.layer.cornerRadius = 10
self.view.addSubview(touchIndicator)
touchIndicators.append(touchIndicator)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for indicator in touchIndicators {
indicator.removeFromSuperview()
}
touchIndicators = []
}
Pretty straightforward. Add circular views when the user touches the screen and remove them when the user lifts his/her fingers. You can also do this using UITapGestureRecognizer.

Apply impulse to a SKSpriteNode from a user swipe

Can anyone tell me why when I try to apply an impulse to a node like this it disappears?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch:UITouch = touches.first! as UITouch
startPoint = touch.location(in: view)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
defer {
startPoint = nil
}
guard touches.count == 1, let startPoint = startPoint else {
return
}
if let touch = touches.first {
let endPoint = touch.location(in: view)
//Calculate your vector from the delta and what not here
direction = CGVector(dx: endPoint.x - startPoint.x, dy: endPoint.y - startPoint.y)
L1Ball.physicsBody?.applyImpulse(CGVector(dx: direction.dx.hashValue, dy: direction.dy.hashValue))
}
}
I think it has something to do with the way I am using hashValue. I don't know another way to get the values from the CGVector direction. If I try to use direction itself as the impulse vector it just crashes. Any insight? Thanks!
Your code worked for me when I removed the .hashValue from direction.dx and direction.dy (hash values are used for comparisons). Oh and your ball node isn't disappearing. Those hash values are large enough that when you apply them on a ball as a force, the speed of the ball is big enough that by the time the next frame is rendered the ball is off the screen.