Create Button in SpriteKit: Swift - ios

I want to create a button in SpriteKit or in an SKScene that sends the view to another view controller.
I tried using the "performSegue with identifier ", however apparently an SKScene doesn't support this.
How would I create a button that sends the view to another view with SpriteKit?
This is the code that I've tried using to perform this action.
The line with "HomeButton.prepareForSegueWithIdentifier()" is just an example. It won't actually let me add the "prepareForSegue" part, it doesn't support it <--- What I mean by that is when I go to add it, it is unrecognized.
class GameOverScene: SKScene {
var HomeButton: SKNode! = nil
init(size: CGSize, won: Bool) {
super.init(size: size)
backgroundColor = SKColor.whiteColor()
HomeButton = SKSpriteNode(color: SKColor.blueColor(), size: CGSize(width: 100, height: 100))
HomeButton.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
HomeButton.userInteractionEnabled = true
self.addChild(HomeButton)
let message = won ? "You Won!" : "You Lose!"
let label = SKLabelNode(fontNamed: "Title 1")
label.text = message
label.fontSize = 40
label.fontColor = SKColor.blackColor()
label.position = CGPoint(x: size.width/2, y: size.height/2)
addChild(label)
runAction(SKAction.sequence([SKAction.waitForDuration(3.0), SKAction.runBlock() {
let reveal = SKTransition.flipHorizontalWithDuration(0.5)
let scene = GameScene(size: size)
self.view?.presentScene(scene, transition: reveal)
}
]))
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if HomeButton.containsPoint(location) {
HomeButton.prepareForSegueWithIdentifier()
}
}
}
Note: I've tried using a button, but they don't work in and SKScene.
I'll be on to respond if there is any confusion.

