Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm working on a game with a replay system, so I need the game logic to be deterministic. A part of this is collision detection and I'm having a bit of a conceptual problem here. (I'm programming in Python but I think my question is more general than that.)

I need collisions to be solved in a deterministic unbiased order. For example, it would be unfair if collisions would always be solved first for the red team, because e.g. they would always collide with (and thus pick up) ammo first. I can't imagine I'm the first person experiencing this problem.

The way the engine works is somewhat as follows:

Until no objects colliding:

  • Find overlapping objects and separate them
  • Add the object pair to a "collided" set (so no duplicates).

Finally:

  • Sort the "collided" set based on some property.
  • Iterate through "collided" set and tell each object pair that they collided with the other object.

Is there a way to sort the set for this final iteration while keeping it fair?

Things that won't work:

  • Memory location (python's default for sorting objects) because this is nondeterministic.
  • Internal object ID's, because these ID's are always lower for the "red team", as they are added first.
  • X/Y coordinates, don't give a complete sorting order, because objects can have identical positions, additionally, this is biased because the "red team" spawns at X=0.
share|improve this question
1  
Try sorting by time of impact. –  Blecki Jan 22 '12 at 3:37

3 Answers 3

up vote 3 down vote accepted

You could use a hash function applied to the object ID as a sort key. This would randomize the order but ensure it was the same order on every run of the game. However, this would still be biased in a way because objects that happened to get small hash values would always solve first. There just wouldn't be any particular pattern to which objects those were. To solve this you might incorporate the frame count or timestep count since the beginning of the game into the hash, so that the hashes will effectively be re-randomized each frame.

Using a hash is a lot like using a seeded RNG and only extracting one number from it. The Python library includes the CRC32 hash (in the zlib module), which may suffice for your purposes.

share|improve this answer
    
This is what I ended up doing. I hadn't even thought about the hashes being unfair too, so I'll do as you suggest and randomize each frame. –  noio Jan 21 '12 at 21:03

I would use a random number generator because they are in fact deterministic. Here's the doc for the Python random generator: http://docs.python.org/library/random.html

How it would work is that you'd want to seed the random number generator using the same seed for actual game as for the replay (save the value in the replay). You'll only want to seed it once per game/replay and you need to use the same random number generator through the entire system (or multiples if you save and restore each seed). As long as you are retrieving the same count of random numbers, it will produce the same sequence, so make sure you are using a fixed time-step in your game and everything will work fine.

See here for more information on fixed vs variable time-steps: Fixed time step vs Variable time step I think you'll need a fixed time-step if you want the replay to be exact.

share|improve this answer
    
So your suggestion is to shuffle the collision list, but in a deterministic way? I think the problem is that the collision list is in a nondeterministic order to begin with (because it's a Python set), so I actually need to explicitly sort it based on some property. –  noio Jan 21 '12 at 21:04
    
I would attach a random number to each "collided" set at collision-time, then sort by that. No need for a hash. –  John McDonald Jan 21 '12 at 21:25
    
The problem with that is that each collided tuple (object1, object2) has to be identical, so that I can rely on Python's set() to keep only unique pairs (I only want to notify each pair once ). Adding tuple = (random(), object1, object2) would indeed be a solution, but then collided.add(tuple) would no longer preserve uniqueness of the list. –  noio Jan 21 '12 at 21:50
1  
Shouldn't you only check each object against each other object once? So with 3 objects: A->B, then A->C, then only B->C. B shouldn't re-check the collision against A because A already did that work (nor should C check against either A or B because both of those have been done). –  John McDonald Jan 22 '12 at 0:24
1  
@Noio : John's solution would work fine. Instead of worrying about why it's not compatible with Python's Set, you should look for ways to customize Set's behavior. I can't imagine a set that didn't offer some way to override the way the items are compared, but even if it doesn't, you shouldn't have any trouble ensuring uniqueness of items in some other standard container, or rolling your own. –  Blecki Jan 23 '12 at 1:49

Without seeing the code, I am having trouble conceptualizing the problem. That said, here are a few ideas that may or may not be useful:

  • You mentioned the second step is 'Add the object pair to a "collided" set'. Could you add a sort key during this step?
  • How about keeping track of elapsed seconds, ticks, or turns since the start of the game and using that as a seed for "random"? Assuming you have a repeatable/predictable number here, the random number will be deterministic.
share|improve this answer
    
I could use a sort key, the problem is that I'm using Python's set() to make sure each pair is only added once to the collided set, adding a sort key would break that behavior. –  noio Jan 21 '12 at 21:06

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.