How to draw a line in Swift 3 - swift

I would like the user to touch 2 points and then a line is drawn between those two points. Here is what I have so far:
func drawline(){
let context = UIGraphicsGetCurrentContext()
context!.beginPath()
context?.move(to: pointA)
context?.addLine(to: pointB)
context!.strokePath()
}
pointA is the first point the user touched and pointB is the second point. I get the error:
thread 1:EXC_BREAKPOINT
Thanks in advance for your help.

To draw a line between two points the first thing you need is get the CGPoints from the current UIView, there are several ways of achieve this. I going to use an UITapGestureRecognizer for the sake of the sample to detect when you make a tap.
The another step is once you have the two points saved draw the line between the two points, and for this again you can use the graphics context as you try before or use CAShapeLayer.
So translating the explained above we get the following code:
class ViewController: UIViewController {
var tapGestureRecognizer: UITapGestureRecognizer!
var firstPoint: CGPoint?
var secondPoint: CGPoint?
override func viewDidLoad() {
super.viewDidLoad()
tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.showMoreActions(touch:)))
tapGestureRecognizer.numberOfTapsRequired = 1
view.addGestureRecognizer(tapGestureRecognizer)
}
func showMoreActions(touch: UITapGestureRecognizer) {
let touchPoint = touch.location(in: self.view)
guard let _ = firstPoint else {
firstPoint = touchPoint
return
}
guard let _ = secondPoint else {
secondPoint = touchPoint
addLine(fromPoint: firstPoint!, toPoint: secondPoint!)
firstPoint = nil
secondPoint = nil
return
}
}
func addLine(fromPoint start: CGPoint, toPoint end:CGPoint) {
let line = CAShapeLayer()
let linePath = UIBezierPath()
linePath.move(to: start)
linePath.addLine(to: end)
line.path = linePath.cgPath
line.strokeColor = UIColor.red.cgColor
line.lineWidth = 1
line.lineJoin = kCALineJoinRound
self.view.layer.addSublayer(line)
}
}
The above code is going to draw a line every time two points are selected and you can customize the above function as you like.
I hope this help you.

Draw line in Swift 4.1
class MyViewController: UIViewController {
#IBOutlet weak var imgViewDraw: UIImageView!
var lastPoint = CGPoint.zero
var red: CGFloat = 0.0
var green: CGFloat = 0.0
var blue: CGFloat = 0.0
var brushWidth: CGFloat = 10.0
var opacity: CGFloat = 1.0
var isSwiping:Bool!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: Touch events
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
isSwiping = false
if let touch = touches.first{
lastPoint = touch.location(in: imgViewDraw)
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
isSwiping = true;
if let touch = touches.first{
let currentPoint = touch.location(in: imgViewDraw)
UIGraphicsBeginImageContext(self.imgViewDraw.frame.size)
self.imgViewDraw.image?.draw(in: CGRect(x:0, y:0,width:self.imgViewDraw.frame.size.width, height:self.imgViewDraw.frame.size.height))
UIGraphicsGetCurrentContext()?.move(to: CGPoint(x: lastPoint.x, y: lastPoint.y))
UIGraphicsGetCurrentContext()?.addLine(to: CGPoint(x: currentPoint.x, y: currentPoint.y))
UIGraphicsGetCurrentContext()?.setLineCap(CGLineCap.round)
UIGraphicsGetCurrentContext()?.setLineWidth(self.brushWidth)
UIGraphicsGetCurrentContext()?.setStrokeColor(red: red, green: green, blue: blue, alpha: 1.0)
UIGraphicsGetCurrentContext()?.strokePath()
self.imgViewDraw.image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
lastPoint = currentPoint
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if(!isSwiping) {
// This is a single touch, draw a point
UIGraphicsBeginImageContext(self.imgViewDraw.frame.size)
self.imgViewDraw.image?.draw(in: CGRect(x:0, y:0,width:self.imgViewDraw.frame.size.width, height:self.imgViewDraw.frame.size.height))
UIGraphicsGetCurrentContext()?.setLineCap(CGLineCap.round)
UIGraphicsGetCurrentContext()?.setLineWidth(self.brushWidth)
UIGraphicsGetCurrentContext()?.move(to: CGPoint(x: lastPoint.x, y: lastPoint.y))
UIGraphicsGetCurrentContext()?.addLine(to: CGPoint(x: lastPoint.x, y: lastPoint.y))
UIGraphicsGetCurrentContext()?.setStrokeColor(red: red, green: green, blue: blue, alpha: 1.0)
UIGraphicsGetCurrentContext()?.strokePath()
self.imgViewDraw.image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
}
}

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))

