XCode 4.2 and referencing external files

Discussion in 'Mac Programming' started by BlinksTale, Nov 15, 2012.

  1. BlinksTale, Nov 15, 2012
    Last edited: Nov 15, 2012

    BlinksTale macrumors newbie

    Nov 15, 2012
    Hello MacRumors! I'm finally taking the dive and trying to learn how to port my C++ game to Mac via XCode. With sfml and opengl, that hasn't been too hard - but I use a custom file type that I read in with ifstream (although I've been told I should switch to fopen eventually) and while I have it working when I click Run in XCode, the OS X App itself does not know how to read in these files. More details below, but, any thoughts?


    I am importing this project into XCode essentially, so I took a working SFML framework, added my files, swapped out the main and hit run. Amazingly, all the core stuff worked! The maps (external files in question) did not load though, and it ended up being due to the location of the working directory. Going into XCode's scheme and changing it to be the working dir I use for my old project itself, the maps began loading just fine (since all the map addresses are relative, ie "./maps/world1.map") when I clicked the Run button from inside XCode. Great! But I want to share the file with friends.

    Going into the Derived Data path, where ultimately under Derived Data/Project Folder/Build/Products/Debug I found myGame.app, a 75MB Intel App (so it appears to be sucking up all the music and sound effect files, since the example sfml project before would only make an 8MB app). Trying to run this file by double clicking though makes the project open, but no sound, music, maps, or images load (so none of the external files that were referenced in the working directory). Moving the app into the working directory does not fix this problem either.

    So far I have been unable to find a way to build the app directly into the working directory, and am only able to influence its placement by changing Derived Data in Preferences for all of XCode. So, any tips on how to get my final product seeing files the same way that the one run out of XCode sees?

    EDIT: And I was wrong! The game does not work flawlessly from XCode, only the first level (the one loaded when building the game) loads properly, every level after that fails to load. I'm guessing that's since after that point, the game is running from the dir where it was built to rather than the one it was built from.
  2. szymczyk macrumors regular

    Mar 5, 2006
    Your game's map, sound, and image files are in the app bundle's Resources folder. The app bundle looks like a single file, the application, but it contains a bunch of directories. You can examine your game's app bundle by selecting it in the Finder, right-clicking, and choosing Show Package Contents.

    To load the files you're going to have to do one of two things. First, you can try setting the game's working directory to the app bundle's Resources folder. I have not used SFML so I'm not sure if this is possible in SFML, but SDL's source code has a method to change the working directory. You'll have to look at SFML's source to see if they have a method to set the working directory.

    Second, you can use Cocoa's NSBundle class or Core Foundation's CFBundle data structures and functions to access the app bundle and load files from the bundle. Since you're using C++, I recommend CFBundle over NSBundle.
  3. BlinksTale thread starter macrumors newbie

    Nov 15, 2012
    The resources folder was exactly what I needed, and the show contents instructions helped a lot. :) The game now fully runs out of XCode! Victory!

    But the war is not won. xD Now I am trying to run the .app as a standalone, and though everything is in the resources folder, it does not load anything in the initial startup of the game. Since I am porting into XCode, I have my repo for the game, and my folders for the XCode project. If I point to the code repo as my working dir, everything works in XCode, but no luck with standalone (although everything AFTER the initial load works, so the second/third/fourth/etc levels all load). If I point the working dir to the .app's resource folder, it does not load the initial content either in XCode or as a standalone.

    I'm pretty sure it's not a problem that has to do with SFML, since loading levels (no SFML involved, just fstream or something, I forget what I've used) will not load the initial level, but loads everything after that. Even without using Cocoa or Core Foundation, the later levels load - so I'm wondering why the first doesn't (and all the music/sfx/images that I load at the same time) in the standalone only. I'm tempted to just not load anything until the Window is up and running and the user hits enter or something...

    And thanks for the help szymczyk! Much further now than I was two weeks ago because of your post, sorry for the late reply! (limited Mac access)
  4. szymczyk macrumors regular

    Mar 5, 2006
    It's not going to work standalone. If you give your game to someone to load on their Mac, they're not going to have your code repo folder so they won't be able to load any files.

    How are you setting the working dir? I noticed you asked the same question on Gamedev.net, and you manually set it to MyGame.app/Contents/Resources. This isn't safe because the user can change the name of the app. Changing the name of the app would make file loading fail. You have to write some code to change the working directory. The following Objective-C code changes the working directory to the app bundle's Resources folder:

    NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
    [[NSFileManager defaultManager] changeCurrentDirectoryPath:resourcePath];
    If you create an Objective-C++ file with the extension .mm, you could place this code inside that file and have it work with your C++ code. Or you can look at Core Foundation's CFBundle functions to access the Resources folder.

    You should also take a look at the following SFML tutorial, which includes a file named ResourcePath.mm that simplifies accessing the app bundle's Resources folder:

    Tutorial - Getting started - SFML and Xcode (Mac OS X)
  5. BlinksTale thread starter macrumors newbie

    Nov 15, 2012
    Responding to my posts from two forums at once? Talk about above and beyond!

    I set my working directory from XCode, it's under Product > Edit Scheme, then under "Run MyGame.app (Release)" in the Options tab, there is a setting there: "Working Directory: Use Custom Working Directory" and then a field to input your own path.

    What's strangest yet though, none of this impacts anything after the data that is loaded when the game first starts. I just disabled using that working directory, and levels 2 through the end all load fine (they all copy over in their folders since XCode has been told that they are necessary files) - it's only that initial batch that has trouble loading. I imagine the rest succeed in accessing the Resources folder inside the app... so why would the first batch not be able to do this, or rely so heavily on the working dir?

    So it really seems like I can get this without diving into Objective C. The latter levels are already loaded seamlessly from the Resources folder, so if I loaded everything with the second level, I would bet it all works. I just can't figure out why that would be right now. So it already can reference Resources on its own (I just make calls to "./map/level002.map" and it finds "~/myGame.app/Contents/Resources/map/level002.map" all on its own) but only after the program is already running. Any idea why its reference point would change between when it was starting and when it was actually running?
  6. szymczyk macrumors regular

    Mar 5, 2006
    You shouldn't have to dive into Objective-C. SFML has done most of the work for you. If you read the tutorial I linked to in the past post, SFML has Xcode project templates. The project templates have the files ResourcePath.mm and ResourcePath.hpp that contain the code to get to the app bundle's Resources folder. Create a SFML Application project, copy the ResourcePath.mm and ResourcePath.hpp files to your game's Xcode project folder, and add those files to your game's Xcode project.

    Alternatively, you could use CFBundle to access the app bundle's Resources folder. CFBundle is a C API, not Objective-C. But I would start with SFML's ResourcePath files and see if that works before doing anything with CFBundle.

    As to why the first level has problems loading, my guess is that the first level loads before the working directory changes to the app bundle's Resources folder. Make sure your code sets the working directory to the app bundle's Resources folder before loading any files.
  7. BlinksTale thread starter macrumors newbie

    Nov 15, 2012
    So, I thought that last advice was a little strange since I already *was* using a template, and so it should have had that file in it. And it did! So I just called on it with #include "ResourcePath.hpp" and then added resourcePath() to the start of every path I used, and now it all works beautifully! One last bug on my end, and the code will be ready for a demo. Even the standalone works!

    Thanks again dude, you basically did half the work for porting my game to Mac :) If you would like mention in the credits, I will gladly give it.
  8. szymczyk macrumors regular

    Mar 5, 2006
    Since SFML is a cross-platform framework, I figured they had a way to access the app bundle's Resources folder. I wasn't sure of the specifics.

    I'm glad you got the code working. I don't need to be mentioned in the credits, but if you are going to have a list of people to thank in the credits, you have my permission to add my name to the list.

Share This Page