How to Drag and Drop a Sprite in Swift 3.0

How do I drag and drop a sprite in Swift 3.0?

I have an implementation where I've subclassed a UIImageView and called it a "DraggableImage"

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
originalPosition = self.center
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let position = touch.location(in: self.superview)
self.center = CGPoint(x: position.x, y: position.y)
}
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {

self.center = originalPosition
}

Move a sprite randomly using Swift 3

That is happening because only the last action from the for loop is executed. You have to make a queue of actions. So you should append them to an array, and run them in a sequence, like this:

import SpriteKit

import GameplayKit

class GameScene: SKScene {

private let greenDragonNode = SKSpriteNode(color: .green, size: CGSize(width: 20, height: 20))

func getRandomPoint(withinRect rect:CGRect)->CGPoint{

let x = CGFloat(arc4random()).truncatingRemainder(dividingBy: rect.size.width)
let y = CGFloat(arc4random()).truncatingRemainder(dividingBy: rect.size.height)

return CGPoint(x: x, y: y)
}

override func didMove(to view: SKView) {

greenDragonNode.position = self.getRandomPoint(withinRect: frame)

addChild(greenDragonNode)

var actions:[SKAction] = []

for i in 1...20 {

let destination = getRandomPoint(withinRect: frame)

let move = SKAction.move(to:destination, duration: 1.0)

actions.append(move)

let label = SKLabelNode(text: "\(i)")
label.position = destination
addChild(label)
}

let sequence = SKAction.sequence(actions)
greenDragonNode.run(sequence)

}
}

(Xcode Swift SpriteKit) How do I move a sprite in the direction it is facing

You will need to use sin and cos. An SKAction may not be the best thing for you, so I would just do this in the update method for now till you find a better spot:

sprite.position = CGPoint(x:sprite.position.x + cos(sprite.zRotation) * 10,y:sprite.position.y + sin(sprite.zRotation) * 10)

Where 10 is the magnitude that you want the sprite to move (aka move 10 pixels)

This assumes that angle 0 means the sprite is looking right, angle 90 (PI/2) is looking up, angle 180 (PI) is looking left, and angle 270 (3PI/2) is looking down.

Dragging and flicking/throwing skspritenode

This should work, I just dug it out from an old project.

CGFloat dt is for changing the speed/power of the movement.

var touching = false

override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {

let touch = touches.first as! UITouch
let location = touch.locationInNode(self)
if sprite.frame.contains(location) {
touchPoint = location
touching = true
}
}
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {

let touch = touches.first as! UITouch
let location = touch.locationInNode(self)
touchPoint = location
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
touching = false
}
override func update(currentTime: CFTimeInterval) {
if touching {
if touchPoint != sprite.position
{
let dt:CGFloat = 0.15
let distance = CGVector(dx: touchPoint.x-sprite.position.x, dy: touchPoint.y-sprite.position.y)
let vel = CGVector(dx: distance.dx/dt, dy: distance.dy/dt)
sprite.physicsBody!.velocity = vel
}
}
}

EDIT:
The reason it gets stronger the farther the distance, is because the vector IS the distance between the the sprite and the touch point.
Try popping this in as the update function. It should work...

override func update(currentTime: CFTimeInterval) {
if touching {
if touchPoint != sprite.position
{
let pointA = touchPoint
let pointB = sprite.position
let pointC = CGPointMake(sprite.position.x + 2, sprite.position.y)
let angle_ab = atan2(pointA.y - pointB.y, pointA.x - pointB.x)
let angle_cb = atan2(pointC.y - pointB.y, pointC.x - pointB.x)
let angle_abc = angle_ab - angle_cb
let vectorx = cos(angle_abc)
let vectory = sin(angle_abc)
let dt:CGFloat = 15
let vel = CGVector(dx: vectorx * dt, dy: vectory * dt)
sprite.physicsBody!.velocity = vel
}
}
}

With the touchPoint (pointA), and the sprite's position (pointB) we can create an angle.

atan2, is a very famous function from C, it creates the angle between two points.
BUT, it's 0 degrees is in a different location than usual.

So, we need our own 0 degrees marker, I use the mid-right of the point as my marker.
It's the common 0 degree placement:

http://www.cs.ucsb.edu/~pconrad/images/math/unitCircleWithDegrees.png

Since it's to the right of the sprite's position, we create a point just to the right of the sprite (pointC).

We now use atan2 to find the angle.

To create a vector from an angle, we just use cos and sin for the x and y values.

How to drag and release an object with velocity

Dragging and releasing a sprite with velocity can be accomplished by

First, a struct to store touch data

struct TouchInfo {
var location:CGPoint
var time:NSTimeInterval
}

Declare SKScene subclass properties

var selectedNode:SKSpriteNode?
var history:[TouchInfo]?

In touchesBegan

  1. Save the sprite that the user touched
  2. Save touch event data

Swift code:

let touch = touches.anyObject() as UITouch
let location = touch.locationInNode(self)
let node = self.nodeAtPoint(location)
if (node.name == "player") {
// Step 1
selectedNode = node as? SKSpriteNode;
// Stop the sprite
selectedNode?.physicsBody?.velocity = CGVectorMake(0,0)
// Step 2: save information about the touch
history = [TouchInfo(location:location, time:touch.timestamp)]
}

In touchesMoved

  1. If a sprite was selected in touchesBegan, move the sprite to the new location
  2. Save the touch event data

Swift code:

let touch = touches.anyObject() as UITouch
let location = touch.locationInNode(self)
if (selectedNode != nil) {
// Step 1. update sprite's position
selectedNode?.position = location
// Step 2. save touch data at index 0
history?.insert(TouchInfo(location:location, time:touch.timestamp),atIndex:0)
}

In touchesEnded

  1. Calculate the differences in x and y from the last touch and the current touch
  2. Find the time difference between touch events
  3. Calculate and keep a sum of the velocity components in x and y
  4. Create a velocity vector and apply it to the sprite
  5. Unselect the node

Swift code:

if let history = history, history.count > 1 && selectedNode != nil {
var vx:CGFloat = 0.0
var vy:CGFloat = 0.0
var previousTouchInfo:TouchInfo?
// Adjust this value as needed
let maxIterations = 3
var numElts:Int = min(history.count, maxIterations)
// Loop over touch history
for index in 0..<numElts {
let touchInfo = history[index]
let location = touchInfo.location
if let previousTouch = previousTouchInfo {
// Step 1
let dx = location.x - previousTouch.location.x
let dy = location.y - previousTouch.location.y
// Step 2
let dt = CGFloat(touchInfo.time - previousTouch.time)
// Step 3
vx += dx / dt
vy += dy / dt
}
previousTouchInfo = touchInfo
}
let count = CGFloat(numElts-1)
// Step 4
let velocity = CGVectorMake(vx/count,vy/count)
selectedNode?.physicsBody?.velocity = velocity
}
// Step 5
selectedNode = nil
history = nil

Sprite won't move with finger/ SpriteKit / Swift 3

this code

simpleS = self.childNode(withName: "simpleS") as! SKSpriteNode

connects the sprites in your GameScene.sks with GameScene.swift
so in the first step you have to make sure that you set the right name (exactly "simpleS") in your sks file.

if you did it right, so please send the error for us.
i have built and ran your code and everything works in a right way.

another point is that if you want your sprites only moves by your finger movement you have to delete the codes in touchesBegan function, because touchesBegan moves your sprite wherever you touch.



Related Topics



Leave a reply



Submit