Suspension script
Posted: 12 Jun 2007, 14:03
http://www.youtube.com/watch?v=cN1vt01mmcU
Here is a demonstration model + script, you will need to write an fbi and stuff to make it work if you want to test it.

The idea is that every wheel has a spring that pushes against the hull of the vehicle, so it bumps around. The spring force is normally proportional to it's displacement. First off we need these objects and variables:
As you can see I have added empty objects in the model, gs1, gs2 etc, those are the "ground sensors" that check the height at the locations of the wheels. This was a quick hack so it's certainly possible to reduce the nunmber of separate objects in different ways. The variables s1, s2, s3 etc is the displacement of each wheel/spring, wich I will show how to compute shortly. xtilt, xtiltv, xtilta etc are the current value, speed, and acceleration of the different axes that the hull can turn, and move. Notice that the body can rotate around both the zaxis, xaxis, and move up/down. Next is the suspension function itself:
Here we compute the different values for s1, s2... etc. Pretty straightforward, but notice that the if:s put a lower bound on how far down the wheels can go, this is important. The result is that sometimes, the wheel is in the air. One thing that can be improved is to add similar code here for the upper bound, this is when the suspension is overloaded and it should make a nasty bump...
Anyway, now we need to take into consideration the different spring displacements. The force from the spring is proportional to this displacement. The force can act in different ways, either giving a linear acceleration, or rotational acceleration on the body, depending on how it's distributed among the wheels/springs. This is just a quick hack to get something that looks like real physics, so I have opted to simply guess some values until i found some that works:
The ATANs where mostly to get angles instead of displacement, not much tought went into those. Notice that s1 and s4 are the front wheels, s3 and s6 are the backmost wheels. The force from the front wheels act in the opposite direction as that from the back, hence the difference in signs here. The last term "xtiltv/7" is the dampening. Depending on how much this is, you get different effects, called subcritical, critical and supercritical dampening. In short, subcritical (too weak) will continue to oscillate for a while, critical will quickly return to a balanced state, while supercritical will again slowly return to the balanced state but withouth oscillating at all.
Computing the speed from the acceleration is straightforward, so is the actual tilt. Notice the *4 there, I found that experimenting with different values here will change the amplitude/frequency in a different way then changing the constant in the acceleration formula itself (/300 here). Then we compute the other tilts, and the displacement, in a similar fashion:
Notice that for the displacement we don't need any ATANS or stuff, it's pretty straightforwardly just an average. Different combinations of spring forces could probably be used to get interesting effects, like weighing or such. Then the actual transformations are put into action. The x rotation followed by z rotation is imprecise and can lead to problems with very steep slopes, a more sophisticated way would be to use vector/matrix math to get the rotations done straight, but interestingly, the system is suprisingly good at overcoming these problems and self-correcting itself in a way!
The spring displacements are then recalculated and the wheels repositioned:
I'm not sure if the recalculation here is necessary, this is just a quick hack as said, I havn't tried removing it yet. The short sleep ensures that this is computed pretty much every frame. I think this is necessary and that It dosn't really take that much performance, but I havn't done any testing on this. I tries putting in 100 units at the same time or so and noticed no more lag then usual. The rest of the script is the usual stuff, just making sure to start this script on creation. It could probably be stopped from running when idle, but with some time to let any remaining oscillations run for a while.
So there is a lot of improvement that could be made. I'm pretty sure this can be used for a great deal of stuff, including different wheel configuration and even tank tracks. I also think these ideas could be used for a truely awesome walking script for legged things as well, combined with the work on "true walkscripts". Also, the unit recoiling when fireing weapons, when hit, and when starting/stopping movement can surely be added in for great effect.
Here is a demonstration model + script, you will need to write an fbi and stuff to make it work if you want to test it.


