How to draw a single point (Swift) - ios

I´m making an app that draw lines between points to make a figure. The first thing is to draw points using touches but i´ve tried a lot and i still can´t find the way to draw the points firstly. Here is my code:
class ViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
var xpoint: CGFloat = 0
var ypoint: CGFloat = 0
var opacity: CGFloat = 1.0
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self.view)
xpoint = location.x
ypoint = location.y
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
}

Now, you just need to take that location and add a view there. Try to update touchesBegan to look something like this:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self.view)
xpoint = location.x
ypoint = location.y
//Initialize the view at the correct spot
//We set the view's frame by giving it an origin (that's the CGPoint we build from the x and y coordinates) and giving it a size, which can be anything really
let pointView = UIView(frame: CGRect(origin: CGPoint(x: xpoint, y: ypoint), size: CGSize(width: 25, height: 25))
//Round the view's corners so that it is a circle, not a square
view.layer.cornerRadius = 12.5
//Give the view a background color (in this case, blue)
view.backgroundColor = .blue
//Add the view as a subview of the current view controller's view
self.view.addSubview(view)
}
}

Related

How can I select a specific circle?

I have created Circle using "draw" and can place it anywhere on view. but when I want to move a specific circle by clicking it. it selects "LAST" created circle.
how can I select a specific circle? please guide me for the same.
if anything else you need let me know.
**CircleView**
import UIKit
class CircleView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .clear
}
required init(coder aDecoder : NSCoder) {
fatalError("init(coder : ) has not been implemented")
}
override func draw(_ rect: CGRect) {
if let context = UIGraphicsGetCurrentContext(){
context.setLineWidth(2)
UIColor.yellow.set()
let circleCenter = CGPoint(x: frame.size.width / 2, y: frame.self.height / 2)
let circleRadius = (frame.size.width - 10) / 2
context.addArc(center: circleCenter, radius: circleRadius, startAngle: 0, endAngle: .pi * 2, clockwise: true)
context.strokePath()
}
}
}
**ViewController**
import UIKit
class ViewController: UIViewController {
var circleView = CircleView(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
let circleWidth = CGFloat(100)
var lastCircleCenter = CGPoint()
var currentCenter = CGPoint()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.lightGray
circleView.isUserInteractionEnabled = true
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first{
lastCircleCenter = touch.location(in: view)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first{
let circleCenter = touch.location(in: view)
if circleCenter == lastCircleCenter{
let circleHeight = circleWidth
circleView = CircleView(frame: CGRect(x: circleCenter.x - circleWidth / 2, y: circleCenter.y - circleWidth / 2, width: 100, height: 100))
view.addSubview(circleView)
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else {
return
}
let location = touch.location(in: view)
circleView.center = location
}
}
how can I select a specific circle? please guide me for the same.
if anything else you need let me know.
how can I select a specific circle? please guide me for the same.
if anything else you need let me know.
If you are creating multiple circles and adding them to your view, I would suggest to keep track of the created circles in a collection. That way on each touch you can check if the coordinate matches any of the created circles. Based on that you can determine if to create a new circle or to move an existing one.
Example:
class ViewController: UIViewController {
var circleViews: [CircleView] = []
let circleWidth = CGFloat(100)
var draggedCircle: CircleView?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// Do nothing if a circle is being dragged
// or if we do not have a coordinate
guard draggedCircle == nil, let point = touches.first?.location(in: view) else {
return
}
// Do not create new circle if touch is in an existing circle
// Keep the reference of the (potentially) dragged circle
if let draggedCircle = circleViews.filter({ UIBezierPath(ovalIn: $0.frame).contains(point) }).first {
self.draggedCircle = draggedCircle
return
}
// Create new circle and store in an array
let offset = circleWidth / 2
let rect = CGRect(x: point.x - offset, y: point.y - offset, width: circleWidth, height: circleWidth)
let circleView = CircleView(frame: rect)
circleViews.append(circleView)
view.addSubview(circleView)
// The newly created view can be immediately dragged
draggedCircle = circleView
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
// If touches end then a circle is never dragged
draggedCircle = nil
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let draggedCircle = draggedCircle, let point = touches.first?.location(in: view) else {
return
}
draggedCircle.center = point
}
}

How to detect if I tapped a SKShapeNode

override func didMove(to view: SKView) {
view.scene?.anchorPoint = CGPoint(x: 0,y : 0)
castle = SKShapeNode(circleOfRadius: ballRadius1)
castle.physicsBody = SKPhysicsBody(circleOfRadius:ballRadius1)
castle.fillColor = .white
castle.name = "castle"
castle.position = CGPoint(x: 0, y: 0)
castle.physicsBody?.isDynamic = false
castle.physicsBody?.affectedByGravity = false;
castle.isUserInteractionEnabled = true
self.addChild(castle)
I have a circle in the middle of the screen, I want to make it disappear when I tap it. Can you please help me? It is an SKShapeNode and has a PhysicsBody with the same radius
You could use touchesBegan and make it look like so
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches{
let pointOfTouch = touch.location(in: self)
let nodeITapped = atPoint(pointOfTouch)
let nameOfTappedNode = nodeITapped.name
if nameOfTappedNode == "castle"{
//make it do whatever you want
castle.removeFromParent()
}
}
}
you could also implement it in touchesEnded instead if you want the node to disappear as soon as the user releases the touch.

Removing lagging latency during continuous period of drawing in ios 8.4 using swift 2

In this code i am facing the lagging problem and High CPU usage. i have created three diff file.
First one DrawView.swift
class DrawView: UIView {
var lines: [Line] = []
var firstPoint: CGPoint!
var percentageOfXY:[String]=[]
var viewWidth:CGFloat!
var viewHeight:CGFloat!
var drawColor:UIColor!
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
viewWidth = frame.width
viewHeight = frame.height
let touch = touches.first as UITouch?
let start = touch!.locationInView(self)
let percentageX = round(((start.x)*100)/viewWidth*100)/100
let percentageY = round(((start.y)*100)/viewHeight*100)/100
firstPoint = CGPointMake(percentageX, percentageY)
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
viewWidth = frame.width
viewHeight = frame.height
let touch = touches.first as UITouch?
let curr = touch!.locationInView(self)
let percentageX = round(((curr.x)*100)/viewWidth*100)/100
let percentageY = round(((curr.y)*100)/viewHeight*100)/100
let lastPoint = CGPointMake(percentageX, percentageY)
lines.append(Line(start: firstPoint, end: lastPoint, color: drawColor))
firstPoint = lastPoint
self.setNeedsDisplay()
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?)
{
}
override func drawRect(rect: CGRect) {
for line in lines
{
let context = UIGraphicsGetCurrentContext()
CGContextSetLineCap(context, CGLineCap.Round)
CGContextSetLineWidth(context,3)
let startX = ((line.start.x)*viewWidth)/100
let startY = ((line.start.y)*viewHeight)/100
let endX = ((line.end.x)*viewWidth)/100
let endY = ((line.end.y)*viewHeight)/100
CGContextBeginPath(context)
CGContextMoveToPoint(context, startX,startY)
CGContextAddLineToPoint(context, endX,endY)
CGContextSetStrokeColorWithColor(context,line.color.CGColor)
CGContextStrokePath(context)
}
}
}
Second Line.swift for storing cordinates in formats.
class Line
{
var start: CGPoint!
var end: CGPoint!
var cord: [String]!
var color:UIColor!
init(start _start: CGPoint,end _end: CGPoint,color _color:UIColor)
{
start = _start
end = _end
color = _color
}
}
Third one for color selection.
#IBOutlet weak var drawView: DrawView!
override func viewDidLoad() {
super.viewDidLoad()
drawView.backgroundColor = UIColor.clearColor()
}
#IBAction func redColor(sender: AnyObject) {
let theDrawView = drawView as DrawView
var color:UIColor!
color = UIColor.redColor()
theDrawView.drawColor = color
}
#IBAction func greenColor(sender: AnyObject) {
let theDrawView = drawView as DrawView
var color:UIColor!
color = UIColor.greenColor()
theDrawView.drawColor = color
}
#IBAction func blueColor(sender: AnyObject) {
let theDrawView = drawView as DrawView
var color:UIColor!
color = UIColor.blueColor()
theDrawView.drawColor = color
}
In this i am drawing round but through lagging problem it's draw straight line.
Several problems:
Get UIGraphicsGetCurrentContext out of your loop.
Get CGContextSetLineCap out of your loop.
Get CGContextSetLineWidth out of your loop.
Kill CGContextBeginPath altogether--CGContextStrokePath does that for you.
You should invent a line object with an array of points so that you don't have to keep setting the color for every little segment. TouchesBegan..TouchesEnded would start and finish one of these line objects. (You'd have to be more careful if you allow multitouch, but it doesn't look like you do.)
If you fix the line object like above, you'd have a pair of nested loops. Then you would move the CGContextMoveToPoint out front of the inner loop and the CGContextSetStrokeColorWithColor and CGContextStrokePath out of the end of the inner loop.
But now to your real problem: moving your finger across the screen can easily give several thousand pixel crossings per second. Your touchesMoved is only getting called 60 times per second (more often on an iPad Pro). If you want your sketch to look smooth, you'll have to "make up" data that was never delivered. See for example Kochanek–Bartels or Catmull–Rom splines on wikipedia.