I have translated Alessandro Ornano’s answer to Swift 3.1:
import SpriteKit
class FTButtonNode: SKSpriteNode {
enum FTButtonActionType: Int {
case TouchUpInside = 1,
TouchDown, TouchUp
}
var isEnabled: Bool = true {
didSet {
if (disabledTexture != nil) {
texture = isEnabled ? defaultTexture : disabledTexture
}
}
}
var isSelected: Bool = false {
didSet {
texture = isSelected ? selectedTexture : defaultTexture
}
}
var defaultTexture: SKTexture
var selectedTexture: SKTexture
var label: SKLabelNode
required init(coder: NSCoder) {
fatalError("NSCoding not supported")
}
init(normalTexture defaultTexture: SKTexture!, selectedTexture:SKTexture!, disabledTexture: SKTexture?) {
self.defaultTexture = defaultTexture
self.selectedTexture = selectedTexture
self.disabledTexture = disabledTexture
self.label = SKLabelNode(fontNamed: "Helvetica");
super.init(texture: defaultTexture, color: UIColor.white, size: defaultTexture.size())
isUserInteractionEnabled = true
//Creating and adding a blank label, centered on the button
self.label.verticalAlignmentMode = SKLabelVerticalAlignmentMode.center;
self.label.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.center;
addChild(self.label)
// Adding this node as an empty layer. Without it the touch functions are not being called
// The reason for this is unknown when this was implemented...?
let bugFixLayerNode = SKSpriteNode(texture: nil, color: UIColor.clear, size: defaultTexture.size())
bugFixLayerNode.position = self.position
addChild(bugFixLayerNode)
}
/**
* Taking a target object and adding an action that is triggered by a button event.
*/
func setButtonAction(target: AnyObject, triggerEvent event:FTButtonActionType, action:Selector) {
switch (event) {
case .TouchUpInside:
targetTouchUpInside = target
actionTouchUpInside = action
case .TouchDown:
targetTouchDown = target
actionTouchDown = action
case .TouchUp:
targetTouchUp = target
actionTouchUp = action
}
}
/*
New function for setting text. Calling function multiple times does
not create a ton of new labels, just updates existing label.
You can set the title, font type and font size with this function
*/
func setButtonLabel(title: NSString, font: String, fontSize: CGFloat) {
self.label.text = title as String
self.label.fontSize = fontSize
self.label.fontName = font
}
var disabledTexture: SKTexture?
var actionTouchUpInside: Selector?
var actionTouchUp: Selector?
var actionTouchDown: Selector?
weak var targetTouchUpInside: AnyObject?
weak var targetTouchUp: AnyObject?
weak var targetTouchDown: AnyObject?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if (!isEnabled) {
return
}
isSelected = true
if (targetTouchDown != nil && targetTouchDown!.responds(to: actionTouchDown)) {
UIApplication.shared.sendAction(actionTouchDown!, to: targetTouchDown, from: self, for: nil)
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if (!isEnabled) {
return
}
let touch: AnyObject! = touches.first
let touchLocation = touch.location(in: parent!)
if (frame.contains(touchLocation)) {
isSelected = true
} else {
isSelected = false
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if (!isEnabled) {
return
}
isSelected = false
if (targetTouchUpInside != nil && targetTouchUpInside!.responds(to: actionTouchUpInside!)) {
let touch: AnyObject! = touches.first
let touchLocation = touch.location(in: parent!)
if (frame.contains(touchLocation) ) {
UIApplication.shared.sendAction(actionTouchUpInside!, to: targetTouchUpInside, from: self, for: nil)
}
}
if (targetTouchUp != nil && targetTouchUp!.responds(to: actionTouchUp!)) {
UIApplication.shared.sendAction(actionTouchUp!, to: targetTouchUp, from: self, for: nil)
}
}
}
Usage:
#objc func buttonTap() {
print("Button pressed")
}
override func didMove(to view: SKView)
{
backgroundColor = SKColor.white
let buttonTexture: SKTexture! = SKTexture(imageNamed: "button")
let buttonTextureSelected: SKTexture! = SKTexture(imageNamed: "buttonSelected.png")
let button = FTButtonNode(normalTexture: buttonTexture, selectedTexture: buttonTextureSelected, disabledTexture: buttonTexture)
button.setButtonAction(target: self, triggerEvent: .TouchUpInside, action: #selector(GameScene.buttonTap))
button.setButtonLabel(title: "Button", font: "Arial", fontSize: 12)
button.position = CGPoint(x: self.frame.midX,y: self.frame.midY)
button.zPosition = 1
button.name = "Button"
self.addChild(button)
}
I have created two .png:

If you need to create a button in SpriteKit, I think this button must have all or some of the available actions to do whatever you want (exactly as UIButton did)
Here you can find a simple class that build a SpriteKit button, called FTButtonNode:
class FTButtonNode: SKSpriteNode {
enum FTButtonActionType: Int {
case TouchUpInside = 1,
TouchDown, TouchUp
}
var isEnabled: Bool = true {
didSet {
if (disabledTexture != nil) {
texture = isEnabled ? defaultTexture : disabledTexture
}
}
}
var isSelected: Bool = false {
didSet {
texture = isSelected ? selectedTexture : defaultTexture
}
}
var defaultTexture: SKTexture
var selectedTexture: SKTexture
var label: SKLabelNode
required init(coder: NSCoder) {
fatalError("NSCoding not supported")
}
init(normalTexture defaultTexture: SKTexture!, selectedTexture:SKTexture!, disabledTexture: SKTexture?) {
self.defaultTexture = defaultTexture
self.selectedTexture = selectedTexture
self.disabledTexture = disabledTexture
self.label = SKLabelNode(fontNamed: "Helvetica");
super.init(texture: defaultTexture, color: UIColor.whiteColor(), size: defaultTexture.size())
userInteractionEnabled = true
//Creating and adding a blank label, centered on the button
self.label.verticalAlignmentMode = SKLabelVerticalAlignmentMode.Center;
self.label.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Center;
addChild(self.label)
// Adding this node as an empty layer. Without it the touch functions are not being called
// The reason for this is unknown when this was implemented...?
let bugFixLayerNode = SKSpriteNode(texture: nil, color: UIColor.clearColor(), size: defaultTexture.size())
bugFixLayerNode.position = self.position
addChild(bugFixLayerNode)
}
/**
* Taking a target object and adding an action that is triggered by a button event.
*/
func setButtonAction(target: AnyObject, triggerEvent event:FTButtonActionType, action:Selector) {
switch (event) {
case .TouchUpInside:
targetTouchUpInside = target
actionTouchUpInside = action
case .TouchDown:
targetTouchDown = target
actionTouchDown = action
case .TouchUp:
targetTouchUp = target
actionTouchUp = action
}
}
/*
New function for setting text. Calling function multiple times does
not create a ton of new labels, just updates existing label.
You can set the title, font type and font size with this function
*/
func setButtonLabel(title: NSString, font: String, fontSize: CGFloat) {
self.label.text = title as String
self.label.fontSize = fontSize
self.label.fontName = font
}
var disabledTexture: SKTexture?
var actionTouchUpInside: Selector?
var actionTouchUp: Selector?
var actionTouchDown: Selector?
weak var targetTouchUpInside: AnyObject?
weak var targetTouchUp: AnyObject?
weak var targetTouchDown: AnyObject?
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if (!isEnabled) {
return
}
isSelected = true
if (targetTouchDown != nil && targetTouchDown!.respondsToSelector(actionTouchDown!)) {
UIApplication.sharedApplication().sendAction(actionTouchDown!, to: targetTouchDown, from: self, forEvent: nil)
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
if (!isEnabled) {
return
}
let touch: AnyObject! = touches.first
let touchLocation = touch.locationInNode(parent!)
if (CGRectContainsPoint(frame, touchLocation)) {
isSelected = true
} else {
isSelected = false
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
if (!isEnabled) {
return
}
isSelected = false
if (targetTouchUpInside != nil && targetTouchUpInside!.respondsToSelector(actionTouchUpInside!)) {
let touch: AnyObject! = touches.first
let touchLocation = touch.locationInNode(parent!)
if (CGRectContainsPoint(frame, touchLocation) ) {
UIApplication.sharedApplication().sendAction(actionTouchUpInside!, to: targetTouchUpInside, from: self, forEvent: nil)
}
}
if (targetTouchUp != nil && targetTouchUp!.respondsToSelector(actionTouchUp!)) {
UIApplication.sharedApplication().sendAction(actionTouchUp!, to: targetTouchUp, from: self, forEvent: nil)
}
}
}
The source is available in this Gist
Usage:
let backTexture: SKTexture! = SKTexture(image:"backBtn.png")
let backTextureSelected: SKTexture! = SKTexture(image:"backSelBtn.png")
let backBtn = FTButtonNode(normalTexture: backTexture, selectedTexture: backTextureSelected, disabledTexture: backTexture,size:backTexture.size())
backBtn.setButtonAction(self, triggerEvent: .TouchUpInside, action: #selector(GameScene.backBtnTap))
backBtn.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame))
backBtn.zPosition = 1
backBtn.name = "backBtn"
self.addChild(backBtn)
func backBtnTap() {
print("backBtnTap tapped")
// Here for example you can do:
let transition = SKTransition.fadeWithDuration(0.5)
let nextScene = MenuScene(size: self.scene!.size)
nextScene.scaleMode = .ResizeFill
self.scene?.view?.presentScene(nextScene, transition: transition)
}

The simplest solution, but possibly not of the greatest quality, is to use a SpriteNode containing an image and name it. Later, using that scene you can easily program it to transfer the user to the next scene when tapped:
class GameScene: SKScene {
let button = SKSpriteNode(imageNamed: "yourImgName")
override func didMoveToView(view: SKView) {
button.name = "btn"
button.size.height = 100
button.size.width = 100
button.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) + 50)
self.addChild(button)
//Adjust button properties (above) as needed
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first
let positionInScene = touch!.locationInNode(self)
let touchedNode = self.nodeAtPoint(positionInScene)
if let name = touchedNode.name {
if name == "btn" {
let yourNextScene = YourNextScene(fileNamed: "YourNextScene")
self.view?.presentScene(yourNextScene!)
}
}
}
}
Don't forget to replace "YourNextScene" with the actual name of your next scene.

