Recognizing an action only when I tap the SKSpriteNode? - ios

I have the following segment of code in which I want a tap to cause the ball to move in my screen.
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
moveBallUp()
moveBallLeft()
moveBallRight()
}
func moveBallUp() -> Void {
ball.physicsBody?.applyImpulse(CGVectorMake(0, impulseFactor))
}
func moveBallLeft() -> Void {
var random = -1 * CGFloat(Float(arc4random()))
ball.physicsBody?.applyImpulse(CGVectorMake(random % impulseFactor, 0))
}
func moveBallRight() -> Void {
var random = CGFloat(Float(arc4random()))
ball.physicsBody?.applyImpulse(CGVectorMake(random % impulseFactor, 0))
}
How do I make it such that only taps on the SKSpriteNode variable "ball" will cause the ball to move?

You can set ball's name (ballNode.name = "ball") and access it like this:
touchesBegan:
let location = (touch as UITouch).locationInNode(self)
if let ball = self.nodeAtPoint(location)
if ball.name == "ball" {
//move the ball
}
}
Another way would be using subclassing SKSpriteNode (and implementing touchesBegan method) like this:
class Ball : SKSpriteNode
{
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
//do your stuff here
}
}
If you are subclassing SKSpriteNode you have to set userInteractionEnabled = true. you can do this in ball's init method or after you create Ball object.

Related

Ease out animation for SKSpriteNode

I'm moving a sprite by using the touchesMoved method. So far this is working fine, but the result looks a little bit unnatural. The sprite stops immediately, once the movement of my finger stops. A more natural impression would be, if the sprite continuous the movement a little time with an ease out function. Any idea how to implement this?
Here is my code:
import SpriteKit
class GameScene: SKScene {
var sprite: SKSpriteNode?
var xOrgPosition: CGFloat = 0.0
override func didMoveToView(view: SKView) {
sprite = SKSpriteNode(imageNamed:"Spaceship")
sprite!.xScale = 0.1
sprite!.yScale = 0.1
sprite!.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
self.addChild(sprite!)
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches {
let xTouchPosition = touch.locationInNode(self).x
if xOrgPosition != 0.0 {
// calculate the new position
sprite!.position = CGPoint(x: sprite!.position.x - (xOrgPosition - xTouchPosition), y: sprite!.position.y)
}
// Store the current touch position to calculate the delta in the next iteration
xOrgPosition = xTouchPosition
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
// Reset value for the next swipe gesture
xOrgPosition = 0
}
}
Update:
I've made a short sample project, based on the answers from hamobi
Tutorial
Git repository
i think this might be what youre going for. let me know if you have any questions :)
import SpriteKit
class GameScene: SKScene {
var sprite: SKSpriteNode?
var xOrgPosition: CGFloat?
override func didMoveToView(view: SKView) {
sprite = SKSpriteNode(imageNamed:"Spaceship")
sprite!.xScale = 0.1
sprite!.yScale = 0.1
sprite!.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
self.addChild(sprite!)
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches {
xOrgPosition = touch.locationInNode(self).x
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
xOrgPosition = nil
}
override func update(currentTime: NSTimeInterval) {
if let xPos = xOrgPosition {
sprite!.position.x += (xPos - sprite!.position.x) * 0.1
}
}
}

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
}
}

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;
}

Dragging of SKShapeNode Not Smooth