SpriteKit, Swift 2.0 - ScrollView in reverse

I managed to get a scrollview working and scrolling, but now when I go to scroll it only scrolls from right to left and was wondering how I go about reversing it so it scrolls from left to right instead.
Here is my menu code that contains my scrollview:
var moveableNode = SKNode()
var scrollView: CustomScrollView!
private var spriteSize = CGSize.zero
let kMargin: CGFloat = 40
var sprite = SKSpriteNode()
class Menu: SKScene {
override func didMoveToView(view: SKView) {
addChild(moveableNode)
spriteSize = SKSpriteNode (imageNamed: "card_level01").size
let initialMargin = size.width/2
let marginPerImage = kMargin + spriteSize.width
scrollView = CustomScrollView(frame: CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height), scene: self, moveableNode: moveableNode)
scrollView.contentSize = CGSizeMake(initialMargin*2 + (marginPerImage * 7), size.height)
// scrollView.contentSize = CGSizeMake(self.frame.size.width * 2, self.frame.size.height)
view.addSubview(scrollView)
for i in 1...8 {
let sprite = SKSpriteNode(imageNamed: String(format: "card_level%02d", i))
sprite.position = CGPoint (x: initialMargin + (marginPerImage * (CGFloat(i) - 1)), y: size.height / 2)
moveableNode.addChild(sprite)
}
Here is my scrollView Class that is a subclass of UIScrollView:
var nodesTouched: [AnyObject] = [] // global
class CustomScrollView: UIScrollView {
// MARK: - Static Properties
/// Touches allowed
static var disabledTouches = false
/// Scroll view
private static var scrollView: UIScrollView!
private static var contentView: UIView!
// MARK: - Properties
/// Current scene
private var currentScene: SKScene?
/// Moveable node
private var moveableNode: SKNode?
// MARK: - Init
init(frame: CGRect, scene: SKScene, moveableNode: SKNode) {
print("Scroll View init")
super.init(frame: frame)
CustomScrollView.scrollView = self
currentScene = scene
self.moveableNode = moveableNode
self.frame = frame
indicatorStyle = .White
scrollEnabled = true
//self.minimumZoomScale = 1
//self.maximumZoomScale = 3
canCancelContentTouches = false
userInteractionEnabled = true
delegate = self
//flip for spritekit (only needed for horizontal)
let verticalFlip = CGAffineTransformMakeScale(-1,-1)
self.transform = verticalFlip
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// MARK: - Touches
extension CustomScrollView {
/// began
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
print("Touch began scroll view")
guard !CustomScrollView.disabledTouches else { return }
currentScene?.touchesBegan(touches, withEvent: event)
}
/// moved
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
print("Touch moved scroll view")
guard !CustomScrollView.disabledTouches else { return }
currentScene?.touchesMoved(touches, withEvent: event)
}
/// ended
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
print("Touch ended scroll view")
guard !CustomScrollView.disabledTouches else { return }
currentScene?.touchesEnded(touches, withEvent: event)
}
/// cancelled
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
print("Touch cancelled scroll view")
guard !CustomScrollView.disabledTouches else { return }
currentScene?.touchesCancelled(touches, withEvent: event)
}
}
// MARK: - Touch Controls
extension CustomScrollView {
/// Disable
class func disable() {
print("Disabled scroll view")
CustomScrollView.scrollView?.userInteractionEnabled = false
CustomScrollView.disabledTouches = true
}
/// Enable
class func enable() {
print("Enabled scroll view")
CustomScrollView.scrollView?.userInteractionEnabled = true
CustomScrollView.disabledTouches = false
}
}
// MARK: - Delegates
extension CustomScrollView: UIScrollViewDelegate {
/// did scroll
func scrollViewDidScroll(scrollView: UIScrollView) {
print("Scroll view did scroll")
moveableNode!.position.x = scrollView.contentOffset.x // Left/Right
//moveableNode!.position.y = scrollView.contentOffset.y // Up/Dowm
}
}
You need get my updated helper on gitHub (v1.1) first before reading the rest.
My helper only really works well when your scene scale mode (gameViewController) is set to
.ResizeFill
so your scenes do not crop. If you use a different scaleMode such as
.AspectFill
than it might crop stuff in your scrollView which you would need to adjust for.
It also doesnt work if your game/app supports both portrait and landscape, which is unlikely for a game anyway.
So as I said and you have also noticed when using a ScrollView in spriteKit the coordinates are different compared to UIKit. For vertical scrolling this doesn't really mean anything, but for horizontal scrolling everything it is in reverse. So to fix this you do the following
Set up your scrollView for horizontal scrolling, passing along the new scrollDirection property (.Horizontal in this case)
scrollView = CustomScrollView(frame: CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height), scene: self, moveableNode: moveableNode, scrollDirection: .Horizontal)
scrollView.contentSize = CGSizeMake(self.frame.size.width * 3, self.frame.size.height) // * 3 makes it twice as wide as screen
view.addSubview(scrollView)
you need to also add this line of code after adding it to the view.
scrollView.setContentOffset(CGPoint(x: 0 + self.frame.size.width * 2, y: 0), animated: true)
this is the line you use to tell the ScrollView on which page to start. Now in this example the scrollView is three times as wide as the screen, therefore you need to offset the content by 2 screen lengths
Now to make things easier for positioning I would do this, create sprites for each page of the scrollView. This makes positioning much easier later on.
let page1ScrollView = SKSpriteNode(color: SKColor.clearColor(), size: CGSizeMake(self.frame.size.width, self.frame.size.height))
page1ScrollView.position = CGPointMake(CGRectGetMidX(self.frame) - (self.frame.size.width * 2), CGRectGetMidY(self.frame))
moveableNode.addChild(page1ScrollView)
let page2ScrollView = SKSpriteNode(color: SKColor.clearColor(), size: CGSizeMake(self.frame.size.width, self.frame.size.height))
page2ScrollView.position = CGPointMake(CGRectGetMidX(self.frame) - (self.frame.size.width), CGRectGetMidY(self.frame))
moveableNode.addChild(page2ScrollView)
let page3ScrollView = SKSpriteNode(color: SKColor.clearColor(), size: CGSizeMake(self.frame.size.width, self.frame.size.height))
page3ScrollView.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
moveableNode.addChild(page3ScrollView)
and now you can positioning your actual labels, sprites much easier.
/// Test label page 1
let myLabel = SKLabelNode(fontNamed:"Chalkduster")
myLabel.text = "Hello, World!"
myLabel.fontSize = 45
myLabel.position = CGPointMake(0, 0)
page1ScrollView.addChild(myLabel)
/// Test sprite page 2
let sprite = SKSpriteNode(color: SKColor.redColor(), size: CGSize(width: 50, height: 50))
sprite.position = CGPointMake(0, 0)
page2ScrollView.addChild(sprite)
/// Test sprite page 3
let sprite2 = SKSpriteNode(color: SKColor.blueColor(), size: CGSize(width: 50, height: 50))
sprite2.position = CGPointMake(0, 0)
page3ScrollView.addChild(sprite2)
Hope this helps.
I also updated my GitHub project to explain this better
https://github.com/crashoverride777/Swift2-SpriteKit-UIScrollView-Helper