Related

SKScene nodes not detecting touch

I am trying to make an ARKit app for ios and the nodes in the scene are not responding to touch. The scene is properly displayed but I haven't been able to detect any touch.
fileNamed: "TestScene" refers to a TestScene.sks file in my project which is empty and I add the node in the code as shown below.
let detailPlane = SCNPlane(width: xOffset, height: xOffset * 1.4)
let testScene = SKScene(fileNamed: "TestScene")
testScene?.isUserInteractionEnabled = true
let winner = TouchableNode(fontNamed: "Chalkduster")
winner.text = "You Win!"
winner.fontSize = 65
winner.fontColor = SKColor.green
winner.position = CGPoint(x: 0, y: 0)
testScene?.addChild(winner)
let material = SCNMaterial()
material.diffuse.contents = testScene
material.diffuse.contentsTransform = SCNMatrix4Translate(SCNMatrix4MakeScale(1, -1, 1), 0, 1, 0)
detailPlane.materials = [material]
let node = SCNNode(geometry: detailPlane)
rootNode.addChildNode(node)
For TouchableNode I have the following class
class TouchableNode : SKLabelNode {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("Touch detected")
}
}
I've achieved this affect using gesture recognize
private func registerGestureRecognizers() -> Void {
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
sceneView.addGestureRecognizer(tapGestureRecognizer)
}
then have a function to handle the tap gesture
#objc private func handleTap(sender: UITapGestureRecognizer) -> Void {
let sceneViewTappedOn = sender.view as! SCNView
let touchCoordinates = sender.location(in: sceneViewTappedOn)
let hitTest = sceneViewTappedOn.hitTest(touchCoordinates)
if !hitTest.isEmpty {
let hitResults = hitTest.first!
var hitNode = hitResults.node
// do something with the node that has been tapped
}
}
}
You need to do isUserInteractionEnabled = true first.
So, something like:
class TouchableNode : SKLabelNode {
override init() {
super.init()
isUserInteractionEnabled = true
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
isUserInteractionEnabled = true
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("Touch detected")
}
}

