SpriteKiit Swift: touch a moving object
you have to set a name for your sprite like "ballNode", then in "touchesBegan" function you can handle it.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in (touches) {
let positionInScene = touch.location(in: self)
let touchedNode = self.atPoint(positionInScene)
if let name = touchedNode.name {
if name == "ballNode" {
//make it hidden by touchedNode.isHidden = true
//or remove it from parent by touchedNode.removeFromParent()
}
}
}
}
Touching moving Sprites in SpriteKit
Are your entities too small? With the given info, I recreated a small scene in a playground, and all is working as expected. If I have a presented child node, defined as
let circle = SKShapeNode(circleOfRadius: 20)
And I have defined both the physicsWorld of the SKScene, and physicsBody of the SKNode, with the given touchesBegan, there is no problem in detecting a collision.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let location = touches.first?.location(in: self)
if self.atPoint(location) === circle {
print("TOUCH")
}
}
}
Continuous Touch/Moving Swift & SpriteKit
Personally, I would create a controller class that has an update function that you poll on your scene update to determine whether a button state is up or down, and go off of that (Touch begins puts button in down state, touch end puts it in up state. update polls state, and performs actions based on state) But in your case, to keep things simple without changing a lot of code, I would just use SKAction.moveBy
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if location.y > 400{
move = true
}else{
//tap somewhere above this to make character jump
if(location.y > 250) {
player.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 200))
}
else
{
let direction = (location.x > CGRectGetMidX(self.frame)) ? 30 : -30
let move = SKAction.moveBy(x:direction,y:0,duration:0)
let rep = SKAction.repeatActionForever(move)
player.runAction(rep,forKey:"Moving")
}
}
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
player.removeActionForKey("Moving")
move = false
}
Move a node to finger using Swift + SpriteKit
You can save yourself a lot of trouble by using: myShip.physicsBody.applyImpluse(vector)
. It works by acting as if you gave myShip
a push in the direction vector
points. If you calculate vector
as the x distance from your last touch location to myShip
, then it'll accelerate, decelerate, change direction, etc. pretty close to the way you're describing because it'll be giving it little pushes in the right direction on each update
.
Basically you store the last touch location then, in your update
function, you calculate the CGVector
pointing from myShip
to lastTouch
and apply that as an impulse to your physics body.
Something like:
var lastTouch: CGPoint? = nil
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
let touch = touches.anyObject() as UITouch
let touchLocation = touch.locationInNode(self)
lastTouch = touchLocation
}
override func touchesMoved(touches: NSSet!, withEvent event: UIEvent!) {
let touch = touches.anyObject() as UITouch
let touchLocation = touch.locationInNode(self)
lastTouch = touchLocation
}
// Be sure to clear lastTouch when touches end so that the impulses stop being applies
override func touchesEnded(touches: NSSet!, withEvent event: UIEvent!) {
lastTouch = nil
}
override func update(currentTime: CFTimeInterval) {
// Only add an impulse if there's a lastTouch stored
if let touch = lastTouch {
let impulseVector = CGVector(touch.x - myShip.position.x, 0)
// If myShip starts moving too fast or too slow, you can multiply impulseVector by a constant or clamp its range
myShip.physicsBody.applyImpluse(impulseVector)
}
}
You'll also probably want to play with the linearDamping
and angularDamping
values on myShip.physicsBody
. They'll help determine how fast myShip
accelerates and decelerates.
I maxed out the values at 1.0
in my app:
myShip.physicsBody.linearDamping = 1.0
myShip.physicsBody.angularDamping = 1.0
If myShip
doesn't stop fast enough for you, you can also try applying some breaking in your update
function:
override func update(currentTime: CFTimeInterval) {
// Only add an impulse if there's a lastTouch stored
if let touch = lastTouch {
let impulseVector = CGVector(touch.x - myShip.position.x, 0)
// If myShip starts moving too fast or too slow, you can multiply impulseVector by a constant or clamp its range
myShip.physicsBody.applyImpluse(impulseVector)
} else if !myShip.physicsBody.resting {
// Adjust the -0.5 constant accordingly
let impulseVector = CGVector(myShip.physicsBody.velocity.dx * -0.5, 0)
myShip.physicsBody.applyImpulse(impulseVector)
}
}
Related Topics
Core Data Update in Swift While Selecting Any Row in List Table View Not Working
Retrieve an Image from Firebase to an Uiimage Swift5
Get All Documents at Once in a Completion Handler with Getdocuments in Firestore
How to Deallocate All References Elements from an Array
Iterate a Grid of Views Swiftui
How to Make a Uiview Grow in Uiview.Animate() with an Accurate Corner Radius
Fetch an Email Body in Mailcore2 Osx with Swift
How to Generate a Random Unicode Character in Swift
Different Path Url for Filemanager Everytime I Open the App
Ibeacon: Get Advertisement Package Faster
Problem Creating and Writing a Subdirectory in Swift 5
How to Handle Async Requests in Swift
How to Make Text Typed in Textfield Undeletable
How to Perform Conditional Segue