Tuesday, April 12, 2011

[devel] Bumping into walls

If you are developing games, you have probably already been faced with this issue: How to make characters nicely slide against the walls?

For a long time I did the usual trick: Detect a collision, compute (somehow) an extraction vector, remove from the motion vector the part parallel to the extraction vector (dot product ...). However, this never seemed to work quite well and I always ended up with troublesome cases. (Well, arguably this was due to poor coding ;) )

In one of my latest projects (a never-to-be-released zombie game I will maybe blog about someday), not only had I to face this problem, but on top of it I had tens of zombies bumping into each other, through network latency to add to the mix. What a nightmare.

After much wasted time, I figured out a simple and (I believe) elegant solution. The link may not be obvious, but it was in fact inspired by the Lloyd algorithm.

Assuming a 2D scene layout, seen from above, let's consider a disk centered around a character. A trivial but important consideration is that the center of mass of the disk is right below the character.



Now, let's consider a wall nearby the character:



The disk is cropped by the wall. The center of mass of the remaining part is now displaced. The trick is simply to correct the position of the character so that it always goes to the center of mass of the cropped disk. In summary at every frame: Compute motion vector, displace, compute center of mass, correct position.



Of course the figure is exaggerated. In practice a disk with smaller radius is used.

For collisions between characters, I subtract from the disk the half plane which is mid-way between the characters:



Now, you might be wondering how in hell you will be able to compute the center of mass. There are two different approaches. Both rely on a square instead of a disk.

In the first approach I used convex shapes as colliders ('brushes') and sliced the collision square by the shape of the colliders, keeping only the parts outside. (For code doing this, look back at Quake's code for slicing polygons by convex brushes). A simple center of mass computation then gives you the corrected position.

The second approach relies on rasterization. Setup a viewport matching the square around the character, render a quad outputting pixel positions in the map, render the colliders in black. Then read back and average the values of non black pixels to obtain the center of mass. This is the new position.

This works nicely, gives a feeling of 'soft' collisions (depending on how large the collision shape is) and supports easily even the trickiest cases (many characters in a tight space of complex shape).

Enjoy!

Wednesday, March 2, 2011

[various] VOD is such a failure here

This is driving me crazy. For years since I enjoyed NetFlix in the US I have been looking forward for a mail-based or download based video rental service in France.

Mail-based DVD rental never really worked here for several practical reasons, but also because well, this is the Internet era and download seems just easier. Unfortunately, VOD services in France are crippled either by a very limited and rather boring choice of movies, or by extremely fragile implementations (not even mentioning prices). Four (!) of my latest attempts at renting movies with different services failed -- either the movie downloaded but could not be watched, or the payment could not be made, or the service was temporarily unavailable. I have to admit, it worked once, giving a fantastic success rate of 20%.

Needless to say that US services cannot be used from France -- the 'global economy' does not seem to cross borders for customers. This left me wondering: If a customer willing to pay for watching movies and shows can't do it , isn't that actively encouraging piracy?

Sunday, January 9, 2011

[wubi] Accessing files from Windows

http://ext2read.blogspot.com/ is a good answer. No driver to install, just an explorer-like interface. Open root.disk and import your files.

Monday, August 30, 2010

[luabind] Global table of classes from C++

These days I am playing with Lua and LuaBind (yet another game project, more on that hopefuly soon). LuaBind is really quite amazing and is a perfect complement to Lua for C++ programmers.

There is one thing, however, that gave me a lot of trouble. I wanted to define from C++ a global table of class instances in the Lua script. With LuaBind you can easily define globals using luabind::globals. For instance, here is how to define, from C++, a global named 'test' and having 1234 for value:

luabind::globals(luaState)[ "test" ] = 1234;

In LuaBind (v0.9), a table is created using luabind::newtable, which returns a generic object. For instance:


luabind::object table = luabind::newtable( luaState );
table[ "Instance1" ] = new MyClass( "A" );
table[ "Instance2" ] = new MyClass( "B" );
table[ "Instance3" ] = new MyClass( "C" );


where 'MyClass' is a C++ class previously registered into LuaBind.

Defining the table as a global is as easy as:


luabind::globals(luaState)[ "AllInstances" ] = table;


This was working fine, but the code would keep randomly crashing after the lua script execution. This was really a strange behavior. Fortunately, this post saved my day.

The problem is not with the code above, but with the context around it. Here is the entire function running my script:


void threadLua()
{
...
lua_State* luaState = lua_open();
luabind::open(luaState);
...
luabind::object table = luabind::newtable(luaState);
table[ "Instance1" ] = new MyClass( 1 );
table[ "Instance2" ] = new MyClass( 2 );
table[ "Instance3" ] = new MyClass( 2 );
luabind::globals(luaState)["TableOfInstances"] = table;
...
int ret = luaL_dostring(luaState, program);
...
lua_close(luaState);
} /// things would crash here


So what's wrong? Well, lua_close destroys the lua context. Unfortunately, my seemingly innocent object 'table' is still alive when this happens. And as it turns out, the destructor of a luabind::object does expect the lua context to still be valid. Hence the crash. The fix is desperately simple - it is enough to limit the scope of the variable:


void threadLua()
{
...
lua_State* luaState = lua_open();
luabind::open(luaState);
...
{
luabind::object table = luabind::newtable(luaState);
table[ "Instance1" ] = new MyClass( 1 );
table[ "Instance2" ] = new MyClass( 2 );
table[ "Instance3" ] = new MyClass( 2 );
luabind::globals(luaState)["TableOfInstances"] = table;
} /// keep this: 'table' must not live after this point
...
int ret = luaL_dostring(luaState, program);
...
lua_close(luaState);
} /// no crash!


This one was painful to find out so I thought it was worth a post!

Friday, July 23, 2010

[research] By-example synthesis of architectural textures

I am leaving for SIGGRAPH tomorrow, where we will present our paper 'By-example synthesis of architectural textures'. This is joint work with Samuel Hornus and Anass Lasram.
The paper is available on this web page.

See you at SIGGRAPH :-)