How to drag certain image in iOS?

Wanted to know how I can drag a image across screen and what code would be used. Tried looking up but only older versions of Swift have answer and no longer work. I want to drag the image, but not place finger on screen and it goes to that spot. Just drag.
Gives me the error:
"Use of undeclared type 'uitouch'"
import UIKit
class DraggableImage: UIImageView {
override func touchesMoved(touches: Set<uitouch>, withEvent event: UIEvent?) {
if let touch = touches.first {
let position = touch.locationInView(superview)
center = CGPointMake(position.x, position.y)
}
}
}
You need to subclass UIImageView and in the init you need to set userInteractionEnabled = true and then override this method override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) well, my code is this:
class DraggableImage: UIImageView {
var localTouchPosition : CGPoint?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.layer.borderWidth = 1
self.layer.borderColor = UIColor.red.cgColor
self.isUserInteractionEnabled = true
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
self.localTouchPosition = touch?.preciseLocation(in: self)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesMoved(touches, with: event)
let touch = touches.first
guard let location = touch?.location(in: self.superview), let localTouchPosition = self.localTouchPosition else{
return
}
self.frame.origin = CGPoint(x: location.x - localTouchPosition.x, y: location.y - localTouchPosition.y)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
self.localTouchPosition = nil
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func drawRect(rect: CGRect) {
// Drawing code
}
*/
}
This is how it looks
Hope this helps
Create a Nsobject Class for moving View and add following Code
import UIKit
class objectClass: UIImageView, UIGestureRecognizerDelegate {
/*
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
// Drawing code
}
*/
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch: UITouch = touches.first!
self.center = touch.location(in: self.superview)
}
}
in mainViewController make a object of NSobject class
var newView: objectClass = objectClass()
on button Action to add new View
#IBAction func objectAdded(theButton: UIButton!) {
let frame = CGRect(x: 100, y: 100, width: 44, height: 44)
newView = objectClass(frame: frame)
if theButton.titleLabel?.text == "image1" {
newView.image = UIImage(named: "1")
} else if theButton.titleLabel?.text == "image2" {
newView.image = UIImage(named: "2")
}else{
newView.image = UIImage(named: "3")
}
newView.contentMode = .scaleAspectFill
newView.isUserInteractionEnabled = true
self.view .addSubview(newView)
newView.alpha = 0
UIView .animate(withDuration: 0.4) {
self.newView.alpha = 1
}
UIView.animate(withDuration: 0.6, delay: 0, options: .curveEaseOut, animations: { () -> Void in
self.sliderViewBottomLayoutConstraint.constant = self.sliderViewBottomLayoutConstraint.constant - self.sliderViewBottomLayoutConstraint.constant
self.view.layoutIfNeeded()
}, completion: nil)
image1Button.isEnabled = false
image2Button.isEnabled = false
image3Button.isEnabled = false
let pinchGesture: UIPinchGestureRecognizer = UIPinchGestureRecognizer(target: self, action: #selector(ViewController.recognizePinchGesture(sender:)))
pinchGesture.delegate = self
let rotateGesture: UIRotationGestureRecognizer = UIRotationGestureRecognizer(target: self, action: #selector(ViewController.recognizeRotateGesture(sender:)))
let tapGesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.RemoveSelectedImageOnTap(sender:)))
tapGesture.numberOfTapsRequired = 2
self.newView.addGestureRecognizer(tapGesture)
self.newView.addGestureRecognizer(pinchGesture)
self.newView.addGestureRecognizer(rotateGesture)
}
func recognizePinchGesture(sender: UIPinchGestureRecognizer) {
sender.view!.transform = sender.view!.transform.scaledBy(x: sender.scale, y: sender.scale)
sender.scale = 1
}
func recognizeRotateGesture(sender: UIRotationGestureRecognizer) {
sender.view!.transform = sender.view!.transform.rotated(by: sender.rotation)
sender.rotation = 0
}

