This week I added some rudimentary dungeon generation code to DungeonFodder. You can see what it looks like on YouTube.

EDIT: Eventually I expect to have a certain chance that a level will be a “special” level that’s been made by hand instead of randomly generated. Same for rooms - some of them will be “special” rooms.

There’re a lot of improvements that can be made to this approach - and so far it doesn’t add much content to the rooms, just the infrastructure. Here’s a quick explanation of how it currently works!

Rooms

Rooms are created as regular 3D Unity GameObjects, complete with scripts and all. Then, the dungeon generation script takes each of these objects, converts their dimensions to a 2D tile-based system and determines where the room has openings for corridors.

Rooms are split into “large” and “small” rooms, so that the engine can produce many small rooms and a couple of large ones, depending on what feel the level should have.

Placement

The script then chooses a random number of rooms of each size, based on a range for the level. For each room it wants to place, it picks a random rotation (n * 90°), and places it at a random location in the world. If the location is taken by another room, it starts searching for a free spot outwards from the initial random location.

Large rooms are placed before small rooms, to prevent the fragmentation from getting out of hand. A random “large” room is picked to be the “spawn” room.

Monsters & loot

Each level has a configured range of “monsters per tile”, like [0.1, 0.4]. For each room, it picks a random number in that range, and multiplies that number with the “square tileage” of the room. It skips the “spawn” room.

Currently, the spawn algorithm is very naïve. There’s also no loot being spawned.

Paths

Then, each “opening” in a room is connected by the shortest path to a neighboring room (using an implementation of the A* algorithm), but if a room has more than one “opening” then they are connected to different rooms. We tell our A* to count unpathed tiles as a bit more expensive than pathed tiles, so that paths will get reused.

Finally, each room is connected to the spawn room to ensure that we don’t have any disjoint “sub-dungeons” that aren’t connected to the rest of them. This time we configure our A* to count unpathed tiles as much more (currently 20x) expensive than pathed tiles, to encourage it to not create unneccessary paths.

Questions? Comments?

Feel free to contact me on jorgenpt@gmail.com or twitter

This week I’ve been deep in non-visible changes, working on a dungeon generator. While there’s not any good visible output yet, here’s the other stuff I had time to do this week:

Basic inventory, supports drag, still missing drop (and on-hover descriptions) ^_^
"Basic inventory"

Initial minimap - should probably not render lighting etc, but it works!
"Initial minimap"

Not too much time this Sunday, but I added some very rudimentary loot support: Boots of speed +50%!

EDIT: Found a way to get audio using Soundflower & sox.
EDIT 2: RTP+SDP was somehow garbling the output, new and improved script now uses FIFOs!

Turns out that livecasting your desktop in OS X is surprisingly hard. I found two ways online, none of which satisfied me, so I hunted for my own.

Adobe Flash Media Live Encoder, CamTwist & Soundflower

This method, described by Mike Chambers, relied on three separate GUI tools (one of which was required the Adobe Flash Media Live Encoder), consumed all my CPU, and refused to support my 16:10 aspect ratio. Yikes.

Ustream Producer

One simple app to do everything, but sadly it only supports streaming to Ucast, downscales to somewhere near the resolution of a feature-phone from 2000, and still constantly complains that I don’t have enough bandwidth. You can get the “Pro” version for $200 which gives you “HD Broadcasting” - but no thanks.

My own

So, based on Tyler’s Linux approach, I tried getting something similar working on OS X. It only used ffmpeg, and seemed to work pretty well.

Surprisingly, my researched ended up with the following results: 1. ffmpeg doesn’t support screen grabbing on OS X 1. ffmpeg doesn’t have a single audio input that can read an audio device on OS X (see OpenAL section below) 1. ffmpeg can’t record a web cam on OS X (this would allow me to use CamTwist as an input source) 1. VLC doesn’t support streaming to an RTMP server 1. VLC can’t record from an audio device 1. The only other app that’d stream audio live from an audio device to a fifo or pipe was sox.

Any of these statements might be wrong, so please tell me if you know a way :)

So, the best I could do was have VLC stream the screen over a FIFO to ffmpeg, redirect audio through Soundflower, then use sox to pipe audio to ffmpeg. Finally, ffmpeg recodes all that data and sends it to the justin.tv RTMP server. Not very simple, but at least it works.

