• # Simple but Effective Collisions Part 1: Radial Collision Handling

Math and Physics

## The Concept

As mentioned, this system allows you to handle collisions with objects which can be enclosed by bounding cylinders. These cylinders can be defined by two numbers, or rather, a vector and a float - one containing a location, and the other containing a radius. Let's imagine we have a simple scenario with a triangle of trees placed on a simple flat plane:
The player can move the camera around in a first person view, and is able to walk among the trees. We will use the 'radial' collision detection method to prevent the camera from passing through the trees. When the player attempts to walk through a tree, the algorithm will slide them smoothly around it, as seen in pretty much all current first person games. This process involves two steps, which are repeated every frame:
1. If the camera has entered a tree's bounding cylinder, register a collision.
2. Calculate a new location for the camera which puts it back outside the bounding cylinder.
So, how do we do this in practice?

## The Implementation

We'll start out by defining the location of each tree using an array of 2D vectors. We only need 2D vectors because the trees are not going to affect our motion in the up-down direction. If you wanted to use this algorithm for objects on 3D terrain rather than a 2D plane, it should work just as well with the same vector format because it's not possible for a walking person to collide with a tree from above or below, only from the side. Because of this, we only need to worry about the positions of the trees in the x-z plane, whether we have a flat terrain or not. As mentioned, we will use DirectX syntax and functions from here on in:  //The array contains 3 vectors - one for each tree: D3DXVECTOR2 v_treePositions[3] = {D3DXVECTOR2(0, 1), D3DXVECTOR2(1, 0), D3DXVECTOR2(-1, 0)};  We will also define a variable to describe the radius of each tree trunk. We will assume they're all the same radius, but if you wanted to personalise each one, you could define an array of numbers, or add a third component to the vectors describing tree locations.  //Each tree is 1m in radius: float f_treeRadius = 1.0f;  ...and while we're at it, we will define a vector to hold the location of our first-person camera as it changes from frame to frame:  //This is a global vector holding the camera's location. It starts at the centre of the world (0, 0, 0): D3DXVECTOR3 v_camPos(0, 0, 0);  OK, now each tree has an entry in our program, and we know where our player's camera is from frame to frame. All that remains is to put this information to use! We will define a function which will be called every frame. This function will loop through the tree locations, comparing each one to the location of the camera for that frame. If it registers a collision (i.e. if the camera's location is closer to one of the trees than is permitted by the bounding radius), then we will push the camera back outside the bounding radius. The effect is cumulative, meaning that each tree makes its own contribution to the overall position change. This way, the algorithm also works for closely bound groups of trees where the camera could be in contact with more than one at once. Let's go through the function line by line:  D3DXVECTOR2 handle_Collisions_Radial() { D3DXVECTOR2 v_deltaPos = D3DXVECTOR2(0, 0); for (int i = 0; i < 3, i++) { D3DXVECTOR2 v_vectorToCentre(v_camPos.x - v_treePositions.x, v_camPos.z - v_treePositions.z); if (D3DXVec2Length(&v_vectorToCentre) < f_treeRadius) { v_deltaPos += ((f_treeRadius / D3DXVec2Length(&v_vectorToCentre)) - 1) * v_vectorToCentre; } } return v_deltaPos; }  First, we notice that the function returns a D3DXVECTOR2. This corresponds to the amount by which the camera needs to move to put it outside of the bounding cylinders of all the trees. It returns a D3DXVECTOR2 because the trees only affect the location of the camera in the x-z plane. Second, we create an inline vector called v_deltaPos which will be filled with the overall change in position required to put the camera outside the bounding radii of all the trees. This is the vector which the function will eventually return. Next, we enter a loop which will iterate through all the trees. Since we have three trees, we will have three iterations. Third, we create a temporary vector called v_vectorToCentre. This contains a directional vector between the location of the camera and the location of tree in the x-z plane. Fourth, we compare the length of this vector to the bounding radius. Note that the +y direction is up. Fifth and finally, if the camera is indeed within the bounding radius of the current tree, we will add on just enough of v_vectorToCentre to put it back outside the tree trunk. Once the loop is complete, we return the resulting position change. The process is fairly intuitive until the final step. This diagram explains the maths behind it a little clearer:
As you can see, the location of the camera has moved within the bounding radius of tree . In order to put the camera back outside of the bounding radius while simultaneously making it slide smoothly around the edge, we need to add a certain amount of the vector v_vectorToCentre to the camera's position until it is once again outside the bounding radius, such that: In this equation, |v_vectorToCentre| denotes the length of the vector between the camera position and the tree's centre. It is calculated using the D3DXVec2Length() function. We are looking for the value of k - that is, the linear multiple of v_vectorToCentre which we should add to our camera position in order to put it back outside the bounding radius. In order to find the value of k, we can first divide through by |v_vectorToCentre|. This gives us: This can easily be rearranged to get: We have now calculated our value of k. All that remains is to add this linear multiple of v_vectorToCentre to our overall change in location (v_deltaPos). If you review the fifth step in the function, you can see that this is exactly what is happening. If called every frame, this function will calculate a collision contribution for each tree in the loop. Once this contribution is acquired, it should be added to the camera position vector as follows:  //Call the function to assess collisions: D3DXVECTOR2 v_camPosCollisionDelta = handle_Collisions_Radial(); //Since this function returns a D3DXVECTOR2 and our camera position is a D3DXVECTOR3, we //will need to create a dummy D3DXVECTOR3 with no y-component to add to v_camPos: D3DXVECTOR3 v_camPosCollisionDelta3D(v_camPosCollisionDelta.x, 0, v_camPosCollisionDelta.y); //Finally, we will move the camera according to our collison delta vector: v_camPos += v_camPosCollisionDelta3D; //Now that we have our new camera position, we can continue to render the frame as normal... 

# Conclusion

That's it! You may be surprised at how well this simple method works. The effect is quite satisfying, and it certainly added an extra professional depth to my exploits in the first-person camera world. Of course, this method could be used to handle collisions involving objects other than a first-person camera, and subjects other than trees. This is also a bare-bones version of the algorithm, and it could easily be adapted to handle collisions in 2D games as well as collisions between circles and spheres and their environment (throughout, we assumed that the first person camera was a simple point rather than an object with dimensions). I intend to write another article describing another collision method which can be used to simulate walls and interiors/exteriors of buildings and things like hedges and maze walls. Until then, thanks for reading!

# Article Update Log

19 May 2013: Initial release

Report Article

## User Feedback

You need to be a member in order to leave a review

## Create an account

Register a new account