Construct provides a powerful 2D collision system (overlap and on collision events). It is in the developer's best interest to keep their collision events from sprawling over multiple event sheets in a spaghetti like fashion for purposes of code readability as well as performance.

Types of Collision Detection



Overlap

Overlap conditions trigger when two or more objects collision boxes are overlapping.

On Collision


Internally, 'On collision' is not a real trigger even though it appears like one in the event sheet - it works like 'Is overlapping' with 'Trigger once' after it. Fake triggers can be placed into subevents, it just means that if Construct calls a trigger, all the parent-level conditions have to be true for it to run the actions.

One crucial difference between Overlap and On Collision is that if two family entities X and Y collide with entity A in the same cycle, the "On A Collision With Family" trigger will run separately twice for each family entity in the same game tick. On the other hand, On Overlap can pass multiple overlapping entities into the SOL in a single game tick, which may necessitate the need for a subsequent for-each event.

For more information about the differences, see Overlap versus Collision.

Internal Performance



Construct does not perform redundancy checks when doing collision detection.
For example, if you have an EntityFamily consisting of Entity1 and Entity2, both of which are placed on the layout, and then call:
On EntityFamily collision with EntityFamily
Internally, this collision check will get run *TWICE* every tick: (debug mode under Collision Checks/sec shows 2 per tick)
  1. Does Entity1 collide with Entity2?
  2. Does Entity2 collides with Entity1?

However, the actual event will only get triggered a single time.

Additionally, Construct does not cache collision checks. This means that during the cycle of a single game tick, Construct will re-run the necessary collision routines for multiple collision related events even if the events are checking duplicate objects.

General performance tips

  • Minimize the number of "On Collision" event calls within one's code. Grouping object types into Families (for example: Environment, Monsters, Players, etc) can help with this.
  • Use "On Overlap" if possible (just be aware of the caveats)
  • Take advantage of collision cells

For more information, see collision redundancy.

Collision Event Location



Should collision events always be top-level, or should top-level events filter the list of objects before testing for potential collisions?

Below is a quote from the creator of Construct 2:
"Make sure collision conditions are the first condition in the top-level event. When no objects are picked, the collision conditions can make efficient use of collision cells to reduce the number of checks made, ensuring performance is good in all circumstances.

If Is overlapping (or On collision) comes after another condition which has picked certain instances, it can no longer use collision cells ... If a prior condition picked a large number of instances, it must brute-force collision checks again. The collision check conditions only need to be the first condition that picks for that object type. (It's just easier to phrase the advice as "make it the first condition".)

You can actually have any number of conditions either in the System object or unrelated object types, so long as the first condition in the whole event branch that picks from that object type is the collision check event - then it still uses collision cells."

However, even leveraging the use of collision cells, a project with hundreds of sprites supporting collisions can still heavily impact a project's average fps. Additionally, collision cells default to the dimensions of the project's window. If you're having frame rate issues in a single-screen game, collision cells are not going to help you. It would be interesting if in a future version of Construct, developers could set the size of collision cells.

In some situations, it may be better to have top-level events that filter by "active" objects (where active is some user defined set of conditions) before doing an "On Collision" test. Many older games particularly sidescrollers put objects which are too distant from the player into a kind of "sleep mode" which disables movement, any state machines, collision detection, rendering, etc. By adding a "Active" boolean to one's objects, a developer could add a periodic event which enables/disables any object based on its distance from the player. In this situation, the top-level event in the collision detection event sheet would be filtering object's by Active and then following with "On Collision" detection.



Frame Rates



As always, a developer should keep a close eye on their project's performance. However bear in mind that running one's project in Debug Layout can also have an impact on performance. When strictly benchmarking one's project, it is advised to keep a simple Text object that periodically updates itself with statistics including fps, cpuutilisation, objectcount, etc.



Further Design



It's good practice to only have one overlap or collision test, and do everything you need to in subevents under that. If you have two 'On collision' or 'Is overlapping' events that are checking similar object type sets, it will re-check the overlap both times.

A developer may elect to use a type of Base class (as a family) which contains the equivalent of "function pointer" instance variables for each type of collision and how they should be handled.

BaseClass (Instance variables)
  • OnEntityCollision (BaseClass.UID, Entity.UID)
  • OnPlayerCollision (BaseClass.UID, Player.UID)
  • OnEnvironmentCollision (BaseClass.UID, Environment.UID)

Furthermore, boolean variables could be used to disable/enable these collision routines allowing for collision to be skipped entirely and performance optimized. Note that these would need to be top-level conditional checks which could interfere with Construct's support for collision cells. Developer discretion is advised.