The idea is that every wheel has a spring that pushes against the hull of the vehicle, so it bumps around. The spring force is normally proportional to it's displacement. First off we need these objects and variables:
Code: Select all
#define TA // This is a TA script
#include "sfxtype.h"
#include "exptype.h"
piece ground, hull, turret, gun, flare, wheel1, wheel2, wheel3, wheel4, wheel5, wheel6, susp1, susp2, susp3, susp4, susp5, susp6, gs1, gs2, gs3, gs4, gs5, gs6;
static-var moving, xtilt, xtiltv, xtilta, ztilt, ztilta, ztiltv, ya, yv, yp, s1, s2, s3, s4, s5, s6, damp;
// Signal definitions
#define SIG_AIM 2
#define ANIM_VARIABLE Moving
#undef ANIM_VARIABLE
Code: Select all
Suspension()
{
while(1)
{
s1 = get GROUND_HEIGHT(get PIECE_XZ(gs1)) - get PIECE_Y(gs1);
if(s1 < [-2])
{
s1 = [-2];
}
s2 = get GROUND_HEIGHT(get PIECE_XZ(gs2)) - get PIECE_Y(gs2);
if(s2 < [-2])
{
s2 = [-2];
}
s3 = get GROUND_HEIGHT(get PIECE_XZ(gs3)) - get PIECE_Y(gs3);
if(s3 < [-2])
{
s3 = [-2];
}
s4 = get GROUND_HEIGHT(get PIECE_XZ(gs4)) - get PIECE_Y(gs4);
if(s4 < [-2])
{
s4 = [-2];
}
s5 = get GROUND_HEIGHT(get PIECE_XZ(gs5)) - get PIECE_Y(gs5);
if(s5 < [-2])
{
s5 = [-2];
}
s6 = get GROUND_HEIGHT(get PIECE_XZ(gs6)) - get PIECE_Y(gs6);
if(s6 < [-2])
{
s6 = [-2];
}
Anyway, now we need to take into consideration the different spring displacements. The force from the spring is proportional to this displacement. The force can act in different ways, either giving a linear acceleration, or rotational acceleration on the body, depending on how it's distributed among the wheels/springs. This is just a quick hack to get something that looks like real physics, so I have opted to simply guess some values until i found some that works:
Code: Select all
xtilta = 0 - (get ATAN(s1, [14]) - get ATAN(s3, [14]) + get ATAN(s4, [14]) - get ATAN(s6, [14]))/300 + xtiltv/7;
xtiltv = xtiltv + xtilta;
xtilt = xtilt + xtiltv*4;
Computing the speed from the acceleration is straightforward, so is the actual tilt. Notice the *4 there, I found that experimenting with different values here will change the amplitude/frequency in a different way then changing the constant in the acceleration formula itself (/300 here). Then we compute the other tilts, and the displacement, in a similar fashion:
Code: Select all
ztilta = 0 - (get ATAN(s1, [14]) + get ATAN(s2, [14]) + get ATAN(s3, [14]) - get ATAN(s4, [14]) - get ATAN(s5, [14]) - get ATAN(s6, [14]))/300 + ztiltv/7;
ztiltv = ztiltv + ztilta;
ztilt = ztilt + ztiltv*4;
ya = (s1 + s2 + s3 + s4 + s5 + s6)/100 - yv/25;
yv = yv + ya;
yp = yp + yv/10;
move ground to y-axis yp now;
turn ground to x-axis xtilt now;
turn ground to z-axis ztilt now;
The spring displacements are then recalculated and the wheels repositioned:
Code: Select all
s1 = get GROUND_HEIGHT(get PIECE_XZ(gs1)) - get PIECE_Y(gs1);
if(s1 < [-2])
{
s1 = [-2];
}
s2 = get GROUND_HEIGHT(get PIECE_XZ(gs2)) - get PIECE_Y(gs2);
if(s2 < [-2])
{
s2 = [-2];
}
s3 = get GROUND_HEIGHT(get PIECE_XZ(gs3)) - get PIECE_Y(gs3);
if(s3 < [-2])
{
s3 = [-2];
}
s4 = get GROUND_HEIGHT(get PIECE_XZ(gs4)) - get PIECE_Y(gs4);
if(s4 < [-2])
{
s4 = [-2];
}
s5 = get GROUND_HEIGHT(get PIECE_XZ(gs5)) - get PIECE_Y(gs5);
if(s5 < [-2])
{
s5 = [-2];
}
s6 = get GROUND_HEIGHT(get PIECE_XZ(gs6)) - get PIECE_Y(gs6);
if(s6 < [-2])
{
s6 = [-2];
}
move wheel1 to y-axis s1 now;
move wheel2 to y-axis s2 now;
move wheel3 to y-axis s3 now;
move wheel4 to y-axis s4 now;
move wheel5 to y-axis s5 now;
move wheel6 to y-axis s6 now;
sleep 10;
So there is a lot of improvement that could be made. I'm pretty sure this can be used for a great deal of stuff, including different wheel configuration and even tank tracks. I also think these ideas could be used for a truely awesome walking script for legged things as well, combined with the work on "true walkscripts". Also, the unit recoiling when fireing weapons, when hit, and when starting/stopping movement can surely be added in for great effect.