Intel sponsors gamedev.net search:   
Skipping a DBy JPatrick      
Marble4D (working title) will at first blush appear to be your common "roll a marble through a maze to reach the goal" game that we've all played in some form or other over the years. The not so subtle distinction, however, is that the world, the objects, and even the player are fully 4-Dimensional. To be pedantic, I mean strictly spatial dimensions, so if you count time I suppose it would be 5D, but that's a whole other topic. The game is being developed in C# using XNA Game Studio with the intent to eventually release on XBox Live Community Games. This journal will detail the developments and challenges along the way; I'll endeavor to make it interesting :) Oh, and in case you were wondering, this journal is entitled Skipping a D because I've never even made a 3D game before. So yeah... Challenges.

Thursday, October 29, 2009
Everything was going pretty smoothly. The emulator core was wrapped up in a nice managed interface, the WPF UI was hosting a winforms control that could be rendered to via SlimDX, xaudio2 output via SlimDX, etc. All the pieces were falling into place... except for the occasional startup crash. I was using vs2010 beta 1, so I was just writing it off as some possible incompatibility with SlimDX and the beta framework. After doing a little refactoring however, I was suddenly getting crashes 15-30 seconds in, and startup crashes much more frequently. I was making use of a few threads for the different components (one for the core itself, one for audio, with rendering and UI on the main thread). Intermittent crashes absolutely scream "synchronization problem" so naturally I started there. Reviewing my WorkerThread class carefully though, I just couldn't see what might be wrong.

Why not use the debugger? Unfortunately, the startup crashes seemed to kill the app even with the debugger attached, which is why I expected something external was going wrong at first. Oh how wrong I was, but that's getting ahead of myself. After refactoring though, the crashes were happening later as well, not just during startup, so I decided to see if the debugger could catch them again. Fired it up, waited a little bit, and:

FatalExecutionEngineError.

That's... not good.

Especially when that was only the error half the time. Other times I'd get NullReferenceException from things that can't possibly be null, StackOverflowExceptions when the callstack couldn't possibly be that deep, "this" reference being the wrong type or even missing altogether, or maybe just a good old fashioned AccessViolationException. It was absolute insanity.

The managed heap was obviously becoming deeply corrupted somehow. The emulator core has a fibers library to implement coroutines for synchronizing all the various parts of the system, which is part of the reason I was interested in it. I've always been a fan of coroutines, and don't think they get enough play in general, but I digress. I was wary in the beginning of what effect that kind of thing might have on the CLR, but I'd seen articles around that illustrated how to use fibers with .NET, so I perhaps it wasn't a problem. The coroutine library, in addition to implementing them in assembly, also has support for just using the windows fiber API directly. Just to make sure nothing was going wrong there, I switched it to use the windows fibers version, but no joy. Content for the moment that the problem wasn't there, I turned back to slimdx. I commented out the video code; still crashing. I commented out the audio code; still crashing. Updated to the latest version of the emulator source; still crashing.

What the FRACK. Seriously.

I was failing utterly at debugging. Maybe I'd have to use windbg or something and look at the core dump, but I'm just not that hardcore. Without any kind of clue as to what was REALLY wrong, I'd just have to shelf the whole thing and go back to working on the Marble4D editor.

Giving up on it for the night, I tried to get some sleep (which REALLY sucks when you have a mysterious unresolved bug). In the morning I took a step back and tried to reason through it. I just KNEW it had to be something relating to fibers, since in the beginning I was unsure if it'd work while hosted by the CLR at all. Perhaps there was something to that.

Wouldn't video and audio always have crashed though if that were the case, since the events are triggered by the core? Well, video refresh is triggered after the coroutine scheduler comes back to the main thread, and the way I was buffering up audio, I have the video refresh callback in the native interface also fire the audio event with all the samples buffered during that entire frame. If not those, then what...

Then it hit me. In one of the obscure crashes, the "this" reference for my worker thread manager object was corrupted and listed as a DevicePolledEventArgs.

INPUT! The emulator core waits as long as it can to poll input, to get the very latest state. The implication of this was that it was happening in a fiber, rather than the main thread. The input request triggers a callback that crosses the managed barrier back into my app, which fires an input event with a DevicePolledEventArgs. One of the things I changed in refactoring was having the input event create a new one each time the event fires, rather than reusing the same one over and over. I was getting that strange feeling where you just KNOW that the problem is there, even if you're not sure exactly why. I commented out the input callbacks, crossed my fingers, and ran it again.

No crash.

I ran it again and again and again and again both from inside the IDE and from explorer. Still nothing (yet). It would seem that fibers and other forms of "fake" threads interfere with the managed heap and the GC, at least in beta1. This is a definite case in support of my personal programming mantra: a brain is the best debugger. The unfortunate implication is that I'll have to poll input before the frame starts, rather than waiting until the last possible moment, but them's the breaks.

If anyone reads this and is an expert on fibers, I'd be very interested in your thoughts. Is calling back into CLR code from a native fiber known to be unsafe? Am I just doing something wrong?

At any rate, once I have some kind of input up and running, I'll post some screenshots to reveal what system and emulator specifically that I'm wrapping. I'll probably keep working on this mostly until around the new year perhaps, then switch gears back to Marble4D with a fresh outlook. Hopefully be able to get some kind of simple demo ready for DBP 10. It's definitely nice to crawl out from under all the limitations imposed by the 360 clr for a while and use more features and APIs. Definitely learning a LOT from this, and SlimDX rules. :)

