So I'm trying to move an object using the touches moved function, however I'm not sure how to do that when the coordinates are not predetermined. This is what I've got going :
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
var touch: AnyObject? = touches.anyObject()
var point = touch?.locationInView(self.view)
}
So basically I'm making the point variable the coordinates (points).
Then what needs to happen is that i move an object (in this case Label1) to that location:
func MoveObject(point) {
Label1.frame.origin = ( /* Here would the ´point´ be */ )
}
Also keep in mind that later when this problem is out of the way I'm going to change the location so its not where you touch but it moves accordingly. I don't know if that matters really but I'm just saying in case it does ;)
What about
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
var touch: AnyObject? = touches.anyObject()
var point = touch?.locationInView(self.view)
moveObject(point)
}
...
func MoveObject(point) {
Label1.center = point
}
Related
I have Swift 2 code below that draws curved lines when the user touches and moves their finger across the screen. New sections of the curved line are added as the user moves their finger to give one continuous curved line on screen. (top image)
However, I wish to change the below code so that as each new section of the line is added and drawn to screen, the previous section and earlier sections are deleted, so that all is seen on the screen is the new section and nothing else. (bottom image)
What needs to be modified in the section of code below to achieve this?
// Swift 2 code below tested using Xcode 7.0.1.
class drawLines: UIView {
let path=UIBezierPath()
var previousPoint:CGPoint = CGPoint.zero
var strokeColor:UIColor?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func drawRect(rect: CGRect) {
strokeColor = UIColor.blackColor()
strokeColor?.setStroke()
path.lineWidth = 10
path.stroke()
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: AnyObject? = touches.first
let currentPoint = touch!.locationInView(self)
path.moveToPoint(currentPoint)
previousPoint=currentPoint
self.setNeedsDisplay()
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: AnyObject? = touches.first
let currentPoint = touch!.locationInView(self)
let midPoint = self.midPoint(previousPoint, p1: currentPoint)
path.addQuadCurveToPoint(midPoint,controlPoint: previousPoint)
previousPoint=currentPoint
self.setNeedsDisplay()
path.moveToPoint(midPoint)
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.setNeedsDisplay()
}
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
self.touchesEnded(touches!, withEvent: event)
}
func midPoint(p0:CGPoint,p1:CGPoint)->CGPoint
{
let x=(p0.x+p1.x)/2
let y=(p0.y+p1.y)/2
return CGPoint(x: x, y: y)
}
}
As far as I know, there's no way to remove points from a UIBezierPath. The solution you're looking for is to store the points in an array, which you can modify freely, then create your path from that point array.
Update
I'm getting a bit confused re-reading your post alongside the comments you've posted. That being said, I've tried to make the example below contain all the elements you need – you might have to re-arrange them if I have not understood you 100%.
This code continuously adds points to an array from the point a touch begins, including while it moves. I added a cap to the maximum number of points so that it removes excess line points if needed. When the user releases their finger I've made it clear all the points.
Note: I've tried to keep the code as simple as possible so that it's clear. Once you find the correct combination of adding/removing points that matches your needs, you should probably look at optimising this. In particular, this assumes a naïve method of drawing where all drawing happens simultaneously (vs deltas), which isn't efficient. The method of removing excess points can also be optimised once you understand it.
import UIKit
class ViewController: UIViewController {
var points = [CGPoint]()
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
addTouch(touches.first)
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
addTouch(touches.first)
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
points.removeAll()
}
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
points.removeAll()
}
func addTouch(touch: UITouch?) {
guard let touch = touch else { return }
let currentPoint = touch.locationInView(self.view)
points.append(currentPoint)
// if you want a limit on your line length, you need these lines
// 20 is an arbitrary number
while (points.count > 20) {
points.removeFirst()
}
}
}
All that remains is for you to add that to your current line drawing code, and you should be good to go.
Apple have done a number of good WWDC talks on graphics performance. This one in particular might be helpful.
If I understand your question correctly, you'll want to reset the
path in the touchesBegan() method
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
path.removeAllPoints()
// ...
}
You could save an array of points and rebuild your bezier path each time as TwoStraws recommends.
Another option would be to draw your curve using a CAShapeLayer, and change the shapeBegin property. (As you move from shapeBegin = 1.0 to shapeBegin = 0.0 it truncates the beginning of the shape.)
A third option would be to edit the path to delete the earlier points. Erica Sadun has sample code in her outstanding iOS Developers' Cookbook series that shows how to parse the points inside a Bezier path (If I remember correctly it actually uses the underlying CGPath object that is inside a Bezier path.) That would be much faster than rebuilding your bezier path each time, but more work for you.
I have a subclass of SKNode called Player which pretty much consists of this: http://hub.ae/blog/2014/03/26/soft-body-physics-jellyusing-spritekit/ converted to swift (With a few changes). I've allowed the user to move the player node with his finger with the following code:
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
let touch = touches.first as! UITouch
player.runAction(SKAction.moveTo(touch.locationInNode(world), duration: 1))
}
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
let touch = touches.first as! UITouch
player.runAction(SKAction.moveTo(touch.locationInNode(world), duration: 1))
}
override func touchesCancelled(touches: Set<NSObject>!, withEvent event: UIEvent!) {
player.removeAllActions()
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
player.removeAllActions()
}
*As a note, the 'world' var you see is just another SKNode. 'player' is a child of this node.
This looks like it should work, however the node moves in very strange directions. This is an example of how it looks:
http://gyazo.com/87b0d09101bbbfd3ac0f2a3cdbf42e4c
How can I fix this? I found that settings the anchor point of the scene to 0.5 fixes this issue, however then the physics body of 'player' node gets messed up.
I had same problem but i can not remember if it is how i fixed it. Try changing this:
world > self
player.runAction(SKAction.moveTo(touch.locationInNode(world), duration: 1))
To:
player.runAction(SKAction.moveTo(touch.locationInNode(self), duration: 1))
If i am wrong let me know :)
EDIT
set anchor point to (0.5,0.5) and write those 2 methods to center on your node.
override func didSimulatePhysics() {
camera.position = CGPointMake(player.position.x, player.position.y);
centerOnNode(camera)
}
func centerOnNode(node: SKNode){
var positionInScene : CGPoint = convertPoint(node.position, fromNode: node.parent)
world.position = CGPointMake(world.position.x - positionInScene.x, world.position.y - positionInScene.y)
}
I'm working a little game for iOS.
I've a SKSpriteNode in my scene - when I remove it with "removeFromParent" and touch the area it was last in, I still get the function.
My code is as following:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if tapToPlayNode.containsPoint(location){
tapToPlayNode.removeFromParent()
startNewGame()
}
}
}
func startNewGame(){
//Starts a new game with resetted values and characters in position
println("Ready.. set.. GO!")
//Shows the ui (value 1)
toggleUiWithValue(1)
}
In other words, I get "Ready.. set.. GO!" output when I touch the area even after it was deleted.
Any clues?
Bests,
Your tapToPlayNode is still retained by self and is removed from it's parent.
You should make it optional var tapToPlayNode:SKSpriteNode?and nil it after remove it from it's parent like this:
if let playNode = self.tapToPlayNode {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if playNode.containsPoint(location) {
playNode.removeFromParent()
startNewGame()
self.tapToPlayNode = nil // il it here!
break
}
}
}
You can also avoid to keep a reference of your tapToPlayNode and give it a name when initializing it like this:
node.name = #"tapToPlayNodeName"
// Add node to scene and do not keep a var to hold it!
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
// Retrieve the ode here
let tapToPlayNode = container.childNodeWithName("tapToPlayNodeName")!
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if tapToPlayNode.containsPoint(location){
tapToPlayNode.removeFromParent()
startNewGame()
}
}
}
I have a ball that I want to move around (Spritekit) and I want to set a velocity so when the player move the ball then he moves his finger from the screen the ball will move and it will have it's own velocity depinding on some calculations
the question :
this is my code , how can I know when the player is moving his finger from the screen ?!
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
if let touch = touches.first as? UITouch{
var location = touch.locationInNode(self)
ball6.position = location
}
Use this method:
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
//your code
}
I am overriding:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent)
in Swift.
I am wondering, is this correct for getting one touch point:
var touchPoint: CGPoint! = event.touchesForView(self)?.anyObject()?.locationInView(self)
Thanks in advance!
As of iOS 8.3, touchesBegan takes a touches parameter which is a Set<NSObject>. It's now Set<UITouch>. So, you would:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let point = touches.first?.location(in: view) else { return }
// use `point` here
}
In previous iOS versions, touchesBegan was defined as a NSSet parameter, as outlined in the question, so you would:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
if let touch = touches.anyObject() as? UITouch {
let touchPoint = touch.locationInView(view)
...
}
}