Tuesday, April 20, 2010

[wubi] X11 trouble during install

At work I have a computer with a Quadro FX. For some reason, the Wubi 9.10 install has trouble with it. The first reboot under Ubuntu is supposed to launch the install process. However, I was left with a blinking screen and a text console. After a bit of struggle, I was able to install the NVidia drivers:

0. sudo stop gdm
(in between two blinks!) This stops gdm and stops the painful blinking.
1. sudo apt-get install lynx
(a text based browser)
2. Launch lynx, navigate through NVidia website
3. Download the dirvers (AMD64 bits for 64 bits computers)
4. Install the drivers
5. Start gdm

After this the X server should start fine. However there is a catch: Ubuntu is not installed yet, in fact you are running in a virtual RAM disk. If you reboot at this stage, all changes are lost!
The trick is simply to launch 'ubiquity', and select the 'loop' partition as install partition. Then the install completes and you are ready to enjoy Ubuntu!

Hope this helps.

Monday, February 1, 2010

[code] Visual Express 2010

I am trying out Visual Studio 2010. Again, thanks to CMake the transition is mostly painless.

I had one issue though, related to global include paths.
As explained here, they can no longer be set for Visual Studio as a whole but only on a per-project basis. Let's not argue whether this is good or bad but let's assume you need to set them globally (I my case, I just want the DirectX SDK include / lib paths to be set once and for all).

In fact, there is a very simple workaround. All projects seem to include the following property sheet: Microsoft.Cpp.Win32.User
Any change to these properties will happen in all your projects. Just edit it and modify the include / lib of the "VC++ directories" entry.

Note that there seem to be issues under XP (I am under Windows 7) => so read the full story if you need to set global paths using XP and 2010.