Comments: 1 - Leave a Comment

Link



Wednesday, September 30, 2009
Disappointed after my XNA module player idea went bust, I was itching for another side project to change things up and keep from getting burned out working on the same thing constantly. Most of the other ideas I had, while simpler than a 4D game to be sure, were full fledged projects in their own right. I wanted something smaller and less architecturally taxing, so I could get charged up from brisk progress and tangible results. In addition, I wanted something that would excersize a different skillset than just another XNA project.

I've been a fan of emulators for a long time, so when the notion got floated for a more windows-centric fork of one of my favorite emulators, I had an idea. The emulator is written in native code, as most are. Unfortunately, it's been years since I've touched the stuff. However, there was a middle ground: c++/cli.

Using c++/cli, the core could be wrapped into a CLI compliant object model, thus facilitating the use of my more recent skillset. I'm no fan of c++ to be perfectly honest, but the simple fact is that it's ubiquitous, particularly in the games industry. So I figure it's best to maintain a moderate working knowledge of it, particular since I had already invested the effort to learn it years ago.

To its credit though, c++/cli does a fantastic job of interop between native and managed code. I was constantly googling the syntax to get things like events and properties working, but that was to be expected. Also to be expected was general rustiness all around. I was constantly forgetting things like the semicolon after the class definition, the ^ before reference types, proper includes, etc.

Speaking of, one thing I sure as hell don't miss is header files. They feel so clumsy and archaic compared to a proper module system to which I had grown accustomed. Preprocessor macros are also a minefield of errors waiting to happen.

That aside, it's still relatively painless to get a managed class up and running that can then be consumed by C#. I was constantly trying to break it with different combinations of managed/unmanaged calls and marshalling, but every reasonable scenario I could think of was working. I'm sure there are scenarios when things get nasty, but for now it's working great, even in x64 mode (which took registry hacks to get working in vc++ express, but thankfully I found an automated script that handled that for me).

So we'll see how it goes. I'm definitely enjoying this a lot, as a fresh change of pace, and am finding it easier to work on it for longer. I'll discuss it in more detail and show pictures if and when it gets working. Ideas are still brewing for the 4D game, and in time I'll be able to attack it again from a fresh perspective.

Comments: 0 - Leave a Comment

Link



Monday, August 31, 2009
Since it's been over a month without a post, I feel compelled to make one, even if just to make sure there's an entry for august. The wheels are still turning, albeit slowly. Another heatwave a while back sapped my motivation, and more recently I've been tempted by other, much simpler, projects. I'm not going to give up on this though. A 4D game simply must exist, and come hell or high water it's going to happen.

Anyway, work on the editor progresses slowly, and has revealed cause for refactory. The first thing wrong was my unnecessarily complex polychoron object model. I had a "Polychoron Part" class, which a polychoron would contain one or more of. As an example, I have a PlatformTesseract which will be the main surface object that the levels will be made of. The top and bottom of these have a grid-line shader applied, and all 6 sides (left/right, front/back, kata/ana) are just a solid color. This requires 2 separate geometry buffers, one for each shader. One polychoron part would be for the top and bottom, the other for the sides.

This worked, but was ugly and unwieldy. Since polychora are subclassed for specific purposes anyway, and they already contain a list of cells that they're made of, I shifted the responsibility of managing different surface materials to the polychoron subclass, rather than this awkward, extraneous part class. This worked swimmingly and greatly simplified slice code, allowing me to completely delete the part class. If refactoring were Tetris (and it kind of is), deleting an entire source file is like clearing 4 lines at once.

With that fresh, clean refactored feeling, I set out to allow my game objects to be consumed by the editor. This presented another problem though (of course it does, why wouldn't it).

In the editor, 4D objects are to be displayed in 2D panels that cover each permutation of axes. The question is then, what's the best way to flatten the object into the 2D plane without them just becoming jumbled messes. I decided that objects should draw the least number of lines possible (in other words, only their actual edges). Unfortunately, I have no way to achieve this yet.

Currently, polychora are just a list of 3D cells, each of which is sliced into a 2D face for rendering; the sum of the 2D faces making up the full 3D "slice" of the object, as detailed in one of my first posts. However, nothing in this process has anything to do with edges. My first instinct was just to draw the slices as wireframe, then flatten them down into 2D for the editor, but this will yield a lot of useless extra lines where the slice seams are (and there are a lot). These seams are typically invisible in 3D, except for the very occasional single-pixel gap wrought by floating point error. A little AA can smooth over those gaps for 3D, but what to do in 2D with all the extra lines?

Trying to detect "useless" lines dynamically would just be a mess, so I'm not even going to go down that road. Instead, what I plan to do is further elaborate on the Cell class so that it knows what 2D faces its made of. I can then write a slicing algorithm analogous to the current one, which will slice the 2D faces into 1D line segments. This should give me an optimal wireframe ideal for editing. Additionally, slicing an object down to edges will allow me to render objects as wirefram in-game, which could be useful for some kind of extra-dimensional awareness mechanic to alert the player of nearby objects on the hidden axis.

My new long term goal is to regroup and try for DPB 10, if there is one. Seems to be a pretty successful contest each year though, so I don't see why they'd stop.

Comments: 0 - Leave a Comment

Link


All times are ET (US)

 
S
M
T
W
T
F
S
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

OPTIONS
Track this Journal

 RSS 

ARCHIVES
October, 2009
September, 2009
August, 2009
July, 2009
June, 2009
May, 2009