How can I avoid a delay with continues touch detection in swift? - ios

I want control a character on my screen with a continuous swipe gesture. As soon as I do a swipe +x or -x my character moves left or right. And as long as I hold my finger it continuous to move to the direction in that I swiped. When I swipe into the opposite direction of my last swipe without leaving my finger from the touch ground, my character should move into this direction. When I release my finger from the touch screen, my character should stops instantly.
My problem is that there is often a small delay within the change of direction. And this delay makes it less precise.
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
var player = self.childNodeWithName("man")
for touch in (touches as! Set<UITouch>) {
let location = touch.locationInNode(self)
let touchedNode = self.nodeAtPoint(location)
lastFingerPosition = location
}
}
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent){
var player = self.childNodeWithName("man")
for touch in (touches as! Set<UITouch>) {
let location = touch.locationInNode(self)
let touchedNode = self.nodeAtPoint(location)
if(location.x > lastFingerPosition?.x){
movePlayer("right")
} else if(location.x < lastFingerPosition?.x)
movePlayer("left")
}
}
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
var player = self.childNodeWithName("man")
for touch in (touches as! Set<UITouch>) {
let location = touch.locationInNode(self)
let touchedNode = self.nodeAtPoint(location)
if(touchedNode.name != "buttonFire"){
player?.removeAllActions()
lastMoveDirection = ""
}
}
}
func movePlayer(direction: String) {
var player = self.childNodeWithName("man")
if(lastMoveDirection != direction){
player?.removeAllActions()
lastMoveDirection = direction
var duration:CGFloat? = 0
var x = player?.position.x
duration = x!
if(direction == "left"){
var xDestination:CGFloat = 10
var run = SKAction.moveToX(10, duration: NSTimeInterval(Double(duration! / runSpeed)))
player?.runAction(run, withKey: "moveLeft")
} else if(direction == "right") {
duration = self.frame.width - x!
var xDestination = frame.size.width - 1
var run = SKAction.moveToX(xDestination, duration: NSTimeInterval(Double(duration! / runSpeed)))
player?.runAction(run, withKey: "moveRight")
}
}
}

I think it is not a programmatic problem. It is more an issue of the control itself. Because a swipe with your finger into one direction and then, a swipe to the opposite direction results in a rotation of your thumb.
And while it's rotating a little bit, it is not moving and that causes the feeling of a delay.
I guess this control is useless, if you need really precise moves - just because of the anatomy of our thumbs.

Related

Calculating the velocity of a swipe

I'm trying to do something (print "Swiped") IF the velocity of a swipe is greater than a specified criteria. Based on researching I've come up with this code. "Began" gets printed whenever I touch the screen, but "Ended" and "Swiped" only print when I first tap and hold the screen, then drag, then lift up (a rather slow process). I hope i can just flick the screen and my text gets printed, but right now it will only print if i take my time with the swipe process. Not exactly a quick swipe.. you know? Hopefully this makes sense!
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
print("Began")
for touch in touches {
let location:CGPoint = touch.locationInView(self.view!)
start = location
startTime = touch.timestamp
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
print("Ended")
for touch in touches {
let location:CGPoint = touch.locationInView(self.view!)
var dx:CGFloat = location.x - start!.x;
var dy:CGFloat = location.y - start!.y;
var magnitude:CGFloat = sqrt(dx*dx+dy*dy)
if (magnitude >= kMinDistance) {
print("OK")
var dt:CGFloat = CGFloat(touch.timestamp - startTime!)
if (dt > kMinDuration) {
var speed:CGFloat = magnitude / dt;
if (speed >= kMinSpeed && speed <= kMaxSpeed) {
print("Swiped")
}
}
}
}
}

How to speed up the movement of the object?

In the scene of a finger you can move the object. But if you just speed up the movement of the finger on the screen - the object remains in place. Is it possible to accelerate the speed of its movement? Duration is already set to 0
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
let touchLocation = touch!.locationInNode(self)
let node = self.nodeAtPoint(touchLocation)
if (node.name == "circle") {
let moveAction = SKAction.moveTo(touchLocation, duration: 0)
figureUser.runAction(moveAction)
}
}
Your problem is not the speed, your problem is you are moving so fast on the screen, that your touch is not recognizing a node underneath it anymore because the node is physically not underneath it. How you handle this problem is on the touch begin event, you check for a node, and assign this node to a variable. Then on the touch move event, update the new variable. Finally on touch end, clear the variable. Note, you would need to handle this code for things like multi touch
var movingNode : SKNode?
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
let touchLocation = touch!.locationInNode(self)
let node = self.nodeAtPoint(touchLocation)
if (node.name == "circle") {
movingNode = node
let moveAction = SKAction.moveTo(touchLocation, duration: 0)
figureUser.runAction(moveAction)
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
let touchLocation = touch!.locationInNode(self)
let moveAction = SKAction.moveTo(touchLocation, duration: 0)
//at this point I am lost, how does node even relate here,
//is figureUser suppose to be node?
figureUser.runAction(moveAction)
}

How do I use buttons or a slider to rotate a sprite?

