I'm using Sprite kit with Swift to assay drawing lines with fingers.
Code:
override func touchesBegan(touches: NSSet!, withEvent event: UIEvent!) {
touch = touches.anyObject() as UITouch!
firstPoint = touch.locationInNode(self)
}
override func touchesMoved(touches: NSSet!, withEvent event: UIEvent!) {
var touch = touches.anyObject() as UITouch!
var positionInScene = touch.locationInNode(self)
lineNode.removeFromParent()
CGPathMoveToPoint(pathToDraw, nil, firstPoint.x, firstPoint.y)
CGPathAddLineToPoint(pathToDraw, nil, positionInScene.x, positionInScene.y)
lineNode.path = pathToDraw
lineNode.lineWidth = 10.0
lineNode.strokeColor = UIColor.redColor()
self.addChild(lineNode)
firstPoint = positionInScene
}
override func touchesEnded(touches: NSSet!, withEvent event: UIEvent!) {
}
But the lines obtained are empty, only the border has color (image).
Any idea?
SKShapeNode has a property called fillColor which is by default set to clearColor. In your code, you only set the strokeColor(outline) to red, but you should also do so to fillColor.
You can do this with lineNode.fillColor = UIColor.redColor()
Good luck!
Related
Im trying to write the code for a line that draws with the drag of a finger but deletes when the finger is removed (in SpriteKit and Swift 3)
var shapeNodes = [SKShapeNode]()
var pathToDraw = CGMutablePath()
var lineNode = SKShapeNode()
func deleteAllShapeNodes() {
for node in shapeNodes {
node.removeFromParent()
}
shapeNodes.removeAll(keepingCapacity: false)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
firstPoint = touch.location(in: self)
}
shapeNodes.append(lineNode)
pathToDraw.move(to: CGPoint(x: firstPoint.x, y: firstPoint.y))
lineNode.lineWidth = 4
lineNode.strokeColor = UIColor.white
lineNode.name = "Line"
lineNode.zPosition = 100000
lineNode.path = pathToDraw
self.addChild(lineNode)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches{
positionInScene = touch.location(in: self)
}
shapeNodes.append(lineNode)
pathToDraw.addLine(to: CGPoint(x: positionInScene.x, y: positionInScene.y))
lineNode.path = pathToDraw
firstPoint = positionInScene
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches{
TouchEndPosition = touch.location(in: self)
}
self.deleteAllShapeNodes()
}
the first line draws and deletes perfectly but when i start drawing the second line the first line reappears.
Creating a brand-new CGMutablePath seems to be the only way to get an empty CGMutablePath.
And you are adding the only instance of SKShapeNode (kept in lineNode) into shapeNodes, it's non-sense. Your lineNode keeps all the lines you added to your pathToDraw.
Generally, you may need to learn when to instantiate objects, and when to release them.
Try this:
//### You are adding the same instance multiple times into this array, it's nonsense.
//var shapeNodes = [SKShapeNode]()
//### `pathToDraw` can be kept in the `SKShapeNode`.
//var pathToDraw = CGMutablePath()
//### In this case, this is not a good place to instantiate an `SKShapeNode`.
var lineNode: SKShapeNode?
func deleteAllShapeNodes() {
//### Release the `SKShapeNode` contained in `lineNode` to delete all lines.
lineNode?.removeFromParent()
lineNode = nil
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let firstPoint = touches.first!.location(in: self)
self.lineNode?.removeFromParent()
//### If you want somethings which live while dragging, `touchesBegan(_:with:)` is a good place to instantiate them.
let lineNode = SKShapeNode()
//### Create an empty new `CGMutablePath` at each `touchesBegan(_:with:)`.
let pathToDraw = CGMutablePath()
self.lineNode = lineNode
pathToDraw.move(to: firstPoint)
lineNode.lineWidth = 4
lineNode.strokeColor = UIColor.white
lineNode.name = "Line"
lineNode.zPosition = 100000
//### `pathToDraw` is kept in the `SKShapeNode`.
lineNode.path = pathToDraw
self.addChild(lineNode)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let positionInScene = touches.first!.location(in: self)
if let lineNode = self.lineNode {
//### Modify the `CGMutablePath` kept in the `SKShapeNode`.
let pathToDraw = lineNode.path as! CGMutablePath
pathToDraw.addLine(to: positionInScene)
//### Refresh the shape of the `SKShapeNode`.
lineNode.path = pathToDraw
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
self.deleteAllShapeNodes()
}
i found this code online that does the job but the posted code isn't full so if anyone can help me with the following
override func touchesBegan(touches: NSSet!, withEvent event: UIEvent!) {
touch = touches.anyObject() as UITouch!
firstPoint = touch.locationInNode(self)
}
override func touchesMoved(touches: NSSet!, withEvent event: UIEvent!) {
var touch = touches.anyObject() as UITouch!
var positionInScene = touch.locationInNode(self)
lineNode.removeFromParent()
CGPathMoveToPoint(pathToDraw, nil, firstPoint.x, firstPoint.y)
CGPathAddLineToPoint(pathToDraw, nil, positionInScene.x, positionInScene.y)
lineNode.path = pathToDraw
lineNode.lineWidth = 10.0
lineNode.strokeColor = UIColor.redColor()
self.addChild(lineNode)
firstPoint = positionInScene
}
what are lineNode and pathToDraw and if you can please show me how to write their code, or redirect me to something that can help.
I'm trying to throw a node around the screen, I've taken the below code but nothing actually happens.
When the scene loads the node spawns in the middle of the screen then drops to the bottom.
The code was taken from elsewhere in the site and granted it was a bit old so I'm assuming I'm missing something?
var sprite: SKSpriteNode!
var touchPoint: CGPoint = CGPoint()
var touching: Bool = false
override func didMove(to view: SKView) {
self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
sprite = SKSpriteNode(color: UIColor.red, size: CGSize(width: 50, height: 50))
sprite.physicsBody = SKPhysicsBody(rectangleOf: sprite.size)
sprite.position = CGPoint(x: 50.0, y: 50.0)
self.addChild(sprite)
}
func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.location(in: self)
if sprite.frame.contains(location) {
touchPoint = location
touching = true
}
}
}
func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.location(in: self)
touchPoint = location
}
}
func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
touching = false
}
func touchesCancelled(touches: Set<NSObject>!, withEvent event: UIEvent!) {
touching = false
}
func update(currentTime: TimeInterval) {
if touching {
let dt:CGFloat = 1.0/60.0
let distance = CGVector(dx: touchPoint.x-sprite.position.x, dy: touchPoint.y-sprite.position.y)
let velocity = CGVector(dx: distance.dx/dt, dy: distance.dy/dt)
sprite.physicsBody!.velocity = velocity
}
}
}
My Swift doodle app works, but when I change the alpha below '1.0', then I draw a line on the screen, the lines keeps overlapping. I created a custom Line class, drawView subclass of UIView. I've been messing around all day but can't seem to figure it out. See Below.
DrawView: UIView class
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
var touch = touches.first as! UITouch
lastPoint = touch.locationInView(self)
}
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
var touch = touches.first as! UITouch
var newPoint = touch.locationInView(self)
//from custom Line class: sets width and opacity as well
lines.append(Line(start: lastPoint, end: newPoint, color: drawColor, brushWidth: brushWidth, opacity: opacity))
lastPoint = newPoint
self.setNeedsDisplay()
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent){
touchesMoved(touches, withEvent: event) // adds point
}
override func drawRect(rect: CGRect) {
var context = UIGraphicsGetCurrentContext()
CGContextBeginPath(context)
CGContextSetLineCap(context, kCGLineCapRound)
for line in lines {
CGContextSetLineWidth(context, line.brushWidth)
CGContextSetAlpha(context, line.opacity)
CGContextSetStrokeColorWithColor(context, line.color.CGColor)
CGContextMoveToPoint(context, line.start.x, line.start.y)
CGContextAddLineToPoint(context, line.end.x, line.end.y)
CGContextStrokePath(context)
}
}
I don't know why it keeps overlapping. I some how need to track a the path then draw over it or somehow see if my CGPoints are the same while next to each other remove it or ignore it.
Is this possible using just one UIView?
Just now I tried using:
var touchesEnd: Bool = false //global variable
Then in touchesEnded:
touchesEnd = true
Finally in TouchesMoved:
if touchesEnd == true {
self.setNeedsDisplay()
}
This is the most recent things i've tried but hasn't worked.
I want to be able to move a sprite with my finger. I first have a variable for whether the finger is on the sprite or not:
var isFingerOnGlow = false
Then I have the touchesBegan function where I change the value of the above variable if the user touches the sprite:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
var touch = touches.anyObject() as UITouch!
var touchLocation = touch.locationInNode(self)
if let body = physicsWorld.bodyAtPoint(touchLocation) {
if body.node!.name == GlowCategoryName {
println("Began touch on hero")
isFingerOnGlow = true
}
}
}
Sometimes it works, and the console displays "began touch on hero", sometimes not. Is there a better way to code this first part?
Then I wonder if my following code for touchesMoved is effective:
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
if isFingerOnGlow{
var touch = touches.anyObject() as UITouch!
var touchLocation = touch.locationInNode(self)
var previousLocation = touch.previousLocationInNode(self)
var glow = SKSpriteNode(imageNamed: GlowCategoryName)
// Calculate new position along x for glow
var glowX = glow.position.x + (touchLocation.x - previousLocation.x)
var glowY = glow.position.y + (touchLocation.y - previousLocation.y)
// Limit x so that glow won't leave screen to left or right
glowX = max(glowX, glow.size.width/2)
glowX = min(glowX, size.width - glow.size.width/2)
glow.position = CGPointMake(glowX, glowY)
}
}
...
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
isFingerOnGlow = false
}
You can modify the functions like this to track the touches.
var isFingerOnGlow = false
var touchedGlowNode : SKNode!
override func touchesBegan(touches: NSSet, withEvent event:UIEvent) {
var touch = touches.anyObject() as UITouch!
var touchLocation = touch.locationInNode(self)
let body = self.nodeAtPoint(touchLocation)
if body.name == GlowCategoryName {
println("Began touch on hero")
touchedGlowNode = body
isFingerOnGlow = true
}
}
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
if isFingerOnGlow{
let touch = touches.anyObject() as UITouch!
let touchLocation = touch.locationInNode(self)
let previousLocation = touch.previousLocationInNode(self)
let distanceX = touchLocation.x - previousLocation.x
let distanceY = touchLocation.y - previousLocation.y
touchedGlowNode.position = CGPointMake(touchedGlowNode.position.x + distanceX,
touchedGlowNode.position.y + distanceY)
}
}
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
isFingerOnGlow = false
}