Recently, a feature request was made in Physion's Discord Server: "Add the ability to visualize the trajectory of an object". This functionality was already implemented in the old version of Physion as you can see in the video below:
Unfortunately (and for the time being) the web version of Physion doesn't natively support tracers. The goods news is that we can implement the tracer functionality using scripting.
The Tracer Script
We're going to create a NodeScript (i.e. a script that gets attached to a Node) to implement the tracer functionality.
Let's start with the constructor:
class Tracer {
constructor(node) {
this.node = node;
this.initialized = false;
this.trajectory = [];
this.maxTrajectorySize = 100;
if (typeof physion !== "undefined") {
this.graphics = physion.utils.createGraphics();
this.lineStyle = physion.utils.createLineStyle(0);
this.fillStyle = physion.utils.createFillStyle(0xff0000);
}
this.tracerRadius = 0.1;
}
// ..
}
In the constructor we initialize the data members of the class that we're going to use:
| Data member | Description |
|---|---|
| node | A reference to the node that this script is attached to (passed as argument in the constructor). |
| initialized | Boolean switch to help us perform a "one-off" initialization (see below). |
| trajectory | The trajectory array which is going to hold the positions (x, y) of our node as the simulation runs. |
| maxTrajectorySize | The maximum length of the trajectory array. The bigger this value is the bigger the trace will be. |
| graphics | This is the 'canvas' where the trace will be drawn. |
| lineStyle | The line style to be used when drawing the tracer (line width of 0 pixels, i.e. don't draw outline) |
| fillStyle | The fill style to be used when drawing the tracer (red color) |
| tracerRadius | The radius of the circles used when drawing the tracer. |
The update() method of the script is shown below:
update(delta) {
if (!this.initialized) {
this.initialized = true;
const scene = this.node.findSceneNode();
if (scene) {
scene.layers.foreground.addChild(this.graphics);
}
}
this.updateTrajectory();
this.drawTracer();
}
First, we use our initialized data member to perform a 'one-off' initialization task:
Add our graphics to the foreground layer of the scene (that our node belongs to).
In order to retrieve the scene that our node belongs to, we use the findscenenode method.
After initialization is performed, the script keeps repeating the following:
- Updates the
trajectoryarray - Draws the tracer
The updateTrajectory() method is responsible to update our trajectory array in each update. It does that by pushing the latest position of our node to the array. It also makes sure that this array doesn't grow infinetely: If the size of the trajectory array gets bigger than maxTrajectorySize then old positions will get removed.
updateTrajectory() {
this.trajectory.push(this.node.getPosition());
while (this.trajectory.length > this.maxTrajectorySize) {
this.trajectory.shift();
}
}
Finally we call the drawTrajectory helper which will use the trajectory array to draw a series of circles thus visualizing the trajectory of our node:
drawTracer() {
if (this.graphics && this.fillStyle) {
this.graphics.clear();
this.trajectory.forEach((point, i) => {
this.fillStyle.alpha = (i + 1) / this.trajectory.length;
physion.utils.drawStyledCircle(this.graphics, point.x, point.y, this.tracerRadius, this.lineStyle, this.fillStyle);
});
}
}
Using the Tracer Script
The Tracer script is available in the Assets Browser. To use it simply drag and drop the script onto the node to create the tracer for.
You can also see the tracer script in action in this sample scene.
Future Work
- Add the ability to trace any point on an object (and not just its center as presented in this solution).
- Add a
TracerNode(and the corresponding UI) to allow creating tracers natively (i.e. without a custom script) - More customization (e.g. gradient color)