I am making a game for iOS in Swift with SpriteKit, the game is currently just a ball moving around with a sword.
I have anchored the sword to the bottom of the sword, but I need to know how to control the direction of rotation with 2 buttons or a slider of some sort.
Here is my code:
import SpriteKit
let sprite = SKSpriteNode(imageNamed:"Player")
let weapon = SKSpriteNode(imageNamed: "weapon")
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
let initialPlayerLocation = CGPoint(x: self.frame.width/2, y: self.frame.height/2)
/* Setup your scene here */
//player
sprite.setScale(1.0)
sprite.position = initialPlayerLocation
sprite.zPosition = 20
self.addChild(sprite)
//weapon
weapon.setScale(1.0)
weapon.position = initialPlayerLocation
weapon.zPosition = -20
weapon.anchorPoint = CGPointMake(0.5,0.0);
self.addChild(weapon)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch in (touches as! Set<UITouch>) {
let location = touch.locationInNode(self)
var move = SKAction.moveTo(location, duration:1.0)
sprite.runAction(move)
weapon.runAction(move)
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
Okay, I think I understand what you are trying to do. It involves a lot of code, but in theory it is pretty simple. We detect if the touch is inside the left or right buttons (which in this example, I've made them SKSpriteNodes), and then set boolean values for the update method to use and rotate the weapon node (I'm assuming this is the sword you were talking about).
I've also included a variable that lets you set the speed of rotation. As you did not say what speed you were looking for, I left it up to you.
At the top of the program:
let sprite = SKSpriteNode(imageNamed:"Player")
let weapon = SKSpriteNode(imageNamed: "weapon")
let leftButton = SKSpriteNode(imageNamed: "leftButton")
let rightButton = SKSpriteNode(imageNamed: "rightButton")
var leftPressed = false
var rightPressed = false
let weaponRotateSpeed = 0.01 // Change this for rotation speed of weapon
And then modify touchesBegan to look like this:
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch in (touches as! Set<UITouch>) {
let location = touch.locationInNode(self)
if (leftButton.containsPoint(p: location))
leftPressed = true
else if (rightButton.containsPoint(p: location))
rightPressed = true
else {
var move = SKAction.moveTo(location, duration:1.0)
sprite.runAction(move)
weapon.runAction(move)
}
}
In update, add this code:
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
if (leftPressed && rightPressed) {
// Do nothing, as both buttons are pressed
} else if (leftPressed) {
weapon.zRotation -= weaponRotateSpeed
} else if (rightPressed) {
weapon.zRotation += weaponRotateSpeed
}
}
We want to stop the weapon from rotating when we detect when the finger has moved off the button like so:
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch in (touches as! Set<UITouch>) {
let location = touch.locationInNode(self)
if (leftButton.containsPoint(p: location))
leftPressed = true
else
leftPressed = false
if (rightButton.containsPoint(p: location))
rightPressed = true
else
rightPressed = false
}
}
And at last, we need to detect when your finger has left the screen:
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if (leftButton.containsPoint(p: location))
leftPressed = false
if (rightButton.containsPoint(p: location))
rightPressed = false
}
}

How to limit the number of nodes? (Spritekit)

I have a little problem. check it out:
override func touchesBegan(touches: Set, withEvent event: UIEvent) {
for touch in (touches as! Set<UITouch>) {
var Location:CGPoint = touch.locationInNode(self)
var Node:SKNode = self.nodeAtPoint(Location)
if(Location.x < self.size.width/2) {
node2.addchild(sprite2)
node1.removeFromParent()
}
if (Location.x > self.size.width/2) {
node1.addchild(sprite1)
node2.removeFromParent()
}
The problem is that when I tap for exmple 10 times on the same side of the screen (let's say, the right side) it apppears 10 spritenodes and I can't use "hidden" because of the physicsBody. Can you guys help me?

One touch moving in 2 points, but it is not moving

Please help!
I want to let my ball moving when the screen is touched to other position and on next touch to original position.
I only want to change X position the Y will be the same.
But when I touch the screen it is doing nothing.
This is the code, I have written for the ball.
override func didMoveToView(view: SKView) {
addball()
}
func addball() {
ball = SKSpriteNode(imageNamed: "Ball")
self.ball.position = CGPointMake(frame.size.width/4, frame.size.height/3)
self.addChild(ball)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
for touch: AnyObject in touches {
if touches.count % 2 == 0 {
let right = SKAction.moveToX(frame.size.width/4*3, duration: 0.1)
self.ball.runAction(right)
} else {
let left = SKAction.moveToX(frame.size.width/4, duration: 0.1)
self.ball.runAction(left)
}
}
}
Thanks for all answers:)
This may be a silly answer, but are you touching it with 2 fingers at the same time?
Try doing touches.count > 0 instead to test if it is just the touch.
If you are touching 1 finger, then another, your touch count will stay at 1 because only 1 touch began event happened.
The first touch will be part of the move state, the second touch is your begin state
Edit:
var toggle = false;
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
for touch: AnyObject in touches {
if toggle {
let right = SKAction.moveToX(frame.size.width/4*3, duration: 0.1)
self.ball.runAction(right)
} else {
let left = SKAction.moveToX(frame.size.width/4, duration: 0.1)
self.ball.runAction(left)
}
}
toggle = !toggle;
}

Resources