i have a sprite kit game and im trying to know if the user has touch the left, right or middle of the screen (25/50/25)
At the moment when i touch the very left side of the screen, it says im touching -450 on the x axis when it should be 0. I assume its getting my touch position relative to the scene and as the achor point starts 450 pixels to the right, gives me -450 when i touch 0.
As this is a side scroller, moving the achor wont work and i need the touch location of the screen:
override func touchesBegan(_ touches: Set<UITouch>,with event: UIEvent?){
var touchLeft : Bool = false
var touchRight : Bool = false
var touchMiddle : Bool = false
for touch in (touches) {
let location = touch.location(in: self)
if(location.x < self.size.width/4){
touchLeft = true
print("Left")
} else if(location.x > ((self.size.width/4) * 3)){
touchRight = true
print("Right")
} else {
touchMiddle = true
print("Middle")
}
}
}
You almost had it, just factor in negative numbers.
In case you were not aware, 0 is the center by default for SKScene. This is because the default anchor point is 0.5,0.5.
Since you are using the camera to handle your scrolling, you want to use
touch.location(in: self.camera) so that you are always touching relative to where the camera is and not where the scene is.
So just change your code to as follows:
override func touchesBegan(_ touches: Set<UITouch>,with event: UIEvent?){
var touchLeft : Bool = false
var touchRight : Bool = false
var touchMiddle : Bool = false
for touch in (touches) {
let location = touch.location(in: self.camera)
if(location.x < -self.size.width/4){
touchLeft = true
print("Left")
} else if(location.x > ((self.size.width/4))){
touchRight = true
print("Right")
} else { //x is between -width / 4 and width / 4
touchMiddle = true
print("Middle")
}
}
}
Related
I am creating an iPhone app in which the user taps structures on an image of an MRI scan to select regions of interest and calculate a score. Each screen contains a UIView with multiple UIImage views. Each UIImageView that is touched by the user is "highlighted". However, on one of the screens the structures of interest are so close together that the frame rectangles of the UIImageView overlap (3 of them). Now, tapping in some areas highlights the wrong image. Rearranging views does not help (moving to front or back) doesn't help, there is a large area of overlap. I included a screen shot of the Storyboard and corresponding code of the view controller. Can anybody think of a solution??
override func touchesBegan(_ touches: Set, with event: UIEvent?)
{
let touch = touches.first!
switch touch.view {
case PO_PV_R:
if PO_PV_R.isHighlighted == false
{
PO_PV_R.isHighlighted = true
loesScore.parieto_occipital_R_perivent = 0.5
}
else
{
PO_PV_R.isHighlighted = false
loesScore.parieto_occipital_R_perivent = 0.0
}
case PO_C_R:
if PO_C_R.isHighlighted == false
{
PO_C_R.isHighlighted = true
loesScore.parieto_occipital_R_central = 0.5
}
else
{
PO_C_R.isHighlighted = false
loesScore.parieto_occipital_R_central = 0.0
}
case PO_SC_R:
if PO_SC_R.isHighlighted == false
{
PO_SC_R.isHighlighted = true
loesScore.parieto_occipital_R_subcortical = 0.5
}
else
{
PO_SC_R.isHighlighted = false
loesScore.parieto_occipital_R_subcortical = 0.0
}
default:
print("default")
}
let score = loesData.shared.totalLoesScore()
scoreLabel.text = String(format:"%.1f", score)
}
I am currently working on an arcade app where the user taps for the sprite to jump over an obstacle and swipes down for it to slide under an obstacle. My problem is that when I begin a swipe the touchesBegan function is called so the sprite jumps instead of sliding. Is there a way to distinguish these two?
You can use a gestures state to fine tune user interaction. Gestures are coordinated, so shouldn't interfere with each other.
func handlePanFrom(recognizer: UIPanGestureRecognizer) {
if recognizer.state != .changed {
return
}
// Handle pan here
}
func handleTapFrom(recognizer: UITapGestureRecognizer) {
if recognizer.state != .ended {
return
}
// Handle tap here
}
How about using a slight delay for your touch controls? I have a game where I do something similar using a SKAction with delay. Optionally you can set a location property to give your self a bit of wiggle room with the touchesMoved method incase someone has a twitchy finger (thanks KnightOfDragon)
let jumpDelayKey = "JumpDelayKey"
var startingTouchLocation: CGPoint?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
// starting touch location
startingTouchLocation = location
// start jump delay
let action1 = SKAction.wait(forDuration: 0.05)
let action2 = SKAction.run(jump)
let sequence = SKAction.sequence([action1, action2])
run(sequence, withKey: jumpDelayKey)
}
}
func jump() {
// your jumping code
}
Just make sure the delay is not too long so that your controls dont feel unresponsive. Play around with the value for your desired result.
Than in your touches moved method you remove the SKAction if your move threshold has been reached
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
guard let startingTouchLocation = startingTouchLocation else { return }
// adjust this value of how much you want to move before continuing
let adjuster: CGFloat = 30
guard location.y < (startingTouchLocation.y - adjuster) ||
location.y > (startingTouchLocation.y + adjuster) ||
location.x < (startingTouchLocation.x - adjuster) ||
location.x > (startingTouchLocation.x + adjuster) else {
return }
// Remove jump action
removeAction(forKey: jumpDelayKey)
// your sliding code
}
}
You could play around with Gesture recognisers although I am not sure that will work and how it affects the responder chain.
Hope this helps
I've looked everywhere but nothing works. Thought I would just ask the question myself. I'm creating a little game in iOS 9 using SpriteKit. My game is going to have left and right controller buttons to move the player sprite. I add the SKSpriteNodes for the directional pads as follows
At the top of the main scene I put:
private var leftDirectionalPad = SKSpriteNode(imageNamed: "left")
private var rightDirectionalPad = SKSpriteNode(imageNamed: "right")
Then I run a method called prepareDirectionalPads
func prepareDirectionalPads() {
// left
self.leftDirectionalPad.position.x = self.size.width * directionalPadLeftXPositionMultiplier
self.leftDirectionalPad.position.y = self.size.height*directionalPadYPosition
self.leftDirectionalPad.size.width = self.leftDirectionalPad.size.width/directionalPadSizeReductionMultiple
self.leftDirectionalPad.size.height = self.leftDirectionalPad.size.height/directionalPadSizeReductionMultiple
self.leftDirectionalPad.name = "leftDirectionalPad"
self.leftDirectionalPad.alpha = directionalPadAlphaValue
self.leftDirectionalPad.zPosition = 1
self.addChild(leftDirectionalPad)
self.leftDirectionalPad.userInteractionEnabled = true
// right
self.rightDirectionalPad.position.x = self.leftDirectionalPad.position.x*directionalPadSpacingMultiple
self.rightDirectionalPad.position.y = self.size.height*directionalPadYPosition
self.rightDirectionalPad.size.width = self.rightDirectionalPad.size.width/directionalPadSizeReductionMultiple
self.rightDirectionalPad.size.height = self.rightDirectionalPad.size.height/directionalPadSizeReductionMultiple
self.rightDirectionalPad.name = "rightDirectionalPad"
self.rightDirectionalPad.alpha = directionalPadAlphaValue
self.rightDirectionalPad.zPosition = 1
self.addChild(rightDirectionalPad)
self.rightDirectionalPad.userInteractionEnabled = true
}
I clearly set userInteractionEnabled for each SKSpriteNode to true. Then, in touches began I wrote...
override func touchesBegan(let touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
var touch = touches.first! as UITouch
var location = touch.locationInView(self.view)
var node = nodeAtPoint(location)
print("Touched")
}
Note: I have also tried var location = touch.locationInNode(self) but that doesnt work either.
I then run the app (either on my xCode Simulator or iPhone 6). If I touch on the SKNodes, nothing happens. Nothing is printed to the console. However, if I touch anywhere else on the screen, I get "touched" printed to the screen.
What am I doing wrong? I want to detect the touch on the pads so I can move the player sprite accordingly. It might be something really stupid I'm forgetting to do. Thanks for your time and patience. Much appreciated.
Figured it out. So apparently self.leftDirectionalPad.userInteractionEnabled = true does not work. It needs to be self.leftDirectionalPad.userInteractionEnabled = false, which is very counter-intuitive. I don't get it but it works now. touchesBegan responds to when the user touches the SKSpriteNode.
let touch = touches.first! as UITouch
let location = touch.locationInNode(self)
let node = nodeAtPoint(location)
if(node.name == leftDirectionalPad.name)
{
print("left")
}
else if (node.name == rightDirectionalPad.name)
{
print("right")
}
So I am having an issue with Swift Sprite-kit. Contact is not being registered. This has something to do with my code for moving a row of objects. I have code in the touchesBegan method that finds the user's touch location, and then a block of code in the touchesMoved method that then recognises a drag on the screen and moves the row correspondingly. I know that the touchesMoved function works because the row moves when the user drags the screen.
Here is the code for my touchesBegan method:
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
if gameOver == 0 {
var touch = touches.first as! UITouch
var touchLocation = touch.locationInNode(self)
if let body = physicsWorld.bodyAtPoint(touchLocation) {
if body.node == self {
//if touchLocation == blueBox.position {
isFingerOnScreen = true
}
}
And this is my code for the touchesMoved
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
// 1. Check whether user touched the screen
if isFingerOnScreen == true {
// 2. Get touch location
var touch = touches.first as! UITouch
var touchLocation = touch.locationInNode(self)
var previousLocation = touch.previousLocationInNode(self)
// 4. Calculate new position along x for objects
var blueBoxX = blueBox.position.x + (touchLocation.x - previousLocation.x)
var greenBoxX = greenBox.position.x + (touchLocation.x - previousLocation.x)
var redBoxX = redBox.position.x + (touchLocation.x - previousLocation.x)
var yellowBoxX = yellowBox.position.x + (touchLocation.x - previousLocation.x)
// 5. Limit x so that the objects won't leave screen to left or right (this code does not actually work for me)
/*
blueBoxX = max(blueBoxX, blueBox.size.width/2)
blueBoxX = min(blueBoxX, size.width - blueBox.size.width/2)
greenBoxX = max(greenBoxX, greenBox.size.width/2)
greenBoxX = min(greenBoxX, size.width - greenBox.size.width/2)
redBoxX = max(redBoxX, redBox.size.width/2)
redBoxX = min(redBoxX, size.width - redBox.size.width/2)
yellowBoxX = max(yellowBoxX, yellowBox.size.width/2)
yellowBoxX = min(yellowBoxX, size.width - yellowBox.size.width/2)
*/
// 6. Update object position
blueBox.position = CGPointMake(blueBoxX, blueBox.position.y)
blueBox.zPosition = 10
greenBox.position = CGPointMake(greenBoxX, greenBox.position.y)
greenBox.zPosition = 10
greenBox.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(greenBox.size.width, greenBox.size.height * 1/100))
greenBox.physicsBody!.dynamic = false
greenBox.physicsBody!.categoryBitMask = greenColourGroup
redBox.position = CGPointMake(redBoxX, redBox.position.y)
redBox.zPosition = 10
yellowBox.position = CGPointMake(yellowBoxX, yellowBox.position.y)
yellowBox.zPosition = 10
}
Now this is all good so far but my issue is that when this code is active, it for some reason stops the app from recognising contact between a ball and an object. Whereas when the code is commented out, the contact is recognised and the objects match. This makes no sense to me because as far as I can tell the only thing I am changing with the greenBox object (the only object I am testing with) is the position of the object in relation to the touchLocation.
My code for the contact is as follows:
func didBeginContact(contact: SKPhysicsContact) {
let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
switch contactMask {
case greenColourGroup | ballColourGroup:
if contact.bodyA.categoryBitMask == greenColourGroup || contact.bodyB.categoryBitMask == greenColourGroup {
if ballColourGroup == greenColourGroup {
score++
scoreLabel.text = "\(score)"
ball.removeFromParent()
makeBall()
I am quite new to coding and am really struggling with this issue, so please help and if it involves code please include the necessary code needed to fix this issue.
Thanks
P.S: Just to confirm, the didBeginContact method works perfectly when the code for moving the objects is commented out, so I know that this code is ok. The issue is that the code within the touchesMoved method is stopping it from working
I am using the iOS SpriteKit Game Swift template on iOS8.3. I am trying to use the function func intersectsNode(_ node: SKNode) -> Bool to detect overlap of two circles created as SKShapeNodes. Turns out the function does not detect the intersection if its SKShapeNodes. But on further troubleshooting, it turns out the function works if I use the default Spaceship sprite of the template. Here is the code which works:
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)
let sprite = SKSpriteNode(imageNamed:"Spaceship")
sprite.xScale = 0.3
sprite.yScale = 0.3
sprite.position = location
self.circles.append(sprite)
self.addChild(sprite)
if circles.count == 1 {
println("One circle")
} else {
for var index = 0; index < circles.count-1; ++index {
if sprite.intersectsNode(circles[index]) {
println(circles[index].frame)
println("Circle intersects another")
}
}
}
}
}
When two sprites overlap in the above code the function returns YES and prints the intersection string. Here is the code which does NOT work:
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)
let sprite = SKShapeNode(circleOfRadius: 50)
sprite.position = location
self.circles.append(sprite)
self.addChild(sprite)
if circles.count == 1 {
println("One circle")
} else {
for var index = 0; index < circles.count-1; ++index {
if sprite.intersectsNode(circles[index]) {
println(circles[index].frame)
println("Circle intersects another")
}
}
}
}
}
As you can see the code blocks are completely identical except in one case its an SKSpriteNode and the other case its SKShapeNode. I also printed the frames of the SKShapeNode Circles and I can see they have have valid frames. So I am puzzled by this as I would like to use SKShapeNodes in my code for now but I cannot use the intersectNode function as it does not work.
The documentation for intersectsNode says this:
The two nodes are considered to intersect if their frames intersect. The children of both nodes are ignored in this test.
Which means you won't get the result you want when using circles.
However, checking if two circles overlap is as easy as checking if the distance between their centers is less than the sum of their radiuses.