Do something every click in Swift

I am trying to make a square appear on a random CGPoint in Swift every time I click the screen. Below is what I have done with no compiler errors, but once I run the application, I can click or drag to move my "person," but every time I do that, a smaller square does not appear. Any advice or solutions are great. Thank you! by the way, person, a UIImageView is no image but has a viable backgroundColor.`
`
#IBOutlet weak var person: UIImageView!
var location = CGPoint(x: 0,y: 0)
var randomPoint = CGPoint(x:Int(arc4random()%1000),y:Int(arc4random()%1000))
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
location = touch!.locationInView(self.view)
person.center = location
for _ in touches {
let mySquare: UIView = UIView(frame: CGRect(x: 0,y: 0,width: 20,height: 20))
mySquare.backgroundColor = UIColor.cyanColor()
mySquare.center = randomPoint
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
location = touch!.locationInView(self.view)
person.center = location
for _ in touches {
let mySquare: UIView = UIView(frame: CGRect(x: 0,y: 0,width: 20,height: 20))
mySquare.backgroundColor = UIColor.cyanColor()
mySquare.center = randomPoint
}
}`
For every touch, you just need create and add(you missed this step) square in touch begin (or touch end), don't do in touch move.
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
location = touch!.locationInView(self.view)
person.center = location
for _ in touches {
let mySquare: UIView = UIView(frame: CGRect(x: 0,y: 0,width: 20,height: 20))
mySquare.backgroundColor = UIColor.cyanColor()
mySquare.center = randomPoint
view.addSubview(mySquare) // add square to the view
}
}
You didn't add mySquare view onto any view.
self.view.addSubview(mySquare)

Resources