Touchesmoved - updating multiple elements on single drag - swift

I'm trying to update multiple images upon clicking and dragging over the elements. I've implemented touchesbegan, touchesmoved, and touchesended, but I don't know how to make touchesmoved effect multiple images.
I've been scouring the web, but I haven't been able to find any guides on this. If you could point me in the right direction, or provide me with some basic advice, that would be greatly appreciated.
The following is an example image:
Edit: The following is an example image of what should be possible:
What it should look like.
I'd like to be able to effect the other letters in the same way through the same press, changing their pictures. These pictures are temporary images.
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
print("touches began:\(touches)")
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.image = UIImage(named: "slot")!
print("touches moved:\(touches)")
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.image = UIImage(named: "tile")!
print("touches ended")
}

If I understood you correctly, that should be something like this:
class ChangableView: UIView {
private var touchedImageView: UIImageView? {
didSet {
if oldValue == touchedImageView { return }
if let oldValue = oldValue {
oldValue.image = UIImage(named: "tile")!
}
if let newValue = touchedImageView {
newValue.image = UIImage(named: "slot")!
}
}
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
guard let touch = touches.first else { return }
updateTouchedImageViewWithTouch(touch, event: event)
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
guard let touch = touches.first else { return }
updateTouchedImageViewWithTouch(touch, event: event)
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
touchedImageView = nil
}
}
private extension ChangableView {
func updateTouchedImageViewWithTouch(touch: UITouch, event: UIEvent?) {
let touchPoint = touch.locationInView(self)
let touchedView = self.hitTest(touchPoint, withEvent: event)
touchedImageView = touchedView as? UIImageView
}
}
In addition your UIViewController should have as view a subclass of ChangableView and do not forget to set userInteractionEnabled property to all the UIImageViews to YES.

Related

How to use a tochesBegan() method as an extension of a class?

How can I add a touchesBegan() method to my class?
Here is my method:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let locationUser = touch.location(in: self)
}}
You can use class extension adding the method in it if your
class is a subclass of UIView or UIWindow:
extension YourClass {
override open func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
for touch in touches{
let locationUser = touch.location(in: self)
}
print("touchesBegan")
}
}

Subclassed node, but want to detect touch in the scene

I have a subclassed node called LocationNode, where touch is enabled. It looks like this.
class LocationNode: SKSpriteNode, CustomNodeEvents {
func didMoveToScene() {
self.isUserInteractionEnabled = true
}
}
I haven't overriden touchesBegan in this subclass file, because I want to control all touch events like this in the actual scene file:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touchLocation = touches.first!.location(in: self)
let touchedNode = self.atPoint(touchLocation)
//if touchedNode.name != nil {
print("touched")
//}
}
When I try do this, however, it doesn't work. How can I control touch events for a subclassed node in the scene file?
EDIT:
Here's what my override function looks like in the scene.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touchLocation = touches.first!.location(in: self)
let touchedNode = self.atPoint(touchLocation)
print("TOUCHED")
}
You could implement this code below in your custom class, in this case LocationNode, to have a "return of touches" to the parent class, then you can handle the touches in both places (also to the main scene) :
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
print("touched!")
}
guard let parent = self.parent else { return }
parent.touchesBegan(touches, with: event)
}

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
}

Method does not override any method from it's superclass

I'm trying to create a new override func when i got this error: Method does not override any method from it's superclass
I have already tried to delete the override part but that only gives me another error.
override func touchesBegan(touches: NSSet!, withEvent event: UIEvent!) {
let touch : UITouch! = touches.anyObject() as! UITouch
location = touch.locationInView(self.view)
person.center = location
}
override func touchesMoved(touches: NSSet!, withEvent event: UIEvent!) {
let touch : UITouch! = touches.anyObject() as! UITouch
location = touch.locationInView(self.view)
person.center = location
}
The correct method signatures are:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
}