How can i alter my program to allow this object to only react to a single touch? - swift

I am making a basketball game. My problem is when I shoot the ball, i can then touch the ball in mid-air again, which i do not want. Once the user shoots the ball I do not want touch to have an effect. Here is my code:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?
{
touching = false
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if ball.frame.contains(location){
touchingPoint = location
touching = true
}
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
touchingPoint = location
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
if touching{
let dt:CGFloat = 8.25/29.5
let distance = CGVector(dx: touchingPoint.x-ball.position.x, dy: touchingPoint.y-ball.position.y)
let velocity = CGVector(dx: distance.dx/dt, dy: distance.dy/dt)
ball.physicsBody!.velocity=velocity
}
}
What can i add to my program so that a touch won't have any effect once the ball has been shot?

after you shoot the ball disable userInteraction
ball.userInteractionEnabled = false
then enable it again when you want them to be able to touch it

Related

Touch implementation in game

I am using Swift 3 with Xcode 8 and I am trying to make simple game with SpritKit. Basically what I'm trying to do is allow player to move my sprite only left and right ( drag it on screen ) and after realising finger ( touch ended ) apply impulse on sprite. I have managed to do that BUT i want that to happen only on first touch, so after applying impulse on sprite player cannot interact with sprite anymore until some collison happens or simillar. Below is my code which works all the time not only on first touch.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches {
let location = t.location(in: self)
if player.contains(location)
{
player.position.x = location.x
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches {
if let t = touches.first {
player.physicsBody?.isDynamic = true
player.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 50))
}
}
}
As Whirlwind commented, you just need a boolean value to determine when you should control the object:
/// Indicates when the object can be moved by touch
var canInteract = true
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches {
let location = t.location(in: self)
if player.contains(location) && canInteract
{
player.position.x = location.x
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches {
if let t = touches.first && canInteract {
canInteract = false //Now we cant't interact anymore.
player.physicsBody?.isDynamic = true
player.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 50))
}
}
}
/* Call this when you want to be able to control it again, on didBeginContact
after some collision, etc... */
func activateInteractivity(){
canInteract = true
// Set anything else you want, like position and physicsBody properties
}

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

All i'm trying to do is be able to drag and drop a sprite across the screen. I've tried the following code:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in (touches ) {
let location = touch.locationInNode(self)
if ball.containsPoint(location) {
ball.position = location
}
}
}
This code does work, however, when I drag the ball quite fast, I guess it detects that the "ball" no longer contains the point "location" and the ball stops, meaning I have pick the ball up again. I want the ball to be able to respond to my touches quickly, so that the ball wont stop moving. How would I do this?
This is the correct way to do it in Sprite Kit. Like I said in my comment, you need to assign the moving node to an activate state, in this case I use a variable called movableNode to act is my activate state. When you touch the ball, it becomes activated by assigning it to movableNode. Then as you drag your finger, movableNode will go with the drag, Then once you release, you enter a deactivate state by setting movableNode to nil. Note that this code will only work on single touch applications, if you want to handle multitouch, then you need to track which touch is doing the dragging.
var movableNode : SKNode?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let location = touch.locationInNode(self)
if ball.containsPoint(location) {
movableNode = ball
movableNode!.position = location
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first where movableNode != nil {
movableNode!.position = touch.locationInNode(self)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first where movableNode != nil {
movableNode!.position = touch.locationInNode(self)
movableNode = nil
}
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
movableNode = nil
}
}
KnightOFDragon solution works just fine. I just added few lines if you don't want to move sprite centre position to position where your finger touched the screen and you would like to move sprite from its centre original position.
var movableNode : SKNode?
var ballStartX: CGFloat = 0.0
var ballStartY: CGFloat = 0.0
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let location = touch.location(in: self)
if (map?.contains(location))! {
movableNode = ball
ballStartX = (movableNode?.position.x)! - location.x // Location X of your sprite when touch started
ballStartY = (movableNode?.position.y)! - location.y // Location Y of your sprite when touch started
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first, movableNode != nil {
let location = touch.location(in: self)
movableNode!.position = CGPoint(x: location.x+ballStartX, y: location.y+ballStartY) // Move node around with distance to your finger
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if let _ = touches.first, movableNode != nil {
movableNode = nil
}
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
movableNode = nil
}
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
}

