• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Math with Heights (need help with 3 problems)

Status
Not open for further replies.
Apparently I can get the height of the terrain with this function:

JASS:
WorldHeight(c_heightMapGround, Point(0.0, 0.0))

I want a generator where the higher or lower the point is above 12.0 the less likely it is for a tree to spawn so: 12.0 = 18% chance for a tree to spawn.

It should rapidly fall off as it gets lower and less rapidly for as it gets higher.

I will also stunt the tree growth at higher heights but I believe I know how to do that if I can just figure out how to do the math here probably.

The thing is I don't know how how to do the math behind this in a nice way...

I think I'm trying to do the same thing as like with a cars acceleration or a flamethrowers overheat where it approaches a certain maximum but never quite gets there. It should approach 0% chance of a tree spawning as it gets higher or lower and at different rates.

I have created a pre-made map with terrain where the height varies and I've basically made myself some cliffs and steep hills and the likes. I want to make it so that units (and other objects such as balls) can slide down the terrain. How do I do this?

I also want to make gravity for my projectiles... I'm not sure how it works though. There are 3 forces right? Velocity, acceleration, and gravity? Is acceleration velocity/time? What is acceleration? How do I get this to work?

This is what DrSuperGood has shown me but I still don't understand :'(
// how this bloody thing is derived...
za = acceleration at z axis
zv = ʃ za dt = za*t + C
z = ʃ zv dt = (za*t^2)/2 + Ct + D
C = initial speed
D = initial distance

// constants
t = 0.1 // the update period

// int the thing
z = 0 // ground level.
zv = 20 // we are jumping upwards at 20 units a second... in SC2 this guy will be in orbit in no time.
za = -9.8 // we are falling due to gravity which we assume is uniform and not a field that drops with height from ground. -9.8 SC2 units will be 1 damn strong attraction force.

//this is done perodicly
z = z+zv*t+za*t*t/2 // current z + z due to velocity + z due to acceleration
zv = zv+za*t // update current velocity based on acceleration​
In return for help I'll give you my perfected vote dialogue system. It can take any number of options as long as all the options will fit on screen, when 1 or more votes are tied it picks at random between the tied votes, it has a lot of nice labels to show how many times a given option has been voted on by a player, how many seconds are left to cast a vote before it automatically expires, and you can switch your vote anytime before the vote has expired too. It's really nice but I'm not giving it away without math help >_>. I spent many hours on it and I've tested it a great deal to make sure it works.

EDIT: Just experimenting myself and with some tips from an old friend I managed to get gravity working! Here's the current form my script takes... now I don't know how to do sliding and bouncing off of terrain though.

JASS:
//---------- Configurable Constants ----------
const fixed c_gravityTimerInterval  = 0.1;
const fixed c_gravity               = 9.8;
//--------------------------------------------
trigger     gt_gravity      = TriggerCreate("gt_Gravity_Func");
timer       gv_gravityTimer = TimerCreate();
fixed       gv_zBoost;

bool gt_Gravity_Func (bool testConds, bool runActions) {
    int         lv_i = 1;
    unit        lv_u = UnitGroupUnit(gv_gravityUG, lv_i);
    fixed       lv_z;
    fixed       lv_za = (gv_zBoost*c_gravityTimerInterval);
    fixed       lv_zg = (c_gravity*c_gravityTimerInterval);
    
    while(lv_u != null) {
        lv_z = UnitGetHeight(lv_u);
        
        lv_z = lv_z - (c_gravity*c_gravityTimerInterval);
        UnitSetHeight(lv_u, lv_z + lv_za - lv_zg, c_gravityTimerInterval);
        DebugMsg("Z: " + FixedToString(lv_z, 2));
        
        lv_u = UnitGroupUnit(gv_gravityUG, lv_i);
        lv_i += 1;
    }
    
    gv_zBoost = gv_zBoost - lv_za;

    return true;
}

// Register Physics Timer Event
void gt_Gravity_Init () {
    TimerStart(gv_gravityTimer, c_gravityTimerInterval/2, true, c_timeReal);
    TriggerAddEventTimer(gt_gravity, gv_gravityTimer);
}

To make them fly I currently just do this each time a unit is given a smart order:
JASS:
gv_zBoost = 30.0;
 
Last edited:
Level 11
Joined
Jul 20, 2004
Messages
2,760
I'll take problem #1 - seeing as physics always gives me a headache :grin:. What you're trying to accomplish here, is obtain a function F:R->(0,0.18]. From your data:
- F has a maximum at xmax = 12, F(12) = 0.18
- F is increasing on [0,12]
- F is decreasing on [12, infinity)
- The modulus of the derivative on [0,12] is greater than the modulus of the derivative on [12,infinity)

Alright, from what I can tell, branching the function ought to do the trick. For the left branch I recommend using an exponential, for the right branch an arccotangent ought to do the trick. More specifically:

JASS:
if (x<=12)
    F(x) = f1(x);
else
    F(x) = f2(x);

If exponential/arccot are too sophisticated, stick to linear functions.

(1) f1(x) - is an exponential. We apply a linear transformation on it, as to satisfy the following conditions:
f1(12) = 0.18
f1(0) = y0 - a threshold value for x=0

With a linear transformation, our function becomes:
f1(x) = a*e^x + b, where a and b are two coefficients.

To compute a and b, we plug in the equation the conditions above:
f1(0) = y0 => a*e^0 + b = y0
f1(12) = 0.18 => a*e^12 + b = 0.18

Solving this system yields the solutions:
a = (y0-0.18)/(e^0-e^12) = (y0-0.18)/(1-e^12)
b = y0 - a*e^0 = y0 - a

Therefore f1(x) becomes: f1(x) = a(e^x) + (y0-a)


(2)f2(x) is an acot. If StarCraft II has only atan, just use the formula:
acot(x) = pi/2 - atan(x). We use arccot(x) because it is strictly decreasing, and has a horizontal asymptote at x->infinity (that is, it approaches 0 as x grows bigger and bigger, but never has an exact value of 0).

Once again, we perform a linear transformation on the function. Hence:
f2(x) = c*acot(x) + d, where c and d are the linear coefficients.

Now the constraints for this case are as follows:
f2(12) = 0.18 => c*arcot(12) + d = 0.18
f2(xn) = t0 => c*arcot(xn) + d = t0, where xn represents a height at which the probability becomes t0. A possible example could be a height of 100, with a probability of 0.0002 (hence, xn=100, t0=0.0002).

Solve the system just like above and you obtain f2(x). Voila, your function should work now.
 
I'll take problem #1 - seeing as physics always gives me a headache :grin:. What you're trying to accomplish here, is obtain a function F:R->(0,0.18]. From your data:
- F has a maximum at xmax = 12, F(12) = 0.18
- F is increasing on [0,12]
- F is decreasing on [12, infinity)
- The modulus of the derivative on [0,12] is greater than the modulus of the derivative on [12,infinity)

Alright, from what I can tell, branching the function ought to do the trick. For the left branch I recommend using an exponential, for the right branch an arccotangent ought to do the trick. More specifically:

JASS:
if (x<=12)
    F(x) = f1(x);
else
    F(x) = f2(x);

If exponential/arccot are too sophisticated, stick to linear functions.

(1) f1(x) - is an exponential. We apply a linear transformation on it, as to satisfy the following conditions:
f1(12) = 0.18
f1(0) = y0 - a threshold value for x=0

With a linear transformation, our function becomes:
f1(x) = a*e^x + b, where a and b are two coefficients.

To compute a and b, we plug in the equation the conditions above:
f1(0) = y0 => a*e^0 + b = y0
f1(12) = 0.18 => a*e^12 + b = 0.18

Solving this system yields the solutions:
a = (y0-0.18)/(e^0-e^12) = (y0-0.18)/(1-e^12)
b = y0 - a*e^0 = y0 - a

Therefore f1(x) becomes: f1(x) = a(e^x) + (y0-a)


(2)f2(x) is an acot. If StarCraft II has only atan, just use the formula:
acot(x) = pi/2 - atan(x). We use arccot(x) because it is strictly decreasing, and has a horizontal asymptote at x->infinity (that is, it approaches 0 as x grows bigger and bigger, but never has an exact value of 0).

Once again, we perform a linear transformation on the function. Hence:
f2(x) = c*acot(x) + d, where c and d are the linear coefficients.

Now the constraints for this case are as follows:
f2(12) = 0.18 => c*arcot(12) + d = 0.18
f2(xn) = t0 => c*arcot(xn) + d = t0, where xn represents a height at which the probability becomes t0. A possible example could be a height of 100, with a probability of 0.0002 (hence, xn=100, t0=0.0002).

Solve the system just like above and you obtain f2(x). Voila, your function should work now.
My god, all that math D:. This might actually make my terrain generator really slow. Damn.

Anyways, it'll depend on the plant species but we'll assume we're using a low-lands deciduous tree, maybe a maple. At 12.0 height is optimal for it but it can also grow at much higher heights. Below 12.0 the chance of the tree germinating has to drop off much faster as in really low-spots (where water collects) we wouldn't want trees growing there. It would vary though for my different trees like willows would prefer the waters edge and some tree species grow mainly in shallow water and alpine trees or bushes at high altitudes. I'd also have walnuts growing at the edge of the forest where they prefer to grow and I'd have different methods of seed dispersal including animals, wind, etc. in the process. I'm just telling you to this to give you an idea of what I'm trying to do; make a simulation where a landscape is covered in foliage and has its own ecosystem and everything. While the map is loading everything will be sped up really fast to establish the initial plant and animal life. I'm not sure how advanced I want to make my weather system but I'll have that in too. I hope the math you showed me is suitable for what I'm doing... I'll get around to making use of it once I figure out how to make my gravity system ignore terrain height so units can jump off of hills and stuff properly.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,255
Use probability density theroies to do problem 1. The number of trees at a certain high can be controled via probability density which varies as a function of hight. A good distribution to use would be the normal distribution which clumps the majoratory of the probability around a central point.

This will model the sutibility of the altitude on the plant as there will be fewer of them at bounderies between growing heights. Obviously you use a clamp to assure that the probability is 0 for inappropiate altitudes.

As for problem 2...
If the objects are only visual then use SC2's inbuilt physics system. This will be enhanced with HotS to be even beter.

If you need them to interact with gameplay then that is more difficult. The basic idea is that gravitational potential energy (E = mgh) is converted into velocity (E = (m*v^2)/2). Some frictional force will logically remove energy from the system.

The physics for this was taught at highschool but unfortunatly I seem unable to recall it now. It is along the lines of the slope determining an upwards force (g*sin(normal)) and then the remaining downwards force is put parallel to the surface.

As for problem 3...
There are 3 forces right? Velocity, acceleration, and gravity?
Velocity is not a force...
Acceleration is force over mass (a = f/m)
Gravity is more like an acceleration because it provides a force depdenant on mass. However gravity in reality decays as you move away from the surface of the source so is an acceleration that is a function of displacement from the surface.

Is acceleration velocity/time?
Acceleration is the derivitive of velocity with respects to time. Velocity/time only works when there is no initial velocity and acceleration was constant. In the case of a car accelerating this will not be the case as acceleration drops as a function of velocity (at the top speed the car's acceleration becomes 0).

What is acceleration
In physics it is defined as a force acting on a certain mass. (a = f/m).
In mathematics it is defined as the double derivitive of displacement or single derivitive of velocity.

Acceleration is about the last meaningful vector to teach people as far as movement is concerned. You could get an infinite number of differentials from acceleration and equally well an equal number of integrals from displacement but such quantities have much more specalist use.

Example of such units.
Rate of change of acceleration m/s^3
Exposure to displacement ms.
 
Use probability density theroies to do problem 1. The number of trees at a certain high can be controled via probability density which varies as a function of hight. A good distribution to use would be the normal distribution which clumps the majoratory of the probability around a central point.

This will model the sutibility of the altitude on the plant as there will be fewer of them at bounderies between growing heights. Obviously you use a clamp to assure that the probability is 0 for inappropiate altitudes.

As for problem 2...
If the objects are only visual then use SC2's inbuilt physics system. This will be enhanced with HotS to be even beter.

If you need them to interact with gameplay then that is more difficult. The basic idea is that gravitational potential energy (E = mgh) is converted into velocity (E = (m*v^2)/2). Some frictional force will logically remove energy from the system.

The physics for this was taught at highschool but unfortunatly I seem unable to recall it now. It is along the lines of the slope determining an upwards force (g*sin(normal)) and then the remaining downwards force is put parallel to the surface.

As for problem 3...

Velocity is not a force...
Acceleration is force over mass (a = f/m)
Gravity is more like an acceleration because it provides a force depdenant on mass. However gravity in reality decays as you move away from the surface of the source so is an acceleration that is a function of displacement from the surface.


Acceleration is the derivitive of velocity with respects to time. Velocity/time only works when there is no initial velocity and acceleration was constant. In the case of a car accelerating this will not be the case as acceleration drops as a function of velocity (at the top speed the car's acceleration becomes 0).


In physics it is defined as a force acting on a certain mass. (a = f/m).
In mathematics it is defined as the double derivitive of displacement or single derivitive of velocity.

Acceleration is about the last meaningful vector to teach people as far as movement is concerned. You could get an infinite number of differentials from acceleration and equally well an equal number of integrals from displacement but such quantities have much more specalist use.

Example of such units.
Rate of change of acceleration m/s^3
Exposure to displacement ms.
Ok I'll give you the map now with my voting dialogue; you can tell me if you like it and if there's anything I should change with it. I also have my physics in there and I need to somehow deal with the variability of terrain height as well as to make units slide around when the terrain is steep (you'll see, just run a test and the physics just aren't perfect yet). I can't seem to make my behaviour I apply cause the unit to ignore terrain height... and I'm not sure how to make my script compensate for it and the various things I have tried resulted in the physics going insane. I'll also need to make em' bounce but I don't know how to do that and I want to create knockback but I'm not sure how to make that work in a nice way.

I would like suggestions at to how to properly name my variables here too...

Btw I'm trying to keep all my systems in my map as separate as possible so you should be able to disable just about everything else besides for example my vote system and still the thing should work.

Some variables I'm using though for examples of use are set in the Map Load script and other variables are in my Variables folder which is right at the top so they can be used by all scripts and there's function calls that use my system elsewhere... I think picking out each system though and transfering it to another map shouldn't be too hard...

(Going to attach the map in a moment, you probably won't see this message before then, just cleaning as much stuff up as possible)

JASS:
//---------- Configurable Constants ----------
const fixed c_gravityTimerInterval  = 0.1;
const fixed c_gravity               = 9.8;
//--------------------------------------------
trigger     gt_gravity              = TriggerCreate("gt_Gravity_Func");
timer       gv_gravityTimer         = TimerCreate();

bool gt_Gravity_Func (bool testConds, bool runActions) {
    int     lv_i = 1;
    unit    lv_u = UnitGroupUnit(gv_gravityUG, lv_i);
    int     lv_cv;
    point   lv_pt;
    fixed   lv_z;  // velocity
    //fixed   lv_zw; // terrain-height displacement
    fixed   lv_za; // acceleration
    fixed   lv_zg; // gravity
    
    while(lv_u != null) {
        lv_u  = UnitGroupUnit(gv_gravityUG, lv_i);
        if (UnitHasBehavior(lv_u, "Jump")) {
            lv_cv = FixedToInt(UnitGetCustomValue(lv_u, c_uIndex));
            lv_pt = UnitGetPosition(lv_u);
            lv_z  = UnitGetHeight(lv_u);
            //lv_zw = WorldHeight(c_heightMapGround, lv_pt);
            lv_za = (gv_zBoost[lv_cv]*c_gravityTimerInterval);
            lv_zg = (c_gravity*c_gravityTimerInterval);

            lv_z  = lv_z + lv_za - lv_zg - (c_gravity*c_gravityTimerInterval);
            //lv_zw = lv_zw; gv_zDisplacement[lv_cv]
            
            // Unit is at ground level
            if (lv_z <= 0) {
                lv_z = 0;
                // UnitGroupRemove(gv_jumpingUnit, lv_u);
                UnitBehaviorRemove(lv_u, "Jump", 1);
            }
            
            DebugMsg("Height: " + FixedToString(lv_z, 2));
            UnitSetHeight(lv_u, lv_z, c_gravityTimerInterval);
            gv_zBoost[lv_cv] += -lv_za;

            //gv_zDisplacement[lv_cv] = gv_zDisplacement[lv_cv] - lv_zw + lv_z;

            //if (UnitGetOwner(lv_u) == 1) {
                //CameraSetValue(1, c_cameraValueHeightOffset, lv_z, 0.2, -1, 10);
                //CameraSetValue(1, c_cameraValueYaw, UnitGetFacing(lv_u), 0.2, -1, 10);
            //}
            
            //DebugMsg("Z Offset Current: " + FixedToString(lv_zw, 2));
            //DebugMsg("Z Height Initial: " + FixedToString(gv_zDisplacement[lv_cv], 2));
        }
        lv_i += 1;
    }
    
    return true;
}

// Register Physics Timer Event
void gt_Gravity_Init () {
    TimerStart(gv_gravityTimer, c_gravityTimerInterval/2, true, c_timeReal);
    TriggerAddEventTimer(gt_gravity, gv_gravityTimer);
}

Current gravity script.
 
Last edited:
Status
Not open for further replies.
Top