how to place image on top of uiview drawing (swift5)

My code below places a behind a drawing area. So as you can see in the image below. Anything I draw goes in front of the lines. I want to make so whatever i draw goes behind the lines. All of my code is attached below. The image is in the assets folder as well.
class ViewController: UIViewController {
var editBtn = UIButton()
var canVasView = UIView()
var path = UIBezierPath()
var startPoint = CGPoint()
var touchPoint = CGPoint()
func addArrowImageToButton(button: UIButton, arrowImage:UIImage = #imageLiteral(resourceName: "graph.png") ) {
let btnSize:CGFloat = 32
let imageView = UIImageView(image: arrowImage)
let btnFrame = button.frame
button.bringSubviewToFront(imageView)
}
override func viewDidAppear(_ animated: Bool) {
self.addArrowImageToButton(button: editBtn)
}
override func viewDidLoad() {
super.viewDidLoad()
setup()
draw()
view.addSubview(editBtn)
view.addSubview(canVasView)
editBtn.backgroundColor = UIColor.orange
canVasView.backgroundColor = UIColor.purple
editBtn.translatesAutoresizingMaskIntoConstraints = false
canVasView.translatesAutoresizingMaskIntoConstraints = false
let myLayer = CALayer()
let myImage = UIImage(named: "graph.png")?.cgImage
myLayer.frame = CGRect(x: 40, y: -80, width: 300, height: 300)
myLayer.contents = myImage
canVasView.layer.addSublayer(myLayer)
self.view.addSubview(canVasView)
NSLayoutConstraint.activate ([
canVasView.trailingAnchor.constraint(equalTo: view.centerXAnchor, constant :175),
canVasView.topAnchor.constraint(equalTo: view.centerYAnchor, constant : 100),
canVasView.widthAnchor.constraint(equalToConstant: 350),
canVasView.heightAnchor.constraint(equalToConstant: 180),
editBtn.trailingAnchor.constraint(equalTo: view.centerXAnchor, constant :175),
editBtn.topAnchor.constraint(equalTo: view.centerYAnchor, constant : 0),
editBtn.widthAnchor.constraint(equalToConstant: 350),
editBtn.heightAnchor.constraint(equalToConstant: 180),
])
editBtn.addTarget(self, action: #selector(didTapEditButton), for: .touchUpInside)
}
#objc func didTapEditButton() {
path.removeAllPoints()
canVasView.layer.sublayers = nil
canVasView.setNeedsDisplay()
self.addArrowImageToButton(button: editBtn)
}
func setup(){
editBtn.layer.cornerRadius = 20
canVasView.clipsToBounds = true
canVasView.isMultipleTouchEnabled = false
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
if let point = touch?.location(in: canVasView){
startPoint = point
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
if let point = touch?.location(in: canVasView){
touchPoint = point
}
path.move(to: startPoint)
path.addLine(to: touchPoint)
startPoint = touchPoint
draw()
}
func draw() {
let strokeLayer = CAShapeLayer()
strokeLayer.fillColor = nil
strokeLayer.lineWidth = 5
strokeLayer.strokeColor = UIColor.blue.cgColor
strokeLayer.path = path.cgPath
canVasView.layer.addSublayer(strokeLayer)
canVasView.setNeedsDisplay()
}
}
To draw behind the lines image you need to add your stroke layer behind it.
To do so, declare myLayer outside of viewDidLoad then change your draw function to:
func draw() {
let strokeLayer = CAShapeLayer()
strokeLayer.fillColor = nil
strokeLayer.lineWidth = 5
strokeLayer.strokeColor = UIColor.blue.cgColor
strokeLayer.path = path.cgPath
canVasView.layer.insertSublayer(strokeLayer, below: myLayer) //draw behind myLayer
canVasView.setNeedsDisplay()
}

Draw Circle where user clicks with UIBezierPath

I am new to swift. I want to draw Circle on those pixels where user clicks.
Here is my code it is drawing circle but not at where I clicks....
I want to draw circle where user clicks....Like it is getting the coordinates where user clicks and printing them to console but I want to update the x and y arguments in ovalsandcircles() function.
Thanks in advance.
`import UIKit
class DemoView: UIView {
var startX :CGFloat = 0.0
var startY :CGFloat = 0.0
var path: UIBezierPath!
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.darkGray
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func draw(_ rect: CGRect) {
// Specify the fill color and apply it to the path.
ovalsAndCircles()
UIColor.orange.setFill()
path.fill()
Specify a border (stroke) color.
UIColor.purple.setStroke()
path.stroke()
}
func ovalsAndCircles () {
self.path = UIBezierPath(ovalIn: CGRect(x: startX,
y: startY,
width: 200,
height: 200))
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let point = touches.first!.location(in: self)
startX = point.x
startY = point.y
print(startY)
print(startX)
}
}
`
(1) Add a UIView control through Interface Builder.
(2) Set the class name of that UIView control to DemoView.
(3) Create a subclass of UIView as DemoView as follows.
import UIKit
class DemoView: UIView {
let fillColor = UIColor.green
let strokeColor = UIColor.black
let radius: CGFloat = 100.0
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = event?.allTouches?.first
if let touchPoint = touch?.location(in: self) {
drawCircle(point: touchPoint)
}
}
func drawCircle(point: CGPoint) {
if let subLayers = self.layer.sublayers {
for subLayer in subLayers {
subLayer.removeFromSuperlayer()
}
}
let circlePath = UIBezierPath(arcCenter: point, radius: radius, startAngle: CGFloat(0), endAngle: CGFloat(Double.pi * 2.0), clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
shapeLayer.fillColor = fillColor.cgColor
shapeLayer.strokeColor = strokeColor.cgColor
self.layer.addSublayer(shapeLayer)
}
}
First look at the Coordinate System in iOS: https://developer.apple.com/library/archive/documentation/General/Conceptual/Devpedia-CocoaApp/CoordinateSystem.html
The CGRect has a origin property of type CGPoint. Maybe it helps to set the origin of your rect in your draw function:
let rect: CGRect = ....
rect.origin = CGPoint(x:0.5, y:0.5) //Set the origin to the middle of the rect
You call the touchesBegan Method to set the points where it should be drawn. But when the user moves over the screen it wont be recognized. Use touchesEnded Method instead

Objects Position Not Matching Up (Spritekit)

I am building a spritekit game and have just started the project. I have a circle on the screen which starts in the center, and when i drag my finger from the circle outward, it will show a dotted line/bezierpath connected to the ball which will help the user see where it is aiming the ball. When the user lifts their finger, the ball will shoot in the opposite direction of the aim line. (Think a game like soccer stars or pool). The issue is that the maneuver works the first time when everything starts in the middle: I drag my finger and the ball shoots in opposite direction then stops. But when I try it again, the position of the aiming line says it is the same as the ball (It should be), but then it shows up like an inch away from the ball on the screen. I feel like this may be an issue that the scene(s) behind the objects may not be the same size? But I'm confused because I think I'm only using one scene.
GameViewController viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
if let scene = SKScene(fileNamed: "GameScene") {
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
scene.size = view.bounds.size
//scene.anchorPoint = CGPoint(x: 0.0, y: 0.0)
// Present the scene
view.presentScene(scene)
}
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
GameScene Code (Doubt you need all of it but whatever):
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var ball = SKShapeNode(circleOfRadius: 35)
var touchingBall = false
var aimLine = SKShapeNode()
var startAimPoint = CGPoint()
var endAimPoint = CGPoint()
let damping:CGFloat = 0.94
override func didMove(to view: SKView) {
ball.fillColor = SKColor.orange
ball.name = "ball"
let borderBody = SKPhysicsBody(edgeLoopFrom: self.frame)
borderBody.friction = 0
self.physicsBody = borderBody
physicsWorld.gravity = CGVector(dx: 0.0, dy: 0.0)
var physicsBody = SKPhysicsBody(circleOfRadius: 35)
ball.physicsBody = physicsBody
ball.physicsBody?.affectedByGravity = false
ball.physicsBody?.friction = 10.0
ball.position = CGPoint(x: frame.midX, y: frame.midY)
self.addChild(ball)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("TOUCHES BEGAN.")
for touch in touches {
print("TB: \(touchingBall)")
let location = touch.location(in: self)
let node : SKNode = self.atPoint(location)
if node.name == "ball" {
// touched inside node
if ball.physicsBody!.angularVelocity <= 0.0{
touchingBall = true
startAimPoint = ball.position
print(touchingBall)
}
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
print("TOCUHES MOVED.")
for touch in touches {
let location = touch.location(in: self)
if touchingBall{
endAimPoint = location
assignAimLine(start: startAimPoint, end: endAimPoint)
print("Moving touched ball")
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
print("Touches ended. \(touchingBall)")
if touchingBall == true{
ball.physicsBody!.applyImpulse(CGVector(dx: -(endAimPoint.x - startAimPoint.x) * 3, dy: -(endAimPoint.y - startAimPoint.y) * 3))
}
touchingBall = false
aimLine.removeFromParent()
print(touchingBall)
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
print("Touches cancelled. \(touchingBall)")
if touchingBall == true{
ball.physicsBody!.applyImpulse(CGVector(dx: -(endAimPoint.x - startAimPoint.x) * 3, dy: -(endAimPoint.y - startAimPoint.y) * 3))
}
touchingBall = false
aimLine.removeFromParent()
print(touchingBall)
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
print(ball.physicsBody!.velocity)
let dx2 = ball.physicsBody!.velocity.dx * damping
let dy2 = ball.physicsBody!.velocity.dy * damping
ball.physicsBody!.velocity = CGVector(dx: dx2, dy: dy2)
}
func assignAimLine(start: CGPoint, end: CGPoint){
aimLine.removeFromParent()
var bezierPath = UIBezierPath()
bezierPath.move(to: start)
bezierPath.addLine(to: shortenedEnd(startPoint: start, endPoint: end))
var pattern : [CGFloat] = [10.0, 10.0]
let dashed = SKShapeNode(path: bezierPath.cgPath.copy(dashingWithPhase: 2, lengths: pattern))
aimLine = dashed
aimLine.position = ball.position
aimLine.zPosition = 0
self.addChild(aimLine)
}
func hypotenuse(bp: UIBezierPath) -> Double{
var a2 = bp.cgPath.boundingBox.height * bp.cgPath.boundingBox.height
var b2 = bp.cgPath.boundingBox.width * bp.cgPath.boundingBox.width
return Double(sqrt(a2 + b2))
}
func hypotenuse(startP: CGPoint, endP: CGPoint) -> Double{
var bezierPath = UIBezierPath()
bezierPath.move(to: startP)
bezierPath.addLine(to: endP)
return hypotenuse(bp: bezierPath)
}
func shortenedEnd(startPoint: CGPoint, endPoint: CGPoint) -> CGPoint{
var endTemp = endPoint
//while hypotenuse(startP: startPoint, endP: endTemp) > 150{
endTemp = CGPoint(x: endTemp.x / 1.01, y: endTemp.y / 1.01)
//}
return endTemp
}
func addTestPoint(loc: CGPoint, color: UIColor){
var temp = SKShapeNode(circleOfRadius: 45)
temp.fillColor = color
temp.position = loc
self.addChild(temp)
}
}
I tried printing the frame size for the scene and it says 400 something x 700 something (I am testing on iPhone 6 Plus), and it says the UIScreen is same size so i don't know what issue is. Overall, I just need the aiming line to be on the center of the circle more than just the first time I try the maneuver. Thanks.
Like I mentioned in the comments, your problem was how you were laying out your paths. The code below makes the path relative to the ball instead of absolute to the scene. I also fixed the issue with creating new shapes every time.
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var ball = SKShapeNode(circleOfRadius: 35)
var touchingBall = false
var aimLine = SKShapeNode()
var endAimPoint = CGPoint()
override func didMove(to view: SKView) {
ball.fillColor = SKColor.orange
ball.name = "ball"
let borderBody = SKPhysicsBody(edgeLoopFrom: self.frame)
borderBody.friction = 0
self.physicsBody = borderBody
physicsWorld.gravity = CGVector(dx: 0.0, dy: 0.0)
ball.position = CGPoint(x: frame.midX, y: frame.midY)
let physicsBody = SKPhysicsBody(circleOfRadius: 35)
physicsBody.affectedByGravity = false
physicsBody.friction = 10.0
physicsBody.linearDamping = 0.94
ball.physicsBody = physicsBody
self.addChild(ball)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("TOUCHES BEGAN.")
for touch in touches {
print("TB: \(touchingBall)")
let location = touch.location(in: self)
let node : SKNode = self.atPoint(location)
if node.name == "ball" {
// touched inside node
if ball.physicsBody!.angularVelocity <= 0.0{
touchingBall = true
aimLine.path = nil
self.addChild(aimLine)
print(touchingBall)
}
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
print("TOCUHES MOVED.")
for touch in touches {
let location = touch.location(in: self)
if touchingBall{
endAimPoint = self.convert(location, to: ball)
assignAimLine(end: endAimPoint)
print("Moving touched ball")
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
print("Touches ended. \(touchingBall)")
if touchingBall == true{
ball.physicsBody!.applyImpulse(CGVector(dx: -(endAimPoint.x) * 3, dy: -(endAimPoint.y) * 3))
}
touchingBall = false
aimLine.removeFromParent()
print(touchingBall)
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
print("Touches cancelled. \(touchingBall)")
if touchingBall == true{
ball.physicsBody!.applyImpulse(CGVector(dx: -(endAimPoint.x) * 3, dy: -(endAimPoint.y) * 3))
}
touchingBall = false
aimLine.removeFromParent()
print(touchingBall)
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
print(ball.physicsBody!.velocity)
//let dx2 = ball.physicsBody!.velocity.dx * damping
//let dy2 = ball.physicsBody!.velocity.dy * damping
//ball.physicsBody!.velocity = CGVector(dx: dx2, dy: dy2)
}
func assignAimLine(end: CGPoint){
let bezierPath = UIBezierPath()
bezierPath.move(to: CGPoint.zero)
bezierPath.addLine(to: end)
let pattern : [CGFloat] = [10.0, 10.0]
aimLine.position = ball.position
aimLine.path = bezierPath.cgPath.copy(dashingWithPhase: 2, lengths: pattern)
aimLine.zPosition = 0
}
func addTestPoint(loc: CGPoint, color: UIColor){
var temp = SKShapeNode(circleOfRadius: 45)
temp.fillColor = color
temp.position = loc
self.addChild(temp)
}
}

Swift: Centre point of fingers in UIRotationGesture in wrong place in SKView?

I'm trying to build a board game whereby the board is built of sprites and you can look over them birds eye view style with an SKCamera node. I've gotten the pan, zoom and rotate down but they don't feel natural as wherever I put my fingers on the screen it will rotate about the centre of the camera node.
To remedy this, I was going to create a SKNode and place this in-between where the fingers are as an anchor for the camera's rotation and zooming.
However I can't get the location of the centre point of the fingers to line up with the right coords in the gamescene.
I've created some red boxes to debug and find my problem and looks as so:
Where-ever I place my fingers in the entire game scene to rotate it, the centre where it thinks it should be is always in that red blob.
The SKView is placed on the storyboard as a SpriteKit view and is bound to the left and right edges of the screen with top and bottom padding:
Inside of viewcontroller:
#IBOutlet weak var Gameview: SKView!
override func viewDidLoad() {
super.viewDidLoad()
let scene = GameScene(size:Gameview.frame.size)
Gameview.presentScene(scene)
}
Inside of GameScene.swift, let a = sender.location(in: self.view) seems to be where the problem lies.
class GameScene: SKScene, UIGestureRecognizerDelegate {
var newCamera: SKCameraNode!
let rotateRec = UIRotationGestureRecognizer()
let zoomRec = UIPinchGestureRecognizer()
//let panRec = UIPanGestureRecognizer()
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer)
-> Bool {return true}
override func didMove(to view: SKView) {
rotateRec.addTarget(self, action: #selector(GameScene.rotatedView (_:) ))
rotateRec.delegate = self
self.view!.addGestureRecognizer(rotateRec)
zoomRec.addTarget(self, action: #selector(GameScene.zoomedView (_:) ))
zoomRec.delegate = self
self.view!.addGestureRecognizer(zoomRec)
//panRec.addTarget(self, action: #selector(GameScene.pannedView (_:) ))
//self.view!.addGestureRecognizer(panRec)
newCamera = SKCameraNode()
newCamera.position = CGPoint(x: self.size.width / 2, y: self.size.height / 2)
self.addChild(newCamera)
self.camera = newCamera
//drawBoard()
//I removed this function as it had nothing to do with the question
}
#objc func rotatedView(_ sender:UIRotationGestureRecognizer) {
print(sender.location(in: self.view))
let square = SKSpriteNode(color: #colorLiteral(red: 0.7450980544, green: 0.1568627506, blue: 0.07450980693, alpha: 1), size: CGSize(width: 10, height: 10))
let a = sender.location(in: self.view)
let b = -a.x
let c = -a.y
let d = CGPoint(x: b, y: c)
square.position = d
self.addChild(square)
newCamera.zRotation += sender.rotation
sender.rotation = 0
if sender.state == .ended {
let rotateAmount = abs(Double(newCamera.zRotation) * Double(180) / Double.pi)
let remainder = abs(rotateAmount.truncatingRemainder(dividingBy: 90))
//print(rotateAmount)
//print(remainder)
if remainder < 10 {
newCamera.zRotation = CGFloat((rotateAmount-remainder)*Double.pi/180)
} else if remainder > 80 {
newCamera.zRotation = CGFloat((rotateAmount-remainder+90)*Double.pi/180)
}
}
}
#objc func zoomedView(_ sender:UIPinchGestureRecognizer) {
let pinch = SKAction.scale(by: 1/sender.scale, duration: 0.0)
newCamera.run(pinch)
sender.scale = 1.0
}
//#objc func pannedView(_ sender:UIPanGestureRecognizer) {
// sender.translation(in: )
//}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
let previousLocation = touch.previousLocation(in: self)
let deltaY = location.y - previousLocation.y
let deltax = location.x - previousLocation.x
newCamera!.position.y -= deltaY
newCamera!.position.x -= deltax
}
}
}
I did remove the function drawboard() as it was redundant in context to the question.
You needed to convert the coords from the sender.location to the coords in the skview using the functions shown in the page:
https://developer.apple.com/documentation/spritekit/skscene
--> https://developer.apple.com/documentation/spritekit/skscene/1520395-convertpoint
in the rotatedview() function, putting the code:
let bluesquare = SKSpriteNode(color: #colorLiteral(red: 0.2392156869, green: 0.6745098233, blue: 0.9686274529, alpha: 1), size: CGSize(width: 10, height: 10))
let a = sender.location(in: self.view)
bluesquare.position = self.convertPoint(fromView: a)
self.addChild(bluesquare)
...will add blue sprites where the centre of your two fingers are.