So I am super new to swift and iOS development but not totally new to programming, and was just going through some tutorials, but basically my code looks like this:
import SpriteKit
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
let circle = SKShapeNode(circleOfRadius: 30.0)
circle.position = CGPointMake(100, 200)
addChild(circle)
}
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
for touch in touches {
let location = touch.locationInNode(self)
let touchedNode = nodeAtPoint(location)
touchedNode.position = location;
}
}
}
When I build this it recognizes and moves the circle when I drag it, but only for about 30 pixels and then I have to touch it again to move it. What am I doing wrong here?
I might be wrong but I believe your finger is leaving the node limits and enters the background. I would set it up as such:
// First make the shape available throughout the code and make sure you have a place to save the touch event for later use.
var circle: SKShapeNode!
var circleTouch: UITouch?
// Create the Shape
override func didMoveToView(view: SKView) {
circle = SKShapeNode(circleOfRadius: 30.0)
circle.position = CGPointMake(100, 200)
addChild(circle)
}
// When a finger is placed on the screen, check if it's in the circle, if it is, keep that touch even in memory so we can reference it later because other fingers could touch other things in the scene.
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
for touch in touches {
if nodeAtPoint(touch.locationInNode(self)) == circle {
circleTouch = touch as? UITouch
}
}
}
// Check if the touch event that is moving is the one that anchored the circle to our finger, if yes, move the circle to the position of the finger.
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
for touch in touches {
if circleTouch != nil {
if touch as UITouch == circleTouch! {
let location = touch.locationInNode(self)
circle.position = location
}
}
}
}
// Clean up the touch event when the finger anchoring the circle is raised from the screen.
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
for touch in touches {
if circleTouch != nil {
if touch as UITouch == circleTouch! {
circleTouch = nil
}
}
}
}
You can also use if let statements in there but I checked for nil instead for clarity.
Tokuriku, thanks so much, you we're not quite right but it got me to the eventual answer, here it is
import SpriteKit
class GameScene: SKScene {
var circleTouch: UITouch?
override func didMoveToView(view: SKView) {
/* Setup your scene here */
let circle = SKShapeNode(circleOfRadius: 40.0)
circle.fillColor = UIColor.blackColor()
circle.position = CGPoint(x: size.width * 0.5, y: size.height * 0.2)
circle.name = "userCircle"
addChild(circle)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
for touch in touches {
if nodeAtPoint(touch.locationInNode(self)).name == "userCircle" {
circleTouch = touch as? UITouch
}
}
}
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
for touch in touches {
if circleTouch != nil {
if touch as UITouch == circleTouch! {
let location = touch.locationInNode(self)
let touchedNode = nodeAtPoint(location)
touchedNode.position = location
}
}
}
}
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
for touch in touches {
if circleTouch != nil {
if touch as UITouch == circleTouch! {
circleTouch = nil
}
}
}
}

Making a rubbing screen gesture in iOS?

Basically, I want to make a mobile game using a custom hand gesture. The gesture is kind of like rubbing the screen, from left to right and from right to left.
If the gesture moves from the left to right, this will call a method and add a point. And once the gesture rubs from right to left, the user can also get one point.
But the problem is, when I use Swipe gesture recognizer, I have to release my finger from the screen, in order to call the method. If I just do the rub gesture, I am unable to call the method to add points.
Instead, I try the touchesBegan, touchesMoved method to detect the finger's position. However, touchesMoved will create many points to compare with the starting point, which leads to calling the methods many times instead of once.
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
for touch: AnyObject in touches
{
self.touchStartPoint = touch.locationInView(self.myView).x
}
}
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
for touch: AnyObject in touches
{
self.touchOffsetPoint = touch.locationInView(self.myView).x - touchStartPoint
if tempTouchOffsetPoint < touchOffsetPoint
{
var xValueIncreaseArray: NSMutableArray = []
xValueIncreaseArray.addObject(touchOffsetPoint)
var maxValue: Double = (xValueIncreaseArray as AnyObject).valueForKeyPath("#max.self") as Double
println("\(maxValue)")
if maxValue - Double (self.touchStartPoint) > 50
{
println("right")
}
println("right")
}
else if tempTouchOffsetPoint > touchOffsetPoint
{
/* var xValueDecreaseArray: NSMutableArray = []
xValueDecreaseArray.addObject(touchOffsetPoint)*/
println("left")
}
else if tempTouchOffsetPoint == touchOffsetPoint
{
println("Remain")
}
tempTouchOffsetPoint = touchOffsetPoint
}
Are there any ways to detect the rubbing gesture? And every time the finger turns its direction, it will call a method only ONCE to add a score to user? Thank you so much!
This works for me:
let deadZone:CGFloat = 10.0
var previousTouchPoint: CGFloat!
var isMovingLeft:Bool? = nil
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
let point = touches.anyObject()?.locationInView(self)
if let newPoint = point?.x {
if previousTouchPoint == nil {
println("Started")
previousTouchPoint = newPoint
} else {
// Check if they have moved beyond the dead zone
if (newPoint < (previousTouchPoint - deadZone)) || (newPoint > (previousTouchPoint + deadZone)) {
let newDirectionIsLeft = newPoint < previousTouchPoint
// Check if the direction has changed
if isMovingLeft != nil && newDirectionIsLeft != isMovingLeft! {
println("Direction Changed: Point")
}
println((newDirectionIsLeft) ? "Moving Left" : "Moving Right")
isMovingLeft = newDirectionIsLeft
previousTouchPoint = newPoint
}
}
}
}
override func touchesCancelled(touches: NSSet!, withEvent event: UIEvent!) {
previousTouchPoint = nil
isMovingLeft = nil
}
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
previousTouchPoint = nil
isMovingLeft = nil
}

Resources