Override function with sprite kit game

I am migrating my game from swift 1 and I can't figure out how to fix this function. I am trying to detect if no touches are taking place, which should keep the ball still. this is the code i have and keep getting error Invalid redeclaration of touchesBegan. Im not sure how to work around this, I've been stuck for a while and can't get the ball to stop moving when no touches present. Please help, thanks
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
// do nothing if ad is showing
if Ad.share().showing {
return
}
let touch = touches.first! as UITouch
let touchedLocation = touch.locationInNode(self)
// change the speedXFirst of the ball if it starts
if start {
// start move
let moveRight = touchedLocation.x > CGRectGetMidX(self.frame)
let speedX = moveRight ? ballSpeedX : -ballSpeedX
ball.speedXFirst = speedX
}
// start game if it stops
else {
startGame()
}
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { //error RIGHT HERE
if start {
// stop move
ball.speedXFirst = 0
}
If you ball must be stopped when the user detaches the finger from the screen, probably you want to use:
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
}
or this if you need to know when the touches were interrupted:
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
}

Move skspriteNode on swipe actions

What I want to do is making a SkspiteNode move from left to right and back. This happens on touch.
I have this code:
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches{
touchLocation = touch.locationInNode(self)
mainGuy.position.x = touchLocation.x;
}
}
This works. But when I have/move my finger at the right side of the screen and the mainGuy is at the left side of the screen it moves to my finger. This is not what I want to happen.
When I move my finger over the screen it needs to 'follow' my finger from the current position of the mainGuy.
How can I do this?
Do something like:
var touchesBeganPosition: CGPoint?
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
touchesBeganPosition = touches.first?.locationInNode(self)
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches {
touchLocation = touch.locationInNode(self)
if let touchesBeganPosition = touchesBeganPosition {
mainGuy.position.x = touchLocation.x - touchesBeganPosition.x
}
}
}
This is untested of of course, but should be enough to get the general idea.

Moving SKSpriteNode over screen

I want to move an SKSpriteNode over the screen with touch. The issue I have is that if I lock onto one sprite and then my finger drags it over another sprite the first one is let go and my finger starts to drag the second one. But once I touch the first sprite this is the only one I want to move.
There must be a simple way to resolve this?
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
let touch: UITouch = touches.first as UITouch!
touchLocation = touch.locationInNode(self)
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: UITouch = touches.first as UITouch!
let newTouchLocation = touch.locationInNode(self)
let targetNode = self.nodeAtPoint(touchLocation)
if targetNode.physicsBody!.categoryBitMask != PhysicsCategory.Ball {
targetNode.runAction(SKAction.moveBy(CGVector(point: newTouchLocation - touchLocation), duration: 0.0))
touchLocation = newTouchLocation
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
//I don't do anything with this yet
}
This is happening because your touchesMoved function is running every time your finger moves and if your finger moves over a new node, that node will be assigned to targetNode. You can fix this by changing this line:
let targetNode = self.nodeAtPoint(touchLocation)
To this:
let targetNode = self.nodeAtPoint(touch)
This way the node at the first touch will be the one that follows your finger and not the one at the last touch.
Thanks to TheCodeComposer, I found the solution:
var targetNode: SKNode!
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
let touch: UITouch = touches.first as UITouch!
touchLocation = touch.locationInNode(self)
targetNode = self.nodeAtPoint(touchLocation)
objectTouched(touch.locationInNode(self))
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch: UITouch = touches.first as UITouch!
let newTouchLocation = touch.locationInNode(self)
// let targetNode = self.nodeAtPoint(touchLocation)
if targetNode.physicsBody!.categoryBitMask != PhysicsCategory.Ball {
targetNode.runAction(SKAction.moveBy(CGVector(point: newTouchLocation - touchLocation), duration: 0.0))
touchLocation = newTouchLocation
}
}
I only define
targetNode
once and then continue to use it instead of redefining it in touchesMoved: