Categories
Game Design Game Development Games Geek / Technical Linux Game Development

LD50: The Theme is Delay the Inevitable #LDJam

The Ludum Dare compo has started, and the theme has been announced.

I am trying to remember if “Delay the Inevitable” was a theme I submitted, but I can’t seem to determine if that information is available.

My plan is to spend the first hour or so coming up with ideas. During Ludum Dare, there is usually an obvious idea that many people might try to pursue, so digging a little bit deeper should result in something more unique.

I just finished watching West Side Story (2021), so the inevitable violence and death that prevents two lovers from being together is top of mind.

Death is inevitable for all of us, and so delaying death might be one of the obvious ideas, but even so it seems like it could be a rich vein.

Taxes are also inevitable, but meh.

And in some areas people might argue that construction is inevitable. A game about constantly fixing roads? So are you delaying the construction, or is the construction delaying the entropy?

“Curse your sudden but inevitable betrayal!” That line from Firefly is classic, and perhaps a game could be built around the idea of joining forces with an enemy that you know is going to target you once your common foe has been defeated or problem has been solved.

Climate change is feeling inevitable. Perhaps a game about being a representative of a corporation trying to convince people that climate change is a personal responsibility despite that corporation being directly responsible for most of the greenhouse gases.

The expansion of the universe seems unending and ultimately results in heat death. I remember learning that Newton’s math, pre-relativity, didn’t actually work, as it predicted that the planets would spin out of orbit. Or was it Kepler? Either way, he suggested that it was God’s hand that was keeping everything in place. So perhaps a game about keeping celestial bodies in place by manually (and frantically) putting them back when they go where they aren’t supposed to. Maybe you start with the Earth-Moon system, then branch out into the solar system, then into the galaxy, etc. Might be a math/physics heavy project. But maybe it will be more enjoyable if the physics was a hand-rolled hack job anyway.

Looking at the time, I see almost an hour has passed. Eep! I want to think a bit more before deciding.

Categories
Game Design Game Development Geek / Technical Linux Game Development

Ludum Dare 50 Is Here: 20 years of #LDJam

Ludum Dare, the 48 hour game jam, is celebrating 20 years today with its 50th main event.

Or 51st, since LD#0 was a thing.

In 2008, I joined my first Ludum Dare. LD11’s theme was Minimalist, and I was very proud of the game I put together. It even had sound effects, which is more than I could say for some of my later Ludum Dare submissions. You can read the post-mortem here: https://www.gbgames.com/2008/04/29/ld11-minimalist-post-mortem/

LD11 Minimalist by GBGames

LD11 Minimalist by GBGames

My cats were there for my first Ludum Dare: Gizmo prevents me from game programming

Back then, there were a lot fewer participants, and it naturally felt a bit more intimate. Since then, it has grown quite a bit. There were MiniLDs, including #20 which I “hosted” (and got scolded by McFunkypants for not having ratings at the end). I remember meeting up with Ludum Dare colleagues at GDC 2011, putting faces to names and/or IRC handles. Instead of a hundred new games, there are thousands being made each event today. It has a dedicated website to call home instead of merely being on someone’s website. I miss my LD Trophy collection, though.

My last LD was #33 in 2015, and it was well-received and one I was very proud of (see the post-mortem here: https://www.gbgames.com/2015/11/30/ld33-free-me-you-idiots-post-mortem-ldjam/). Out of 1,199 entries, my game was rated in the top 36% overall and top 8% in innovation. Not bad.

I haven’t participated in recent years, partly because priorities made it difficult to dedicate a weekend to game development.

But thanks to my wife putting in herculean efforts to make it possible for me to focus more or less 100% on it this weekend, I will be participating in Ludum Dare 50.

I watched the LD 50 Keynote today, and it was nostalgic and inspirational. I’ve missed you all.

While her brother Diego died a few years ago, Gizmo is still alive and kicking at about 19 years old, and she’ll be next to me (or on top of my arms as I try to make a game) this LD, too

As always, I will participate in the Compo version of the event, in which I work by myself, create all of the code, art, and sound myself, and release the source at the end. I’ll be on IRC, and I’ll be blogging about my progress as I go. I will create a timelapse of my development. I will post pictures of my food. I will probably drink orange juice at some point.

In 2012, I wrote a Ludum Dare pre-compo checklist, and as I read it today, I realize it is pretty much still valid. I need to get groceries. I still need to prepare some of my tools. And we’re in the final hours before the theme is announced and the compo starts.

Are you participating? Good luck!

We’re all counting on you.

Categories
Game Development Geek / Technical Linux Game Development

Screenshots Made Easy with Window Resizing Tool wmctrl

I needed to create screenshots for the iOS port of Toytles: Leaf Raking, my leaf-raking business simulation. My game doesn’t have a built-in screenshot shortcut key, and I needed screenshots that were 2688×1242, 2208×1242, and 2732×2048.

Immediately I knew I didn’t want to resize windows by hand, as it would be annoying and error-prone. Was there a tool that let me do it in a much more controlled manner?

I did a search, and I came across this Ask Ubuntu question about resizing windows to a particular width and height.

That’s when I learned about wmctrl. It is a tool that allows you to interact with the X window manager, which is the main windowing system used by GNU/Linux desktops.

I ran the following command to find the window of the running game:

wmctrl -l

It output a bunch of windows and showed me that I had:

0x0320000f 2 [machine name] Toytles: Leaf Raking

And then I used the ID corresponding to the game to resize that window:

wmctrl -i -r 0x0320000f -e 0,10,10,2688,1242
wmctrl -i -r 0x0320000f -e 0,10,10,2732,2048
wmctrl -i -r 0x0320000f -e 0,10,10,2208,1242

And then I just navigated around my game, found a good spot to take a screenshot, pressed Ctrl+PrtScn to take the screenshot, then resized and repeated for the various iOS sizes.

I then used Gimp to remove the top 30 pixels which was just the title bar of the window. I think I should be able to take screenshots without the window decorations, but I haven’t researched it yet.

I think I’d like to create a script to handle resizing, taking the screenshot, cropping the top 30 pixels, and placing into the appropriate screenshot folder, but I’ll probably create it next time I need to make screenshots, which might be sooner than I think.

Categories
Game Development Geek / Technical Linux Game Development Marketing/Business

Gearing Up for Release: Platform-specific Issues, Part 2

Last time, I talked about Linux-specific issues to fix before my game’s release.

This time, I’ll address the issues I’m seeing on Android and Windows platforms.

Android: manual code signing

Quite frankly, between running the game on my phone and on my tablet, I haven’t seen any issues since I first tried to get my game built and installed on this platform. The main issue I had was figuring out which directory to save to, and I solved that issue.

Oh, and code signing was another solved issue. I can build and deploy debug builds by turning on developer mode on my devices, but the release build needed to be signed. As I am not using amazing IDEs that have one-touch buttons that do all sorts of fanciness, I had to figure it out myself from the documentation.

Luckily, the Android developer documentation for signing manually was fairly straightforward in this regard. In my CMakeLists.txt, I added a custom target called sign, which requires the location of my keystore and its alias. I created a few environment variables that I pass into my build, and the following is basically what’s needed as per the documentation:

ADD_CUSTOM_TARGET(sign
"echo" "================ SIGNING WITH KEY ================="
COMMAND "jarsigner" "-verbose" "-sigalg" "SHA1withRSA" "-digestalg" "SHA1" "-keystore" "${GB_KEYSTORE}" "bin/${ANDROID_APP_NAME}-release-unsigned.apk" "${GB_KEYSTORE_ALIAS}"
COMMAND "echo" "================ VERIFYING WITH JARSIGNER ================="
COMMAND "jarsigner" "-verify" "-verbose" "-certs" "bin/${ANDROID_APP_NAME}-release-unsigned.apk"
COMMAND "echo" "================ USING ZIPALIGN ================="
COMMAND "zipalign" "-v" "4" "bin/${ANDROID_APP_NAME}-release-unsigned.apk" "${ANDROID_APP_NAME}-release.apk"
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/android-project/")

Otherwise, I found porting to Android be very straightforward thanks to using the NDK and libSDL2-based libraries. If anything, I worry about scaling to different screen resolutions and device-specific compatibility problems due to the lack of devices I have to test on.

I’ve already signed up for the Google Play developer program, so the main piece to worry about is actually submitting my app to their store. How hard could it be?

Windows: persistence and font rendering

While GNU/Linux and Android are more or less the same, Windows is the odd duck.

I can easily cross-compile to create a Win32 build, and with my limited testing I found that the 32-bit version runs smoothly on a 64-bit system, so that’s good.

Since I don’t need to use a lot of memory, there’s no real advantage I can see to building a 64-bit version of my Windows port. The main downside would be an inability to support people on 32-bit systems, requiring that I provide both 32-bit and 64-bit binaries as I might need to do for the Linux-based package.

However, I did have to fix a few issues this past week that I didn’t know were there until someone tested it for me. Thanks, Rick!

I knew of an issue with using MinGW to cross-compile to Windows in which using std::cout would result in a crash. I never looked too hard into it because I only used cout for my own logging in order to find out what is happening, so I just commented them out when I released for Windows, usually for a Ludum Dare game.

Well, it turns out that there was still a crash, and I found that if I commented out the code that saved the current game state to a file, it would run just fine.

Was the known issue applicable to file stream operations, too? Luckily, gdb can be downloaded and run as a standalone applications on Windows, so I ran my game on Windows through gdb and read through the stack trace. It pointed to yaml-cpp.

I use yaml-cpp to save and load my game data, and it works very well. But why does it crash on Windows?

I found this thread on GitHub that mentioned a similar stack trace: Crashy shared object

It was closed without really being addressed, as the original poster gave up after seeing the issue disappear when using a later version of gcc.

Luckily, someone else found a different solution involving a change to a few lines in yaml-cpp’s code, although they said more tests are needed. I tried it, and it seemed to solve the problem for me, although I am a bit wary about not knowing what the change does or how it solves it. B-(

The other issue I found on Windows was that resizing the window results in the text looking completely wrong:

Leaf Raking Game Windows Text Corruption

All the other graphics look fine. Under the hood I am using SDL2_ttf, but using it directly isn’t showing this problem. I am using NFont, which does some caching, and I wonder if it is somehow being corrupted. I need to do some more tests, but this issue does not occur on my Ubuntu system, and Android doesn’t allow you to resize the screen dynamically at runtime, so it’s a Windows-specific issue so far.

I’ll continue looking into it, but updating to the latest version of NFont didn’t help. I tried updating my SDL2-related libaries next since some Windows 10-specific updates were made between the initial Windows runtime binaries and the latest release.

NFont’s creator Jonathan Dearborn has been running test apps I’ve sent him and sending back updates to try, and so far it seems we’re nearing a solution. Thanks for being so responsive, Jonny D!

The main major issue is signing my game’s binary. Windows 10’s SmartScreen puts up a warning about how they have protected your PC because they prevented the app from starting. It shows the binary as coming from Unknown Publisher.

That’s scary. I need to look into how to make it less scary. Does it require buying a code signing certificate, or is it similar to how Android’s code signing works? I don’t know yet, but I’m looking into it.

The other issue with Windows is that saving the game is sloooooow. In my game, I persist changes each time the player makes a major decision. Basically, if you click a button that switches to a different screen or causes something to happen in-game, I save so that if you shut the game down and reload it, it takes you back to where you were.

My Linux-based and Android-based builds are zippy. I can click, click, click, and any changes are instant. As a result, the game has been feeling very responsive despite the lack of a real-time need for it.

My Linux-based system does not have an SSD drive, and my wife’s Surface Pro does, and yet her system takes forever to save a file.

So on Windows, it feels less like click, click, click and more like click, wait, see screen update, then click. Because of the delay, sound effects are playing too early as well. It’s a lesser experience on Windows.

I haven’t ever needed to do multithreaded programming before as a single thread was usually plenty for the work I’ve ever done, but now I am wondering if I should spin of a thread specifically for writing to a file due to this issue that seems to be Windows-specific.

How Much Longer?

Ok, so there’s some technical issues, and some are easily surmountable, and some require some more investigation, and it’s possible there are some I haven’t run into yet.

Since Android seems the simplest to release, perhaps it goes into the Google Play store first, and I worry about the Linux and Windows versions later.

But I do not want this three month project to get to the ninth month before its first release.

The good news is that the next project will have a much clearer release plan, and many of these issues will be already solved. B-)

Categories
Game Development Geek / Technical Linux Game Development Marketing/Business

Gearing Up for Release: Platform-specific Issues

I started a three-month project at the beginning of the year, and I’m now in the eighth month. I reported on the reasons why it was taking so long last month.

But I’m feeling pretty good about it, and while I still have some balance issues to work out, and it’s a bit ugly, I’m preparing for the actual release.

The thing is, I haven’t really done a serious release before, and since I want to do a simultaneous cross-platform release, I’m finding issues unique to each platform.

The platforms I currently support:

  • GNU/Linux
  • Android
  • Windows

What I want to support:

  • Mac OS X
  • iOS

I’ll start with Apple platforms, then talk about the environment I use natively. Other platforms will be discussed in the next post later this week.

Mac/iOS: no development or testing environments

I would love to create a Mac port. I know it is theoretically possible to create a cross-compiler to generate a Mac version, but it seems I need Mac-specific libraries, which requires owning a Mac.

I don’t own a Mac, and while I know of virtual Mac services you can subscribe to online, I haven’t bothered to look too seriously into them. I would also like to be able to test the game, and so I would need to use a Mac in order to see how it really runs, especially after running into the Windows-specific issues above.

As for iPhone or iPad, I’m in a similar position. I don’t own an iOS-based device. As I’m using libSDL2, I know it is possible to port to it, even without a Mac, but I would need to look into how to do so, and I would still need to invest in the devices to test on.

I am saving up for these things, but at the moment I don’t have them and I don’t want to spend time on them until I know what I’m doing.

And in the past it’s been difficult to hear back from people willing to be paid for porting a game for me, and volunteers have had difficulty figuring out how to put my project together on their system. I might look into it again, because that was years ago, and it’s a different world today.

GNU/Linux: distributing dependencies and architecture compatibilities

I develop and test the game on my Ubuntu GNU/Linux system, and the main thing to worry about there is that I can distribute the game and have it work out of the box on other distributions.

My game uses libSDL2 and related libraries. While I installed them on my system using my package manager, I can’t assume that my customers will have them installed as well.

Basically, I need to build custom dependencies, as per Troy Hepfner’s excellent article series on Linux Game Development, and then distribute them with my game.

Quite frankly, rather than worry about an installer to put everything in the correct locations on someone’s system, I think providing a basic tarball might be fine. Rather than provide .deb or .rpm or customer shell installers for each type of system, and then worrying about following the correct Linux Filesystem Hierarchy Standard, you allow the player to put the game in the directory of their choosing, extract it, and play.

But then I need to worry about how the tell the system to load the libraries. Running an application on Windows, the system generally looks in the local directory for libraries to depend upon. Unfortunately, Linux-based systems don’t do so, and while there is a way to point it towards your libraries using the LD_LIBRARY_PATH environment variable, I also know that it is frowned upon to do so due to the security and compatibility issues it can introduce.

On the other hand, many popular commercial games on my system do just that. For instance, looking at the directory for Don’t Starve, I see:

$ cat bin/dontstarve.sh
#!/bin/bash
export LD_LIBRARY_PATH=./lib64
./dontstarve

The fact that it is in this shell script wrapper is better than the original concern of changing the default environment variable in a more or less permanent way, which can cause version conflicts and such. It’s your program. You know what it needs, and any other applications that run will not be affected.

Still, supposedly the better way is to tell your binary at build time where to look, which isn’t very difficult. It requires -rpath=\$ORIGIN/[directory where you put your libs]. $ORIGIN expands into the directory that your binary is located.

So if the extracted tarball would have the following structure:
– foo-bin
– libs
– libfoo.so
– libbar.so

Then I would build foo-bin with -rpath=$ORIGIN/libs.

Of course, now foo-bin MUST be in the same directory as libs, but in practice, it’s fine. When was the last time you moved parts of a game’s files to different relative locations and expected it to continue to work?

I’m sure there’s issues with this approach as well, but with these two approaches, there’s plenty of precedent.

The only unknown I have is dealing with 32-bit vs 64-bit systems. Ubuntu has multiarch support, but I’ve seen comments on forums about people not being able to run an application due to architecture issues.

Don’t Starve distributes separate 64-bit and 32-bit builds. FTL, on the other hand, distributed both the 64-bit and 32-bit binaries and libraries together, and using a shell script, it determined which platform you were on at runtime to point LD_LIBRARY_PATH to the appropriate directory.

And other games distribute all desktop platforms together in one file, so if you bought the game, you bought it for Windows and Linux and Mac, whichever one you wish to play on. I like this option, especially since I hate the idea that I have to pay for a game twice in order to play on two different platforms.

I know some companies make their living by porting games and then selling them directly, but it’s not a business model I prefer.

Next time

In the next post, I will talk about issues specific to Android and Windows.

Categories
Game Development Geek / Technical Linux Game Development

A Better Way to Write Platform-specific C++ Code

Gaming on Linux reported that Linux porter Ethan Lee’s SteamOS & Linux talk at MAGFest has slides and audio available.

Ethan Lee has ported a number of games to GNU/Linux, and his talk gives some insight into what people can do to make the porting process easier.

Some of it is obvious, such as not accidentally introducing proprietary dependencies. Just because you like using Visual Studio, it doesn’t mean you need to force anyone who wants to build your project to need Visual Studio to do so.

He dug into coding patterns that make it easier or harder for someone to port, and while the slides are annotated, having the audio makes it easier to understand the context.

What I found funny was that the day before I saw these slides, I wrote code that looks almost exactly like what he had on slide 20 under “Bad Idea”.

I was basing my code off of Aquaria‘s, which has a long function filled with #ifdef #else #endif lines to get the path to the user’s save directory, providing a different path depending on if you are using Windows, Mac OS X, or GNU/Linux. While I wrote my version a bit more simplistically, it seemed like a decent approach.

Here’s what my code looked like:

std::string Persistence::getUserDataDirectory()
{
    #if defined (__WIN32__)
    const char *environment = std::getenv("APPDATA");
    std::string homeDirectory = (environment ? environment : ".");

    #elif defined (GB_ANDROID_BUILD)

    std::string homeDirectory = RealInstanceDelegator().SDL_AndroidGetInternalStoragePath();

    #else
    // IF ON LINUX

    std::string homeDirectory(".");
    // See https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
    const char *environment = std::getenv("XDG_DATA_HOME");
    if (NULL == environment || std::strcmp(environment, ""))
    {
        const char *home = std::getenv("HOME");
        homeDirectory = (home ? home + std::string("/.local/share") : ".");
    }
    else
    {
        homeDirectory = environment;
    }
    #endif

    return homeDirectory + "/" + Version::PROJECT_NAME + Version::DEMO_STATUS;
} 

Ick. I would have to have to dive back into it and debug it if there is a problem later. Hopefully I got it right the first time.

But Lee’s presentation made me wonder how the “Good Idea” slide works and what was so different about it.

Here’s the code example in his slide:

char path[PLATFORM_MAX_PATH];
const char* GetSavePath()
{
   PLATFORM_GetSaveDir(path, "save.sav");
   return path;
}

It definitely looks cleaner without the preprocessing code, but even with the audio of the talk I didn’t understand what he was actually doing here. To me, it looked like his GetSavePath() was just delegating to a platform-specific version of the call, but how does this code know which one to use?

So I emailed him and asked.

His response:

The idea is that the way you write portable code separates the different paths from each other in a clear way while also being able to debug each path in a way where reading the path is trivial to do. The big problem with defs is that they often make things _crazy_ hard to read and are just error-prone in general, so I try to separate them in a different way.

Basically PLATFORM_* is just a blanket C namespace I make for separating everything; you just have a platform.h that all of the otherwise #ifdefy stuff will go to, then you write different platform.c files. In the case of the slide example I would write a platform_win32.c and a platform_linux.c, and of course you can mix and match if you really need to (linux.c and osx.c might both share a unix.c), and that’s a lot easier to reason about and is easier to share in places where platform code might be the same in certain places. It’s also a lot easier to know what you need to implement later when the linker points to exactly what PLATFORM_* calls it couldn’t resolve for a new port.

Ohhhhhh.

Ok, I get it.

So basically in, say, your CMakeLists.txt, you know which platform you care about, so you’ll build the project with the platform-specific .c file and ignore the rest, and when you read through the code, you don’t have the #if define #elif #endif mess to read through because they’re separated into different files that never collide with each other in the same build.

Nice! Oh, and also nice is that each of these implementations can easily be unit tested because you can create a separate test for each implementation.

So I got to work. I create one header file called Persistence.h and three different .cpp files: Persistence_ANDROID.cpp, Persistence_LINUX.cpp, and Persistence_WIN32.cpp. My project’s CMakeLists.txt would create a list of .cpp files to build. Now I make sure that list includes the platform-specific version of the .cpp file in the project’s sources. So if I am building an Android version of my game, it would build Persistence_ANDROID.cpp and ignore the Linux and Windows versions of the file.

FILE (GLOB GBLIB_SOURCES *.cpp)
IF(GB_ANDROID_BUILD)
    FILE (GLOB PLATFORM_SOURCES PlatformSpecificImplementation/*_ANDROID.cpp)
ELSEIF(GB_LINUX_BUILD)
    FILE (GLOB PLATFORM_SOURCES PlatformSpecificImplementation/*_LINUX.cpp)
ELSEIF(GB_WINDOWS_BUILD)
    FILE (GLOB PLATFORM_SOURCES PlatformSpecificImplementation/*_WIN32.cpp)
ENDif(GB_ANDROID_BUILD)
ADD_LIBRARY (GB-lib ${GBLIB_SOURCES} ${PLATFORM_SOURCES})

And look at it!

std::string Persistence::getUserDataDirectory()
{
	std::string homeDirectory = RealInstanceDelegator().SDL_AndroidGetInternalStoragePath();

	std::string userDataDirectory = homeDirectory + "/" + Version::PROJECT_NAME + Version::DEMO_STATUS;

	return userDataDirectory;
}

It’s straightforward to read and tweak, especially compared to the ugly mix of code in the original version. New platforms would be easy to support by changing the build script and adding a source file.

Thanks for the pro tips, Ethan Lee!

Categories
Game Design Game Development Geek / Technical Linux Game Development Personal Development

LD33: Free Me, You Idiots! Ported to Android! #LDJam

Shortly after I ported my Ludum Dare game to Windows, I ported it to Android! You can download and install the .apk now and play on your phone or tablet. I’ve updated my LD#33 compo entry.

Here’s a handy link to explain how to install an app outside of the Google Play store.

LD#33 Game Play

Warning: it’s not really optimized for mobile yet. It pauses when idle, but it doesn’t pay attention to the back button, so you’ll have to long-press the Home button then swipe it away to close it.

Categories
Game Design Game Development Geek / Technical Linux Game Development Personal Development

LD33: Free Me, You Idiots! Ported to Windows #LDJam

I’ve updated my Ludum Dare #33 compo entry with the Windows version of Free Me, You Idiots!. Now most of the world can play it!

LD#33 Game Play

Next up: fixing my Linux-based entry so that it uses a non-custom install of SDL2.

Categories
Game Design Game Development Geek / Technical Linux Game Development Personal Development

LD33: Free Me, You Idiots! Development Time Lapse #LDJam

Want to see the last 48 hours compressed down to a little over 3 minutes?

I uploaded the time lapse video of my development of Free Me, You Idiots!:

You can find the final submission at http://ludumdare.com/compo/ludum-dare-33/?action=preview&uid=251. Thanks for playing!

Categories
Game Design Game Development Geek / Technical Linux Game Development Personal Development

LD33: SUBMITTED! #LDJam

I did it!

With 15 minutes to spare, I submitted my entry for LD#33, Free Me, You Idiots!

LD#33 Title Screen

It has no sound, and there is a lack of challenge which makes it hard to call it a real game, and the UI feedback is lacking to let the player know what is going on, but it’s complete and playable.

LD#33 Game Play

It’s also quite complicated! I created a simple yet effective goal-based artificial intelligence, a little economy, and upgrades. The thing I wish I had was direct conflict between the good and evil villagers.

But I’ll have more to say when I write the post-mortem.

For now, check out my entry at Ludum Dare, and if you submitted your own entry, please rate my game.

I’ll create a Windows port, soon. You can download the game for:
GNU/Linux (459K)
Windows (2.8MB)
Android .apk (3.6MB)

Congratulations to everyone who submitted a game! It’s been a fun weekend, and I look forward to playing your games!