Creating a volumetric sensor in Unity is simple: you add a Collider component to a Transform, configure it as a trigger, shape the Collider to define the sensor's range, and add a script to the Transform that implements the OnTriggerEnter and OnTriggerExit methods. The Collider will activate these methods when another collider enters or exits its range, respectively.
That's all, and it usually suffices in most cases, but there are others where we need to define the shape of the volumetric sensor in real-time, during the game's execution. Imagine, for example, that you want to equip a mobile agent with a volumetric sensor to detect obstacles that may interfere with its path. Normally, you would place a volumetric sensor in the shape of a box in front of the agent, and this box would extend forward along a distance proportional to the agent's speed. If the box is too short, obstacles may be detected too late for the agent to avoid a collision. If the box is too long, the agent may react to obstacles that are too far away, which would be unrealistic.
 |
A mobile agent with a volumetric sensor to detect obstacles |
If the agent always maintains a constant speed, it will suffice to manually set the sensor's size when designing the agent. But if the agent varies its speed depending on its behavior, a single type of sensor may not be suitable for all possible speeds. In such cases, we could equip the agent with several sensors of different sizes and activate one or another depending on the speed range the agent is in. However, this solution will be very complex and difficult to scale if we end up changing the agent's speed range. It is much better to modify the sensor's size during execution and adapt it to the agent's speed at each moment.
I will explain how I do it with a BoxCollider2D. I'm not saying it's the best way to do it, but it's the best way I've found so far. You will find it easy to adapt my examples to other collider shapes and use them as a starting point to find the mechanism that best suits your case.
A BoxCollider2D allows changing its size through its size property. This consists of a Vector2 whose first component defines the width and the second the height of the box. We can change the value of this property at any time, and the collider will adapt its shape to it. The problem is that the BoxCollider will remain centered and grow in both directions of the modified component. If we have a case like the one in the previous capture, what we want is for the collider to grow forward when we increase the speed, and not for the collider to grow also towards the rear of the agent.
The way to solve it is to modify the dimension we are interested in, in the case of the agent in the capture it will be the height of the box, and at the same time displace the box, manipulating its offset, so that it seems to grow only on one side. In the example at hand, to make the sensor grow, we would increase the height of the box and at the same time displace its offset upwards to keep the lower side of the box in the same position and make it seem to grow only on the upper side.
 |
We want the collider to grow only on one side |
Based on the above, I will show you the code I use to generalize the different possible cases for a box. For a BoxCollider, the possible size modifications are those of the enum in the following capture:
 |
Possible growth directions for a box |
The options explain themselves: "Up" means we want the box to grow only on its upper side, "Down" on the lower side, "Left" on the left side, and "Right" on the right side. "Symmetric" is the default behavior according to which, when changing the height, the box would grow both on its upper and lower sides.
The point is that when you increase the size of a box in one of its dimensions, this increase is evenly distributed in a growth of both sides of that dimension. For example, if you increase the height of a box by 2 units, you can expect the upper side to rise by one unit and the lower side to drop by another. Therefore, if you wanted the box to appear to grow only on the upper side, you should keep the lower side in the same position by making the box rise by one unit.
The way to generalize it is that the box must move half the size increase in the growth direction we have marked.
 |
How to calculate the box's movement vector |
The box's movement vector can be obtained from a method like the previous one (GetGrowOffsetVector). In the case of our example, where we want the box to appear to grow on the upper side and the lower side to remain in its position, the growDirection would be "Up," so the method would return a Vector2 with the values (0, 0.5). Note that I have defined OffsetBias as a constant value of 0.5. This vector will then be multiplied by the box's growth vector, which will give us the box's displacement.
The growth vector is the resulting vector from subtracting the new box size from the initial size.
 |
Calculation of the growth vector |
Therefore, every time we want to change the box's size, we will have to calculate the growth vector and multiply it by the box's movement vector to obtain the new box offset so that it appears to have moved only on one side.
 |
Method to change the box's size |
The SetBoxSize() method, in which I implement the above, cannot be simpler. In lines 153 and 154, I reset the box to its initial size (1,1) and its offset to (0,0). Since the new size is set immediately afterward, the reset is instantaneous and not noticeable.
Then, in line 155, I execute the GetGrowOffsetVector() method to obtain the box's movement vector. And in line 156, I obtain the growth vector by calling the GetGrowVector() method. Both vectors are multiplied in line 158 to give the new box offset. Note in that same line, 158, that I use the initialOffset field (of type Vector2) to define a default box offset. This will be the offset the box will have when no movement has been applied.
Also note that I use the boxCollider field to manipulate the collider's properties. This field has a reference to the collider. You can obtain this reference either by exposing the field in the inspector and dragging the collider onto that field or by using a call to GetComponent() in the script's Ready().
If you include the previous methods in a script and make it expose public methods that end up calling SetBoxSize(), you will be able to manipulate the collider's size in real-time from other game scripts.
And with this, you have everything. It's quite simple once you have it clear, but if you start from scratch, it can take a while to figure out how to do it. I hope this article has saved you that time and that you found it interesting.