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;
}
Related
Here is a video of the issue I am having. As you can see in the video, I move a gray ball to try and collide with a red ball. When the two objects collide no bouncing occurs, the red ball just moves. I've tried playing around with the densities of the red balls, such as making the red ball densities 0.00001. There was no difference in the collision behavior.
How can I change the collision behavior so there is bouncing?
Here are the properties of the gray ball:
func propertiesGrayBall() {
gray = SKShapeNode(circleOfRadius: frame.width / 10 )
gray.physicsBody = SKPhysicsBody(circleOfRadius: frame.width / 10 )
gray.physicsBody?.affectedByGravity = false
gray.physicsBody?.dynamic = true
gray.physicsBody?.allowsRotation = false
gray.physicsBody?.restitution = 1
}
Here are the properties of the red ball:
func propertiesRedBall {
let redBall = SKShapeNode(circleOfRadius: self.size.width / 20
redBall.physicsBody = SKPhysicsBody(self.size.width / 20)
redBall.physicsBody?.affectedByGravity = false
redBall.physicsBody?.dynamic = true
redBall.physicsBody?.density = redBall.physicsBody!.density * 0.000001
redBall.physicsBody?.allowsRotation = false
redBall.physicsBody?.restitution = 1
}
Here is how I move the gray ball.
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
if fingerIsOnGrayBall {
let touch = touches.first
var position = touch!.locationInView(self.view)
position = self.convertPointFromView(position)
grayBall.position = position
}
}
Major Edits
The ball originally had attachments. I deleted them to simplify the problem. That's why the comments might not add up with the code.
If you move a node (with a physics body) by settings its position, directly or with an SKAction, the node will not be a part of the physics simulation. Instead, you should move the node by applying a force/impulse or by setting its velocity. Here's an example of how to do that:
First, define a variable to store the position of the touch
class GameScene: SKScene {
var point:CGPoint?
Then, delete the following statement from your code
redBall.physicsBody?.density = redBall.physicsBody!.density * 0.000001
Lastly, add the following touch handlers
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
for touch in touches {
let location = touch.locationInNode(self)
let node = nodeAtPoint(location)
if (node.name == "RedBall") {
point = location
}
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
for touch in touches {
let location = touch.locationInNode(self)
if point != nil {
point = location
}
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
point = nil
}
override func update(currentTime: CFTimeInterval) {
if let location = point {
let dx = location.x - redBall.position.x
let dy = location.y - redBall.position.y
let vector = CGVector(dx: dx*100, dy: dy*100)
redBall.physicsBody?.velocity = vector
}
}
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.
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
}
}
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.
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
}
}
}
}