I can detect only start point(touchBegan) that contain in c1 and end point(touchEnded) that contain in c2 but I can't detect path between them in c3, How should I do ?
Application image
override func layoutSubviews() {
self.clipsToBounds = true
self.isMultipleTouchEnabled = false
self.contentMode = .scaleToFill
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
swiped = false
lastPoint = touch?.location(in: self)
firstPoint = lastPoint
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
swiped = true
let currentPoint = touch?.location(in: self)
lastPoint = currentPoint
linePoint = lastPoint
drawShapeLayer(from: lastPoint, to: currentPoint!)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if !swiped {
drawShapeLayer(from: lastPoint, to: lastPoint!)
}
if c1.contains(firstPoint) && c3.contains(linePoint) && c2.contains(lastPoint){
AlertView.instance.showAlert(title: "Hooray!", message: "You made it!", alertType : .success)
}
else {
AlertView.instance.showAlert(title: "Oops!", message: "You've almost got it.", alertType : .failure)
}
}
}
As per my comments above, I think the there is a logic error in touchesMoved and you need to reorder the code if you are trying to draw a three point line, and then later check that each point is in a specific view area.
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
swiped = true
currentPoint = touch.location(in: self)
drawShapeLayer(from: lastPoint, to: currentPoint)
lastPoint = currentPoint
linePoint = currentPoint
}
}
(Also safely unwrapped touch to remove the optional and avoid crashes in the v unlikely scenario where touches.first is nil)
Related
I'm my game I'm using a custom SKSpriteNode which the player are going to be able to drag and drop at a position of his/hers desire.
My custom node is made of this code in file DraggableNode.swift:
class DraggableNode : SKSpriteNode {
var nodeSelected : SKNode?
init() {
let texture = SKTexture(imageNamed: "draggableNode_1")
super.init(texture: texture, color: UIColor.white, size: texture.size())
self.isUserInteractionEnabled = true
self.zPosition = 1
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let location = touch.location(in: self)
let touchedNodes = self.nodes(at: location)
for node in touchedNodes.reversed() {
nodeSelected = node
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first, let node = self.nodeSelected {
let touchLocation = touch.location(in: self)
node.position = touchLocation
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
nodeSelected = nil
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
nodeSelected = nil
}
}
In my GameScene.swift I add the custom node in this way:
let node = DraggableNode()
node.position = CGPoint(x: randomX, y: randomY)
self.addChild(node)
Now, the problem is that when I start to drag the node it's all jump and is placed a total random place - sometimes even out of the screenarea.
I wonder if the problem consists of the fact that it's a custom node inherited from a SKSpriteNode?
If anyone can point me in the right direction, I'd be a happy man :-)
I want change the image of a button as long as the user taps on it, but change the image back to the original if he releases his finger from the screen(I´m using Sprite-Kit)
My code:
var SettingButton = SKSpriteNode(imageNamed: "SettingButton1.0")
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let locationUser = touch.location(in: self)
if atPoint(locationUser) == SettingButton{
let SettingButton = SKSpriteNode(imageNamed: "SettingButton2.0") //change the image
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let locationUser = touch.location(in: self)
if atPoint(locationUser) == SettingButton{
//change image back to original
}
}
}
Try swapping the texture of the SpriteNode
var buttonTextureUp = SKTexture(imageNamed: "SettingButton1.0")
var buttonTextureDown = SKTexture(imageNamed: "SettingButton2.0")
var settingButton = SKSpriteNode(texture: buttonTextureUp)
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let locationUser = touch.location(in: self)
if atPoint(locationUser) == settingButton {
settingButton.texture = buttonTextureDown //change the image
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let locationUser = touch.location(in: self)
if atPoint(locationUser) == settingButton{
settingButton.texture = buttonTextureUp //change image back to original
}
}
}
I´m making a game with Swift.
I need to add nodes where I press the screen, I know this is not from other planet but I can't do it.
Highly simplified example could look like this:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
let location = touch.location(in: self)
let node = SKNode()
node.position = location
addChild(node)
}
Here is how you can add an remove labels by tapping:
class ViewController: UIViewController{
private var labels = [UILabel]()
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else {
return
}
for label in labels {
if label.frame.contains(touch.location(in: view)) {
label.removeFromSuperview()
return
}
}
let label = UILabel()
view.addSubview(label)
labels.append(label)
label.text = "touch"
label.sizeToFit()
label.center = touch.location(in: view)
}
}
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
}
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
}