ContactBitMask indicates that my objects collide, but they didn't

I was coding this game, and the game is over when the pig and fish collide. But when I play it, the pig didn't touch the fish but the game automatically overs. How do i fix that? The method related are did began and eaten etc.
import SpriteKit
import GameplayKit
var totalTime = 0
class GameScene: SKScene,SKPhysicsContactDelegate {
private var label : SKLabelNode?
var flyingPig:SKSpriteNode!
var water = SKSpriteNode()
var scoreLabel :SKLabelNode!
var currentGameState = gameState.atGame
struct PhysicsCategories{
static let None :UInt32 = 0
static let pig : UInt32 = 0b1
static let aFish : UInt32 = 0b100
}
var timer : Timer!
var timing : Timer!
var fish = ["nemo","bluedy","lantern","balloon","Knife"]
var myTime = 0
var lives:[SKSpriteNode]!
override func didMove(to view: SKView) {
totalTime = 0
self.physicsWorld.contactDelegate = self
water = SKSpriteNode(imageNamed: "water")
water.position = CGPoint(x: self.size.width/2,y:self.size.height/2)
water.physicsBody = SKPhysicsBody(rectangleOf: water.size)
water.physicsBody?.affectedByGravity = false
water.physicsBody?.isDynamic = false
self.addChild(water)
flyingPig = SKSpriteNode(imageNamed:"FlyingPig")
flyingPig.position = CGPoint(x:self.size.width/2,y:self.size.height/2)
flyingPig.physicsBody = SKPhysicsBody(rectangleOf: flyingPig.size)
flyingPig.physicsBody!.affectedByGravity=false
flyingPig.physicsBody!.collisionBitMask = PhysicsCategories.None
flyingPig.physicsBody!.categoryBitMask = PhysicsCategories.pig
flyingPig.physicsBody!.contactTestBitMask = PhysicsCategories.aFish
self.addChild(flyingPig)
self.physicsWorld.gravity = CGVector(dx:0,dy:0)
self.physicsWorld.contactDelegate = self
scoreLabel = SKLabelNode(text:"Score: 0")
scoreLabel.position = CGPoint(x:85,y:1270)
scoreLabel.fontName = "PartyLetPlain"
scoreLabel.fontSize = 44
scoreLabel.text = "Score: \(totalTime) km"
self.addChild(scoreLabel)
timer = Timer.scheduledTimer(timeInterval:1.25 ,target:self,selector:#selector(addFish),userInfo:nil,repeats:true)
timing = Timer.scheduledTimer(timeInterval: 1.5, target: self, selector: #selector(tick), userInfo: nil, repeats: true)
addLives()
}
func addLives()
{
lives = [SKSpriteNode()]
for live in 1...3{
let liveNode = SKSpriteNode(imageNamed:"FlyingPig2")
liveNode.position = CGPoint(x:750-CGFloat(4-live)*liveNode.size.width,y:1270)
self.addChild(liveNode)
lives.append(liveNode)
}
}
func addFish()
{
fish = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: fish) as![String]
let aFish = SKSpriteNode(imageNamed: fish[0])
let fishPosition = GKRandomDistribution(lowestValue:0, highestValue:700)
let position = CGFloat(fishPosition.nextInt())
aFish.position=CGPoint(x:position,y:1200)
aFish.physicsBody = SKPhysicsBody(rectangleOf: aFish.size)
aFish.physicsBody!.affectedByGravity = false
aFish.physicsBody?.isDynamic=false
aFish.physicsBody!.categoryBitMask = PhysicsCategories.aFish
aFish.physicsBody!.collisionBitMask = PhysicsCategories.None
aFish.physicsBody!.contactTestBitMask = PhysicsCategories.pig
self.addChild(aFish)
let animationDuration:TimeInterval = 12
var actionArray = [SKAction]()
actionArray.append(SKAction.move(to:CGPoint(x:position,y:-800),duration:animationDuration))
aFish.run(SKAction.sequence(actionArray))
}
func didBegin(_ contact: SKPhysicsContact) {
var body1 = SKPhysicsBody()
var body2 = SKPhysicsBody()
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask{
body1 = contact.bodyA
body2 = contact.bodyB
}
else{
body1 = contact.bodyB
body2 = contact.bodyA
}
if body1.categoryBitMask == PhysicsCategories.pig && body2.categoryBitMask==PhysicsCategories.aFish
{
body2.node?.removeFromParent()
gameOver()
}
}
enum gameState{
case before
case atGame
case after
}
func gameOver(){
self.removeAllActions()
currentGameState=gameState.after
let changeSceneAction = SKAction.run(changeScene)
let waitToChangeScene = SKAction.wait(forDuration:0.1)
let changeSceneSequence = SKAction.sequence([waitToChangeScene,changeSceneAction])
self.run(changeSceneSequence)
}
func changeScene(){
let newScene = GameOverScene(size:self.size)
newScene.scaleMode = self.scaleMode
let transition = SKTransition.fade(withDuration: 0.1)
self.view!.presentScene(newScene,transition:transition )
}
func touchDown(atPoint pos : CGPoint) {
}
func touchMoved(toPoint pos : CGPoint) {
}
func touchUp(atPoint pos : CGPoint) {
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in (touches ){
let location = touch.location(in: self)
if self.flyingPig.contains(location){
flyingPig.position = location
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in (touches ){
let location = touch.location(in: self)
if flyingPig.contains(location){
flyingPig.position = location
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
func tick()
{
totalTime+=1
}
}
body1.categoryBitMask == PhysicsCategories.pig && body2.categoryBitMask==PhysicsCategories.aFish
change to this
let contactMask = bodyA.contact.categoryBitMask || bodyB.contact.categoryBitMask
switch contactMask
case PhysicsCategories.pig || PhysicsCategories.aFish :
// code
default:
break

Swift 2.2: Recording swipe from one UIButton to another works slowly

I have an UIImageView on a storyboard and through the .swift file, I have added several UIButton as subviews into this UIImageView.
What I want to do is, when I swipe from one of these UIButton to another UIButton, the software should record which one it is when I put my finger on the screen, and which one it is when I lift it up.
Everything works correctly. Except, I must do it slowly (ie touch down, and pause before moving my finger, then swipe to the other view, and then pause slightly before touching up). If I naturally do the swipe, it does not trigger the subview.
I do have a line drawn that traces my movement, and I can confirm I am hitting on the SubView.
Any advice for this?
Function for the touchdown event:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
// Swipe trace
stSwiped = false
if let touch = touches.first as UITouch! {
stLastPoint = touch.locationInView(swipeTraceDisplay)
}
let touch = touches.first
let location: CGPoint = (touch?.locationInView(self.view))!
let buttons: [UIButton] = mapDisplay.subviews as! [UIButton]
for button in buttons {
if button.pointInside(self.view.convertPoint(location, toView: button.viewForBaselineLayout()), withEvent: nil) {
button.backgroundColor = UIColor.redColor()
selectedOriginUIButtion = button
selectedOrigin = arrayMLegs[button.tag - tagOffset]
hasSelectedOrigin = true
}
}
}
Function for the move event (this is irrelevant, but I'll put it on anyway):
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
stSwiped = true
if let touch = touches.first as UITouch! {
let currentPoint = touch.locationInView(swipeTraceDisplay)
drawLineFrom(stLastPoint, toPoint: currentPoint)
stLastPoint = currentPoint
}
}
Function for the touch up event:
override func touchesEnded(touches: Set, withEvent event: UIEvent?) {
if (!stSwiped) {
drawLineFrom(stLastPoint, toPoint: stLastPoint)
}
UIView.animateWithDuration(0.6, delay: 0, options: .CurveEaseIn, animations: {
self.swipeTraceDisplay.alpha = 0
}, completion: { finished in
self.swipeTraceDisplay.image = nil
})
let touch = touches.first
let location: CGPoint = (touch?.locationInView(self.view))!
let buttons: [UIButton] = mapDisplay.subviews as! [UIButton]
if (!hasSelectedOrigin) {
return
}
for button in buttons {
if button.pointInside(self.view.convertPoint(location, toView: button.viewForBaselineLayout()), withEvent: nil) {
button.backgroundColor = UIColor.redColor()
selectedDestination = arrayMLegs[button.tag - tagOffset]
UIView.animateWithDuration(1) {
button.backgroundColor = UIColor.whiteColor()
self.selectedOriginUIButtion.backgroundColor = UIColor.whiteColor()
}
makeEntry(selectedOrigin, destination: selectedDestination)
hasSelectedOrigin = false
return
}
}
selectedOriginUIButtion.backgroundColor = UIColor.whiteColor()
hasSelectedOrigin = false
}
Function for creating a button:
func makeButton(label: String, posX: Int, posY: Int) {
let pposX = CGFloat(posX) * 0.01
let pposY = CGFloat(posY) * 0.01
let button = UIButton(type: .Custom)
button.frame = CGRectMake(pposX * imageWidth, pposY * imageHeight, 44, 44)
button.setTitle(label, forState: UIControlState.Normal)
button.setTitleColor(UIColor.blackColor(), forState: UIControlState.Normal)
button.layer.cornerRadius = 0.5 * button.bounds.size.width
button.layer.borderColor = UIColor.redColor().CGColor
button.backgroundColor = UIColor.whiteColor()
button.layer.borderWidth = 4
button.userInteractionEnabled = false
mapDisplay.addSubview(button)
}
Make the button's hit area larger:
extension UIButton {
override public func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
let relativeFrame = self.bounds
let hitTestEdgeInsets = UIEdgeInsetsMake(-20, -20, -20, -20)
let hitFrame = UIEdgeInsetsInsetRect(relativeFrame, hitTestEdgeInsets)
return CGRectContainsPoint(hitFrame, point)
}
}
Thanks in advance!

SpriteKit - Error while creating a button

here is my custom button class:
import SpriteKit
class Button: SKNode {
var defaultButton: SKSpriteNode
var activeButton: SKSpriteNode
var action: () -> Void
init(defaultImage: String, activeImage: String, buttonAction: () -> Void) {
defaultButton = SKSpriteNode(imageNamed: defaultImage)
activeButton = SKSpriteNode(imageNamed: activeImage)
action = buttonAction
activeButton.hidden = true
super.init()
userInteractionEnabled = true
addChild(defaultButton)
addChild(activeButton)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches {
let location = touch.locationInNode(self)
activeButton.hidden = false
defaultButton.hidden = true
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches {
let location = touch.locationInNode(self)
if defaultButton.containsPoint(location) {
action()
}
activeButton.hidden = true
defaultButton.hidden = false
}
}
Here is how I'm initializing it in GameScene:
var button = Button(defaultImage: "default_Image", activeImage: "active_Image", buttonAction: someFunction)
button.position = CGPoint(x: size.width / 2, y: size.height / 2)
addChild(Button) // <- Error here !
The error I get: "Cannot convert value of type '(Button).Type' (aka 'Button.Type') to expected argument type 'SKNode'"
What am I doing wrong ?

Resources