Turns out that this works best if you do no work in VLC other than spew to a FIFO: no encoding or encapsulating. Even using MPEG-TS had issues in this context. Raw video in a dummy mux is passed over the FIFO to ffmpeg, and ffmpeg is allowed to do all the encoding.

In any case, I figured I should share this with the rest of you.

Here’s a modified version of Tyler’s script:

OpenAL issues

ffmpeg can theoretically record input devices on OS X using OpenAL - which ships with OS X by default. I spent some time trying to get homebrew to build it (patch here), but when I finally got it building I realized it was completely broken. Yay!

First video of gameplay from my alpha game, Dungeon Fodder.

So far: Very rudimentary AI, health, gibs, zombies and magic missile.

About a week ago I started playing around with Unity3D, trying to learn the ropes of the engine so that I could start making a game with it. This is that game: Dungeon Fodder.

Dungeon Fodder will be a dungeon crawler, inspired by great games like Nethack, Gauntlet) and Cannon Fodder) (!). While it’ll be a learning project, I’ll also focus on having my mechanics playable and fun as soon and often as possible.

It’ll be in the third person, hopefully feature a small group of adventurers (like Cannon Fodder), fast paced and action-oriented.

First up: Simple dungeon rendering, camera & control. :-)

I was tinkering with our build system at work, and I realized that builds were failing on r5b and below. After a bit of debugging (and reading the NDK changelog), I realized that LOCAL_WHOLE_STATIC_LIBRARIES was broken in r5b and missing in r4 and before. To prevent other engineers from running into this, I wanted to make our project depend on r5c or above.

There doesn’t seem to be a facility in place to do this, so I created a shellscript you can invoke from your Makefile to assert that the right version of the NDK is present. You can find the shellscript as a gist on GitHub

EDIT: This script depends on the environment variable ANDROID_NDK_ROOT to point to the base of your NDK. The script has been updated to test that this is the case (thanks to David R. for pointing this out).

The only caveat is that it does not support asserting versions below r5 - this is because only r5 and above have a version identifier in the NDK tree. It will correctly identify r4 and below as not being good enough for your build, but you can’t say “I need r3 or above”.

Put the script into jni/assert_ndk_version.sh, and put the following at the top of your jni/Android.mk, and voilà! Builds should now fail with a more understandable message if someone’s using the wrong NDK version. :-)

jni/Android.mk
1
2
3
ifneq ($(shell $(LOCAL_PATH)/assert_ndk_version.sh "r5c"),true)
  $(error NDK version r5c or greater required)
endif

With the launch of Lion, Apple added a new security feature to the operating system: The Application Sandbox. It encourages application authors to specify what subset of system functionality their app needs to function correctly, in order to reduce the impact of a malicious or compromised app. See the Mac OS X Developer Library or the ars technica Lion review for more info on this.

As a part of this, Apple added a set of entitlements labeled “temporary exceptions” (here’s a complete list), most likely to simplify and speed up adoption of this new technology. Your app can claim to need one of these “temporary” entitlements to do certain things that otherwise wouldn’t be allowed by the Sandbox. For GrabBox I need to have read-only access the users desktop – which falls under this category.

I’ve been spending some time today trying to figure out how to get the com.apple.security.temporary-exception.files.home-relative-path.read-only entitlement working. The documentation is sparse, and there’re no samples as far as I can tell. After many attempts, I finally figured out the key piece of information keeping me from getting this working: The path you specify in the entitlement needs to start with a slash. For example, instead of specifying Desktop, you specify /Desktop.

Here’s an example of a valid entitlement plist:

Info.plist
1
2
3
4
5
6
7
8
9
10
11
12
13
<pre><?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>com.apple.security.app-sandbox</key>
        <true/>
        <key>com.apple.security.temporary-exception.files.home-relative-path.read-only</key>
        <array>
                <string>/Desktop</string>
                <string>/Dropbox</string>
        </array>
</dict>
</plist>

I assume this applies to the com.apple.security.temporary-exception.files.home-relative-path.read-write entitlement as well.

I hope this saves other people trying to get this working a little bit of time. :-)