In this post I will cover two topics: detecting collisions within components and helper classes I needed to write for the framework. I will cover the structure and goals for each of these, as well as what would I do differently about them if I did it again.
From my previous post, it’s probably clear that I see the structure of Unity as a really good way to do things, and members of the team who have used Unity in the past seem to agree on this. So now that we have the component based system, we would like to have some collision handling as well. Unity does this by providing OnCollisionEnter, OnCollisionStay and OnCollisionExit callbacks.
I thought we could maybe do something similar, as it gives a nice, easy to use interface for managing collision logic. My best effort to mimic this so far can be seen in the diagram below:
(A full-sized version of this diagram can be accessed at https://drive.google.com/open?id=0B_BnvnFZLH7mMWIyMm9wWkEtUGs )
When beginning to implement this, I’ve found that rigid bodies in PhyreEngine have a collision callback that the client can set. This is a function that will be called when the rigid body hits something, and it passes some data about the collision as well.
The ideal solution would be to set the callback in every component that’s interested in collisions. However, the important thing to realise is that an Entity has at most one Rigid Body, but can have many Components attached to it. For this kind of thing to work, you would need to be able to subscribe your callback function to collisions, but instead you only have a single callback function you can set.
The natural answer to this is to create a component of which there would be at most one on each entity (depending on whether we care about collisions or not), which would contain the collision callback mentioned. This is what CGCObjCollisionComponent is for. If your entity cares about collisions, simply add this component to your entity. I’ll explain how this system works.
On initialisation, the CGCObjCollisionComponent sets the collision callback for the rigid body in the entity to point to a function that the component contains.
On creation of a CGCComponent, it sets the rigid bodies user data pointer to point to the entity. Furthermore, every CGCComponent looks for a CGCObjCollisionComponent on the same entity and tries to subscribe to collisions. CGCObjCollisionComponent holds a list of all subscribed components on that same rigid body.
When a collision occurs, the callback is called and the collision component is then ready to process the data. First of all, the callback returns the two objects that have collided. From their user data pointers, we can extract the entities that they belong to. It also passes the user data pointer of the rigid body that the callback belongs to. This is also crucial, since the callback is a static function and we do not know which specific collision component is processing this information. From that pointer, we can also extract the entity – and this is the entity that holds a particular collision component. We can then get the component from the entity, figure out which of the two collided entities is us, and which is the thing we collided with, and notify all subscribed components with something like “Hey, I just collided into this entity!”.
This might sound a bit confusing when explained in words purely due to the words “entity”, “collision component” and “user data pointer” used so much. I thoroughly recommend looking at the diagram or the code, as it’s much easier to understand what’s going on from there (after all, that’s what the diagram is there for).
This kind of system allows us to react to collisions, much like in Unity. The big difference here though, is that the callback will be called repeatedly, every frame that the collision is still happening. Furthermore, there’s no way to easily differentiate between when a collision starts and when it exits. I’ve tried keeping some sort of list of objects that an entity collided with in the component, and then figuring out when the collision begins and ends from that, but with no information about collision endings, the best I can do is a timer of some sorts, which will always be prone to error.
However, having the collision callback spammed is certainly not ideal either, so I looked into Box2D and how it implements BeginContact and EndContact. It turns out that Box2D starts registering a collision before it happens by extending the AABBs for each rigid body. It then stores this information in a collision manifold, which it can check at every step to see if the objects have started touching. Furthermore, it can detect when the objects stop touching in the same way due to the extended AABB technique.
From looking at the documentation Bullet offers, there seems to be several global callbacks that a user might be able to set, such as gContactAddedCallback, which gets called when a collision is added. However, bullet warns about using these global callbacks in that they might be called too frequently for our uses: http://www.bulletphysics.org/mediawiki-1.5.8/index.php?title=Collision_Callbacks_and_Triggers . Furthermore, it would take us significant effort to extend the PhyreEngine bindings for Bullet to be able to use this. I spoke to Richard Foster about this during his visit to the studio, and apparently this is indeed a shortcoming of the current PhyreEngine and that they’re having the same kind of problems in the CaveVR demo, where the sound system can get flooded due to repeated collision callbacks. He advised that they might include a flag in the collision data to indicate whether the collision has just started for the next version of PhyreEngine.
In terms of this collision system, I think the main point is fairly obvious: investigate further into how we could detect the start of collisions and potentially modify PhyreEngine to support this, as we probably can’t afford to wait a couple of months for the next version of the engine. I know for a fact that there are a few coders in the team that are interested in looking into physics, so it might well be a task for module 3. After all, the only other answer to flooded collision messages is to have cooldown timers for each type of gameplay response to collisions, or a state machine where collisions trigger state switches, and different states only react to certain types of collisions.
Looking back at our iOS game which included a lot of collision spamming, I would like to avoid the option of timers. After all, they often resulted in weird bugs and issues down the line, because a timer is just an arbitrary value – it can almost never be exactly precise. The option to use state machines sounds better, but it might not be applicable in all cases. For example, say a bullet shoots a drone and the drone should lose health from a health bar of some sorts. The bullet will most likely spam the collision callback, so how do we avoid subtracting health more than once for one bullet? With a state machine, you could resolve this by going into a brief invulnerability state (although that’s effectively the same as a timer?), but that would also mean that your combat design is defined by the collision system’s shortcomings (which we’d like to avoid, because I think that would make us look bad as programmers – our code should implement the design, rather than the design implementing the limitations of our code).
Writing this post and reflecting on the collision system itself, I’ve noticed a few things that I would do differently and/or improve upon. Firstly, the CGCComponent sets the user data pointer to be the entity. I would like to avoid this. Imagine if we care about bumping into walls. This would mean that every wall should have some sort of component on it, otherwise we won’t be able to identify it. This obviously does not scale well. We need to come up with a better solution than this, or we need to add some sort of default component to all walls at game initialisation. After all, otherwise the entity is going to be null, and we have no way of knowing what we bumped into. I will need to look into what the user data pointer is set to by default (I suspect it might be the rigid body object itself), and see if we can use that instead. This would eliminate the requirement of having a component on each solid object.
Moreover, currently the collision component needs to be added to each entity that cares about collisions and wants to execute collision logic through the level editor. I think this shouldn’t be the case – neither the designers nor artists care about this purely technical component, so why should they need to remember to add it? In fact, PhyreEngine supports adding components from code, so ideally we would want the collision component to be added from a component that cares about collisions. This would also take care of the optimisation I have mentioned in the diagram:
Currently, all components subscribe to get notified about collisions. This makes the system easier to use (i.e. less manual), but also results to additional processing that’s not strictly necessary – it might turn out that a lot of components don’t care about collisions, but they’re still getting notified. So instead, I should place a mechanism such as:
If I am a component that wants to know about collisions:
- When I initialise, I will try to add a collision component to the entity (if it does not exist yet)
- I will subscribe to collisions using that collision component
This would remove the unnecessary subscriptions. I will need to develop this idea further and consider the best way to do this so that it’s easy to switch on/off for every new component.
For this framework, I had to write two helper classes. One is CGCObjDebugDrawer and the other is CGCObjRaycaster. I’ll try to briefly explain both of those.
The Debug Drawer class is, bluntly put, a workaround. When building our game, we want to be able to draw debug lines on the screen – either for raycasts, or for visualising vectors or whatever. PhyreEngine provides this functionality via a class called DebugUtils (which PApplication, or, in our case, CGCApplication, holds an instance of). Unfortunately, we can’t pass this instance to components directly, since it’s what I would call a runtime class – it doesn’t work in library projects because X and Y has not been initialised (for example, the renderer). We can use it in our project, but the PhyreAssetProcessor solution will not compile, meaning that, well, nothing will work (after all, there is no renderer set up in the PhyreAssetProcessor solution). Hence the need for this class.
It’s a singleton that wraps debug drawing functionality in a way that works when used within components. When you call DrawLine, it stores the line information in an array, which the CGCApplication then retrieves and draws the requested lines at every frame:
So it effectively acts as a buffer between components and CGCApplication. Since this is quite a simple class, I will not go into detail about how it’s implemented, as it’s pretty trivial.
This class is a singleton much like CGCObjDebugDrawer, but it serves a different purpose than just being a workaround. Instead, it’s provided as a wrapper to enforce encapsulation.
Raycasting in Phyre is done through calls to the PhysicsWorld. We might want to use raycasts in our components, so should we pass the physics world to them? I think this is exposing way too much information to components with regards to what we’re actually trying to do. Components should not know about the physics world. This is precisely why the raycast class exists – it provides a handy interface that components can use to perform raycasts without exposing the physics world to them. The class is also quite trivial, but should be really useful in the long run. I’ve used it when I was implementing hovercraft physics, and Radu is implementing raycasted lasers, to for both of these types of components we would this kind of interface.
Helpers – what now?
Since these are very simple classes, there’s not much to reflect about them. I think it’s a shame that we need the debug drawer buffer class, since it’s wasted resources in search of a workaround. Instead, we should be creating a framework that does not require workarounds like these, and that’s all the more motivation to look into alternative ways to implement components (as I discussed in my previous blog post).
However, if we do go down the route we’re taking right now, I expect the amount of helper classes to grow with time, and I think that this is a good way to implement them – in really small chunks of code, that serve one specific purpose and completely uncoupled from anything else. Building these types of helper libraries allows to create a toolkit of robust, easy to understand, use and manage utilities.
None due to NDA.