I am developing a game using Sprite and the game works perfectly fine. I am trying to add in a feature that allows you to change things on that GameView. But the buttons for the feature are on a different ViewController. How would I be able to have the code be implemented into a different view controller?
This is the code i want the button to implement
for touch: AnyObject in touches {
// Get the location of the touch in this scene
let location = touch.location(in: self)
// Check if the location of the touch is within the button's bounds
if button.contains(location) {
Ghost.texture = SKTexture(imageNamed:"Ghost2")
}
}
And here is the button
#IBAction func button(_ sender: AnyObject) {
}
But the button is on ViewController1 and the object that i want to change is on ViewController2 (GemScene)
Take a look to this question:
Passing Data between View Controllers (One of the answers shows Swift 3 syntax.)
Anyway, what I personally have done in these cases is to use NotificationCenter, which provides loosely coupled messages even between different ViewControllers. You can take a look here: NSNotifications in Swift 3
Related
I'm writing an app for Apple Watch using SpriteKit, so I don't have access to functions like touchesBegan and I have to use a WKTapGestureRecognizer to detect taps, no big deal, but I have issues detecting taps on a node.
In my InterfaceController I have:
#IBAction func handleTap(tapGestureRecognizer: WKTapGestureRecognizer){
scene?.didTap(tapGesture: tapGestureRecognizer)
}
And in my Scene file I have
func didTap(tapGesture:WKTapGestureRecognizer) {
let position = tapGesture.locationInObject()
let hitNodes = self.nodes(at: position)
if hitNodes.contains(labelNode) {
labelNode.text = "tapped!"
}
Problem is the Tap Gesture Recognizer gives me the absolute coordinates of the touch point (for example 11.0, 5,0) while my node is positioned relatively to the center of the screen (so its position is -0.99,-11.29 even though is at the center of the screen) therefore the tap is hitting the node not when actually tapping it, but when I tap on the top left of the screen. I searched everywhere and it looks like this is the way to do it yet I don't find people having the same issues. The node has been added via the editor. What am I doing wrong?
So you have the right idea. You are getting this wrong because hitNodes is an array of SKNodes. Those are newly created. So when you use hitNodes.contains the addresses of the labelNode and the address of the newly created SKNode that is being compared would be completely different. Therefore it would never be tapped.
Here's what I would do. This would be in my Scene File. Your InterfaceController class is correct.
func didTap(tapGesture:WKTapGestureRecognizer) {
let position = tapGesture.locationInObject()
if labelNode.contains(position) {
labelNode.text = "tapped!"
}
}
OR another way would be this. I like this way because you only have one function which would be in the WKInterfaceControlller And you would need no functions in your Scene File.
#IBAction func tapOnScreenAct(_ sender: WKGestureRecognizer) {
if scene.labelNode.contains(sender.locationInObject()) {
scene.labelNode.text = "tapped!"
}
}
Either way, both should work. Let me know if you have any more questions or clarifications.
I'am new to ios. I have several view controllers and I want back button to get user to level up controller. Example.
But if user comes from gameOver view, back button sent him back to gameOver and I don't want such behavior (I want user to be sent at second level (games level) controller as shown). On android I could set the pop behavior for the navigation actions with mouse very easily.
What is the correct way to do the same in ios? Or I have to create the custom back button and do everything manually?
Using Swift this can be achieved using below code:
func popToViewController(_ specificViewController: Swift.AnyClass) {
let viewControllers = self.navigationController!.viewControllers
for eachViewController in viewControllers {
if eachViewController.isKind(of: specificViewController) {
self.navigationController!.popToViewController(eachViewController, animated: true)
break;
}
}
}
Usage:
self.popToViewController(gameLevelViewController.self)
In a couple of my projects I think I'm not created a great structure in many cases.
It could be a game where I've created a game board (think about chess) with a grid of 8 * 8 cells. Each cell has a gesture recognizer that relies on a subclass (cell.swift), with the game logic in a parent ViewController.
For arguments sake, let us say we want to display to the user which square they have touched.
I've found out how to do this from the subclassed UIView (obvs. create the alert in the subclassed UIView / cell.swift in this example)
UIApplication.shared.keyWindow?.rootViewController?.present(alertController, animated: true, completion: nil)
but it seems to break the structure of the app - but wouldn't it be the same accessing an action in the parent ViewController? What is the best way of approaching this>
Your rootViewController is the VC on the bottom of your stack. It's not a safe way to access the visible VC, and is rarely useful, in general (there are cases, but I doubt your app would find them useful).
What you likely want to use is a delegate pattern. Let's say the parent VC that displays your chess board (let's call this MyBoardViewController), conforms to a protocol like the following. MyView is whatever custom UIView class you're using for the chess squares:
protocol SquareAlertHandler {
func handleSquarePressed(sender : myView)
}
And add the following property to your MyView class:
weak var delegate : SquareAlertHandler?
And replace whatever event handler you're currently using, with the following (I'm assuming you're using a UIButton in IB to handle the press, and have arbitrarily named the outlet 'didPress:'):
#IBAction didPress(sender : UIButton) {
delegate?.handleSquarePressed(self)
}
Now, add the protocol to your MyBoardViewController, and define the method:
class MyBoardViewController : UIViewController, SquareAlertHandler {
... ... ...
func handleSquarePressed(sender : myView) {
// Do something to handle the press, here, like alert the user
}
... ... ...
}
And finally, wherever you create the MyView instances, assign the MyBoardViewController instance as the delegate, and you're good to go.
Depending on your Swift literacy, this may be confusing. Adding code, so that I can at least match up the class names, would help to clarify things.
I'm working on an iPhone app (Objective-C) which has barcode scanning functionality on many of its screens. The user can tap a control to recognize different barcodes and navigate to different screens depending on what type of barcode is recognized. The majority of the logic does not depend on which screen they initiated the scan from... As such, I don't want to duplicate the code in each view controller, but am uncertain where the best place for it is. It requires the user tapping on a detection rectangle, so it does need to be able to handle these events. Many thanks!
You could use a singleton
class DataStore {
static let sharedDataStore = DataStore()
func scanBarcode() {
//logic
}
}
calling the function in another View Controller
class viewController: UIViewController {
let shared = DataStore.sharedDataStore
override func viewDidLoad() {
//calling the function
shared.scanBarcode()
}
I have a progress bar (with its own controller). This bar is supposed to be shown in different views depending on which view is visible. As the progress will be same, If possible I don't want to create many progress bar in many views rather I want to use same instance in all these views. Also in that way when I need to change any property of the progress bar it will be reflected commonly, which is required.
Please suggest me how can I use this common view. And also if my strategy is wrong, what would be the better design for such scenarios.
1) Well you have 2 options. You can declare a new Class ViewBox (or whatever name) and then use that inside your code
First View Controller
var box:ViewBox = ViewBox()
When you segue or transition to your next screen, you can have a predefined variable var box:ViewBox!. Then say when you press a button, the button has a function called transition.
//Now setup the transition inside the Storyboard and name the identifier "toThirdViewController"
override func prepareForSegue(segue:UIStoryboardSegue, sender:AnyObject?) {
if(segue.identifier == "toThirdViewController") {
var vc = segue.destinationViewController as! `nextViewController` //The class of your next viewcontroller goes here
vc.box = self.box
}
//Since The SecondViewController doesn't need ViewBox, we don't need it there.
}
where
nextViewController:UIViewController {
var box:ViewBox!
}
Or you could do a much simpler way and that is to look up a UIPageViewController :)