Drawing using my finger in SpriteKit and swift 3 - ios

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.

Related

Nodes in SKShapeNode reappearing when creating another new node

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

Node not moving

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

nodeAtPoint wrong node

I'm making a game with swift and spritekit and I have a function where I have multiple sprites falling from the top of the screen. I also made it so I can be able to detect a touch on the sprite using nodeAtPoint, and made it possible to flick the sprites. My problem is that due to nodeAtPoint dragging the deepest node in the tree, when i click and drag on a sprite, the newest sprite in the scene gets pulled toward my touch instead of the one i originally touched. If anyone has some suggestions on how to only affect the node I touched I'd really appreciate it.
class GameScene: SKScene {
var ball = SKSpriteNode(imagedNamed: "blueBlue")
var touchedNode: SKNode? = SKNode()
override func didMoveToView(view: SKView) {
var create = SKAction.runBlock({() in self.createTargets()})
var wait = SKAction.waitForDuration(2)
var waitAndCreateForever = SKAction.repeatActionForever(SKAction.sequence([create, wait]))
self.runAction(waitAndCreateForever)
}
func createTargets() {
ball = SKSpriteNode(imageNamed: "blueBlue")
let randomx = Int(arc4random_uniform(170) + 290)
ball.zPosition = 0
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.width / 11)
ball.physicsBody?.dynamic = true
ball.size = CGSize(width: ball.size.width / 1.5, height: ball.size.height / 1.5)
let random = Int(arc4random_uniform(35))
let textures = [texture1, texture2, texture3, texture4, texture5, texture6, texture7, texture8, texture9, texture10, texture11, texture12, texture13, texture14, texture15, texture16, texture17, texture18, texture19, texture20, texture21, texture22, texture23, texture24, texture25, texture1, texture7, texture18, texture24, texture25, texture1, texture7, texture18, texture24, texture25]
ball.texture = textures[random]
ball.position = CGPoint(x: randomx, y: 1400)
addChild(ball)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
let touch = touches.first as! UITouch
let touchLocation = touch.locationInNode(self)
touchedNode = self.nodeAtPoint(touchLocation)
if touchedNode.frame.contains(touchLocation) {
touching = true
touchPoint = touchLocation
}
}
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
let touch = touches.first as! UITouch
let touchLocation = touch.locationInNode(self)
touching = true
touchPoint = touchLocation
}
override func update(currentTime: NSTimeInterval) {
if touching {
if touchPoint != touchedNode.position {
let dt: CGFloat = 0.1
let distance = CGVector(dx: touchPoint.x - touchedNode.position.x, dy: touchPoint.y - touchedNode.position.y)
let vel = CGVector(dx: distance.dx / dt, dy: distance.dy / dt)
if touchedNode.parent != nil {
touchedNode.physicsBody?.velocity = vel
}
}
}
}
}
I suggest you make the following changes to the code:
Add a check to see if a sprite is already being moved (if yes, do nothing)
Turn off the affectedByGravity property for the sprite being moved
Reset touchedNode and touching variables when the touch ends
Here's an implementation with the above changes...
Replace touchesBegan and touchesMoved with the following
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
let touch = touches.first as! UITouch
let touchLocation = touch.locationInNode(self)
if (!touching) {
let node = self.nodeAtPoint(touchLocation)
if node is SKSpriteNode {
touchedNode = node
touching = true
touchPoint = touchLocation
touchedNode!.physicsBody?.affectedByGravity = false
}
}
}
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
if (touching) {
let touch = touches.first as! UITouch
let touchLocation = touch.locationInNode(self)
touchPoint = touchLocation
}
}
And add this method
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
if (touchedNode != nil) {
touchedNode!.physicsBody!.affectedByGravity = true
}
touchedNode = nil
touching = false
}

How can I move sprites around with my finger?

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
}

Draw lines with Sprite kit and swift

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!

Resources