• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Gravity Simulator 3.1

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
  • Like
Reactions: maddeem
I was bored, so I decided to build a gravity simulator in WC3 based on one I wrote a while ago in C++. Includes a mediocre unit indexer that I wrote myself, since Bribe's only deindexes when a new unit is indexed, while I need to update my index in real time, as it would mean that dead planets/stars would still exert gravity.

Indexed unit variables:
pull_on: Boolean - whether the unit will pull on other units
pulled_on: Boolean - whether the unit will be pulled by other units
force_x/y/z: Real - the current force on the unit along the x/y/z axis
mass: Real - mass of the object, the most important variable
position_x/y/z: Real - the position of the unit along the x/y/z axis
velocity_x/y/z: Real - the velocity of the unit along the x/y/z axis
body_1/2/3: Unit - DO NOT EDIT THESE UNLESS YOU KNOW WHAT YOU ARE DOING
unit: Unit - the unit

"Constants":
index_min: Integer - minimum unit index
index_max: Integer - maximum unit index
indices_per_update: Integer - number of three body indices updated per time interval
gravitational_constant: Real - directly modifies force, the one real constant
scaling_factor: Real - magnification on the universe
seconds_per_move: Real - how often the units are moved
seconds_per_update: Real - how often the three bodies are recomputed
time_factor: Real - how fast time passes

Since it's all GUI, just turn on the create new variables and copy/paste all of the triggers into your map. It would be nice if you gave credits to me if you use this, but it's not like I'll hunt you down if you don't.



  • Variable Initialization
    • Events
      • Map initialization
    • Conditions
    • Actions
      • -------- Sets all of the "constants" and creates the periodic event --------
      • Set i_index_min = 1
      • Set i_index_max = 500
      • Set i_index_current = (i_index_min - 1)
      • Set i_indices_per_update = 10
      • Set i_update_index_min = i_index_min
      • Set i_update_index_max = (i_update_index_min + (i_indices_per_update - 1))
      • Set r_gravitational_constant = (6.67 x (Power(10.00, -11.00)))
      • Set r_scaling_factor = 1.00
      • Set r_seconds_per_move = 0.05
      • Set r_seconds_per_update = 0.10
      • Set r_time_factor = 1.00
      • Trigger - Add to Move <gen> the event (Time - Every r_seconds_per_move seconds of game time)
      • Trigger - Add to Update <gen> the event (Time - Every r_seconds_per_update seconds of game time)


  • Index
    • Events
    • Conditions
    • Actions
      • -------- Sets all variables to default when indexing a new unit --------
      • Custom script: local integer i_temp = udg_i_index[0]
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • i_index[0] Equal to 0
        • Then - Actions
          • Custom script: set i_temp = udg_i_index_current + 1
          • Custom script: set udg_i_index_current = i_temp
        • Else - Actions
          • Custom script: set udg_i_index[0] = udg_i_index[i_temp]
      • Custom script: if i_temp < udg_i_index_max then
      • Custom script: set udg_b_index_allocated[i_temp] = true
      • Custom script: set udg_b_index_pull_on[i_temp] = true
      • Custom script: set udg_b_index_pulled_on[i_temp] = true
      • Custom script: set udg_r_index_position_x[i_temp] = GetUnitX(udg_u_new) / udg_r_scaling_factor
      • Custom script: set udg_r_index_position_y[i_temp] = GetUnitY(udg_u_new) / udg_r_scaling_factor
      • Custom script: if UnitAddAbility(udg_u_new, 'Amrf') then
      • Custom script: call UnitRemoveAbility(udg_u_new, 'Amrf')
      • Custom script: endif
      • Custom script: set udg_r_index_position_z[i_temp] = GetUnitFlyHeight(udg_u_new) / udg_r_scaling_factor
      • Custom script: set udg_u_index_unit[i_temp] = udg_u_new
      • Custom script: call SetUnitUserData(udg_u_new, i_temp)
      • Custom script: else
      • Game - Display to (All players) the text: Cannot index new un...
      • Custom script: endif


  • Update
    • Events
    • Conditions
    • Actions
      • For each (Integer i_loop_a) from i_index_min to i_index_current, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Life of u_index_unit[i_loop_a]) Less than or equal to 0.00
              • b_index_allocated[i_loop_a] Equal to True
            • Then - Actions
              • Unit - Remove u_index_unit[i_loop_a] from the game
              • Set b_index_allocated[i_loop_a] = False
              • Set b_index_pull_on[i_loop_a] = False
              • Set b_index_pulled_on[i_loop_a] = False
              • Set r_index_force_x[i_loop_a] = 0.00
              • Set r_index_force_y[i_loop_a] = 0.00
              • Set r_index_force_z[i_loop_a] = 0.00
              • Set r_index_mass[i_loop_a] = 0.00
              • Set r_index_position_x[i_loop_a] = 0.00
              • Set r_index_position_y[i_loop_a] = 0.00
              • Set r_index_position_z[i_loop_a] = 0.00
              • Set r_index_velocity_x[i_loop_a] = 0.00
              • Set r_index_velocity_y[i_loop_a] = 0.00
              • Set r_index_velocity_z[i_loop_a] = 0.00
              • Set u_index_body_3[i_loop_a] = No unit
              • Set u_index_body_2[i_loop_a] = No unit
              • Set u_index_body_1[i_loop_a] = No unit
              • Set u_index_unit[i_loop_a] = No unit
              • Set i_index[i_loop_a] = i_index[0]
              • Set i_index[0] = i_loop_a
            • Else - Actions
      • Custom script: call ExecuteFunc("gravity_update_bodies_loop")
      • Custom script: endfunction
      • -------- Calculates the net force on the unit and checks if it is the most --------
      • Custom script: function gravity_update_bodies takes nothing returns nothing
      • Custom script: local real r_x_difference
      • Custom script: local real r_y_difference
      • Custom script: local real r_z_difference
      • Custom script: local real r_distance
      • Custom script: local real r_gravitational_force
      • Custom script: local real r_temp_1 = 0
      • Custom script: local real r_temp_2 = 0
      • Custom script: local real r_temp_3 = 0
      • For each (Integer i_loop_b) from i_index_min to i_index_current, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • i_loop_a Not equal to i_loop_b
            • Then - Actions
              • Custom script: set r_x_difference = udg_r_index_position_x[udg_i_loop_b] - udg_r_index_position_x[udg_i_loop_a]
              • Custom script: set r_y_difference = udg_r_index_position_y[udg_i_loop_b] - udg_r_index_position_y[udg_i_loop_a]
              • Custom script: set r_z_difference = udg_r_index_position_z[udg_i_loop_b] - udg_r_index_position_z[udg_i_loop_a]
              • Custom script: set r_distance = SquareRoot(Pow(r_x_difference, 2.00) + Pow(r_y_difference, 2.00) + Pow(r_z_difference, 2.00))
              • Custom script: set r_gravitational_force = udg_r_gravitational_constant * udg_r_index_mass[udg_i_loop_a] * udg_r_index_mass[udg_i_loop_b] / Pow(r_distance, 2.00)
              • Custom script: if r_gravitational_force > r_temp_1 then
              • Custom script: set r_temp_3 = r_temp_2
              • Custom script: set r_temp_2 = r_temp_1
              • Custom script: set r_temp_1 = r_gravitational_force
              • Set u_index_body_1[i_loop_a] = u_index_unit[i_loop_b]
              • Custom script: elseif r_gravitational_force > r_temp_2 then
              • Custom script: set r_temp_3 = r_temp_2
              • Custom script: set r_temp_2 = r_gravitational_force
              • Set u_index_body_2[i_loop_a] = u_index_unit[i_loop_b]
              • Custom script: elseif r_gravitational_force > r_temp_3 then
              • Custom script: set r_temp_3 = r_gravitational_force
              • Set u_index_body_3[i_loop_a] = u_index_unit[i_loop_b]
              • Custom script: endif
            • Else - Actions
      • Custom script: endfunction
      • -------- Adds the 3 units with the strongest gravitational force on a unit to the index --------
      • Custom script: function gravity_update_bodies_loop takes nothing returns nothing
      • For each (Integer i_loop_a) from i_update_index_min to i_update_index_max, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • b_index_pulled_on[i_loop_a] Equal to True
            • Then - Actions
              • Custom script: call ForForce(bj_FORCE_PLAYER[0], function gravity_update_bodies)
            • Else - Actions
      • Set i_update_index_min = (i_update_index_min + i_indices_per_update)
      • Set i_update_index_max = (i_update_index_max + i_indices_per_update)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • i_update_index_min Greater than i_index_current
        • Then - Actions
          • Set i_update_index_min = i_index_min
          • Set i_update_index_max = (i_update_index_min + (i_indices_per_update - 1))
        • Else - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • i_update_index_max Greater than i_index_current
            • Then - Actions
              • Set i_update_index_max = i_index_current
            • Else - Actions


  • Move
    • Events
    • Conditions
    • Actions
      • Custom script: call ExecuteFunc("gravity_move")
      • Custom script: endfunction
      • Custom script: function extra_test takes nothing returns nothing
      • Custom script: local integer i_temp = GetUnitUserData(udg_u_temp)
      • Custom script: local real r_x_difference = udg_r_index_position_x[i_temp] - udg_r_index_position_x[udg_i_loop_a]
      • Custom script: local real r_y_difference = udg_r_index_position_y[i_temp] - udg_r_index_position_y[udg_i_loop_a]
      • Custom script: local real r_z_difference = udg_r_index_position_z[i_temp] - udg_r_index_position_z[udg_i_loop_a]
      • Custom script: local real r_distance = SquareRoot(Pow(r_x_difference, 2.00) + Pow(r_y_difference, 2.00) + Pow(r_z_difference, 2.00))
      • Custom script: local real r_gravitational_force = udg_r_gravitational_constant * udg_r_index_mass[i_temp] * udg_r_index_mass[udg_i_loop_a] / Pow(r_distance, 2.00)
      • Custom script: set udg_r_index_force_x[udg_i_loop_a] = udg_r_index_force_x[udg_i_loop_a] + r_x_difference * r_gravitational_force / r_distance
      • Custom script: set udg_r_index_force_y[udg_i_loop_a] = udg_r_index_force_y[udg_i_loop_a] + r_y_difference * r_gravitational_force / r_distance
      • Custom script: set udg_r_index_force_z[udg_i_loop_a] = udg_r_index_force_z[udg_i_loop_a] + r_z_difference * r_gravitational_force / r_distance
      • Custom script: endfunction
      • -------- Calculates the net force on all units --------
      • Custom script: function gravity_calculate_force_loop takes nothing returns nothing
      • Custom script: local real r_y_difference
      • Custom script: local real r_x_difference
      • Custom script: local real r_z_difference
      • Custom script: local real r_distance
      • Custom script: local real r_gravitational_force
      • Custom script: local integer i_temp
      • For each (Integer i_loop_a) from i_index_min to i_index_current, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • b_index_pulled_on[i_loop_a] Equal to True
            • Then - Actions
              • -------- Calculates the net force on the unit --------
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • u_index_body_1[i_loop_a] Not equal to No unit
                • Then - Actions
                  • Set u_temp = u_index_body_1[i_loop_a]
                  • Custom script: call ForForce(bj_FORCE_PLAYER[0], function extra_test)
                • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • u_index_body_2[i_loop_a] Not equal to No unit
                • Then - Actions
                  • Set u_temp = u_index_body_2[i_loop_a]
                  • Custom script: call ForForce(bj_FORCE_PLAYER[0], function extra_test)
                • Else - Actions
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • u_index_body_3[i_loop_a] Not equal to No unit
                • Then - Actions
                  • Set u_temp = u_index_body_3[i_loop_a]
                  • Custom script: call ForForce(bj_FORCE_PLAYER[0], function extra_test)
                • Else - Actions
            • Else - Actions
      • Custom script: endfunction
      • -------- Moves all units --------
      • Custom script: function gravity_move takes nothing returns nothing
      • Custom script: call ForForce(bj_FORCE_PLAYER[0], function gravity_calculate_force_loop)
      • For each (Integer i_loop_a) from i_index_min to i_index_current, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • b_index_pulled_on[i_loop_a] Equal to True
            • Then - Actions
              • -------- Sets the velocity based on force and time --------
              • Set r_index_velocity_x[i_loop_a] = (r_index_velocity_x[i_loop_a] + ((r_index_force_x[i_loop_a] x (r_seconds_per_move x r_time_factor)) / r_index_mass[i_loop_a]))
              • Set r_index_velocity_y[i_loop_a] = (r_index_velocity_y[i_loop_a] + ((r_index_force_y[i_loop_a] x (r_seconds_per_move x r_time_factor)) / r_index_mass[i_loop_a]))
              • Set r_index_velocity_z[i_loop_a] = (r_index_velocity_z[i_loop_a] + ((r_index_force_z[i_loop_a] x (r_seconds_per_move x r_time_factor)) / r_index_mass[i_loop_a]))
              • Set r_index_force_x[i_loop_a] = 0.00
              • Set r_index_force_y[i_loop_a] = 0.00
              • Set r_index_force_z[i_loop_a] = 0.00
              • -------- Sets the position based on velocity and time --------
              • Set r_index_position_x[i_loop_a] = (r_index_position_x[i_loop_a] + (r_index_velocity_x[i_loop_a] x (r_seconds_per_move x r_time_factor)))
              • Set r_index_position_y[i_loop_a] = (r_index_position_y[i_loop_a] + (r_index_velocity_y[i_loop_a] x (r_seconds_per_move x r_time_factor)))
              • Set r_index_position_z[i_loop_a] = (r_index_position_z[i_loop_a] + (r_index_velocity_z[i_loop_a] x (r_seconds_per_move x r_time_factor)))
              • -------- Moves the unit and incorporates scaling --------
              • Custom script: call SetUnitX(udg_u_index_unit[udg_i_loop_a], udg_r_index_position_x[udg_i_loop_a] * udg_r_scaling_factor)
              • Custom script: call SetUnitY(udg_u_index_unit[udg_i_loop_a], udg_r_index_position_y[udg_i_loop_a] * udg_r_scaling_factor)
              • Animation - Change u_index_unit[i_loop_a] flying height to (r_index_position_z[i_loop_a] x r_scaling_factor) at 0.00
            • Else - Actions



Updates:
3.1 Fixed recycling problem
3.0 Massive rehaul, efficiency is way up, now able to support 400 units moving ever 0.05 sec at 40 fps (before, only 30 units at 0.05 sec would lag crash the game)
2.2 Improved indexing
2.1 Made indexing more efficient, fixed force computation
2.0 Incorporated movement in the z axis
1.2 Consolidated the "Move" and "Calculate Force" triggers into the "Run" trigger
1.1 Consolidated the "Recycle" trigger into the "Run" trigger, added local variables
1.0 Released

Keywords:
gravity, physics, space, star, stars, sun, suns, planet, planets, space ship, pull, velocity, force
Contents

Gravity Simulator (Map)

Reviews
v3.1 IcemanBo: http://www.hiveworkshop.com/forums/spells-569/gravity-simulator-3-1-a-237184/index3.html#post2767878 10:37, 15th Jul 2013 Magtheridon96: This is just a reminder to what we've spoken about in chat to keep you from forgetting...

Moderator

M

Moderator

v3.1
IcemanBo:
http://www.hiveworkshop.com/forums/spells-569/gravity-simulator-3-1-a-237184/index3.html#post2767878

10:37, 15th Jul 2013
Magtheridon96:

This is just a reminder to what we've spoken about in chat to keep you from forgetting the discussion:

- Scalability and Speed in Physics Systems are important
- ExecuteFunc is not the kind of function you'd want running in a loop for this kind of system ;O
- Merge the functions into 1 function to reduce the impact of the ExecuteFunc calls.
- In order to stay away from the op limit, you can test for how many instances it takes for your system to go kaboom, and use that as a threshold. To iterate over the instances in the system, you would iterate over <threshold> instances, stop, make the trigger run itself again and loop over the remaining instances until it does <threshold> instances again, and repeat.
 
Level 29
Joined
Oct 24, 2012
Messages
6,543
also making multiple triggers for something so simple makes it harder for someone to copy, less efficient since u dont need all these triggers, and hard to read. u should really change how u code spells. Also note that using multiple triggers makes it so u cant use as many tempVariables which are better to use than creating more and more unnecessary variables.
 
Level 8
Joined
Oct 12, 2011
Messages
483
i tested it, the unit went off bounds and the game crashed also the variable names look weird and im not sure what your aim is when uploading something this simple

1. At the moment, I'm leaving the out of bounds as is, since I figure it should be open to the person whether to remove the unit, move it somewhere else, or do whatever else with the unit.
2. My variable names just happen to be the conventions I use in C++ to make sure I always match up correct data types, though I guess I don't really need that if I'm working in GUI. If it bothers peaople that much, I guess I'll change it.
3. I don't see this as being that much simpler than other GUI spells I've glanced at, but it is true that it's much less flashy than other spells, since it's just a system that moves units.

also making multiple triggers for something so simple makes it harder for someone to copy, less efficient since u dont need all these triggers, and hard to read. u should really change how u code spells. Also note that using multiple triggers makes it so u cant use as many tempVariables which are better to use than creating more and more unnecessary variables.

1. That is indeed true now that I think about it. However, there are some triggers I', fairly sure that I can't compress, such as the giant loops, as I'm fairly sure that a loop 8000 x 8000 times would hit the operation limit. I'll look into it though.
2. That is what I aim to do, as this is my first spell posted on Hive, I plan to change my coding to be more user friendly.
3. I totally forgot about local variables when I was coding. I'll go back and put some in.
 
Level 8
Joined
Oct 12, 2011
Messages
483
Is there another way to start a new thread other than creating an entirely new trigger or inserting a wait? I need the double 8k loops because I have to take every indexed unit (max 8k) and calculate the force all of the other indexed units exert on it (max 8k-1) Otherwise I would gladly combine as many triggers as I can.
 
Level 8
Joined
Oct 12, 2011
Messages
483
Originally it was for a little game where you navigate your spaceship to different parts of the star system and fired gravity pulled projectiles. I still have yet to figure out OpenGL, so atm I just use it in physics ball dropping simulations.
 
Level 8
Joined
Oct 12, 2011
Messages
483
I was about to ask about z next, are the units the same as x/y? The deallocation is in the "Run" trigger. The update speed is customizable, I just set it to 0.01 since what I have atm is not that lag intensive with just 2 units. And I am about to update to the three-trigger version.
 
Level 8
Joined
Oct 12, 2011
Messages
483
There are many ways to do it. I think you're talking about if the array = 1, 2, 3, 4, 5 and you remove 3, it becomes 1, 2, 4, 5. My indexing style is that it becomes 1, 2, 5, 4. I fill in the removed index with the last index value and decrease the index pointer.
 
nah I'm talking about it becoming 1,2,5,4 as yours claims to. I'm just going to show a algorithm that yours is doing:


  • instances 1, 2, 3, 4, 5
  • loop variable reaches 3rd place
  • instance 3 has ended
  • decreases index size: 1, 2, 3, 4
  • swap current index with last index: 1, 2, 4, 3
  • loop variable reaches 4th place
  • loop runs instance 3 again


if I'm wrong on this I'd love to be corrected, but that seems to me to be what's happening, have you tested the indexing?
 
Level 29
Joined
Oct 24, 2012
Messages
6,543
u should only decrease the index after u de-index everything. also u should decrease the current looping integer after u reduce the max index variable

edit: i see how ur indexing works and it is inefficient.

u should increase the index then index all the units and other things. in ur loop u should then decrease ur max index and then ur current index after de-indexing.

the method u use now is inefficient because u are looping through a non-existent index every looping period. also u do a lot of math which isnt necessary if u do it the normal way.
 
Level 8
Joined
Oct 12, 2011
Messages
483
Actually, I was only looping through current index - 1, so it wasn't doing the uber extra calculations. But you're right that it's kind of awkward, so I'm changing it right now. Along with a bug I may have found with the calculations.
 
Level 33
Joined
Apr 24, 2012
Messages
5,113
How about this allocation/deallocation?
Allocate:
  • Get first a recycled instance from stack
  • If the stack is empty, increment instances
  • If not, push the next instance of the recycled instance as the top of stack.

Deallocate:
  • Push top of stack back of the to-be-recycled instance
  • Set the recycled instance as the top of stack

Or simply in code:
JASS:
function Allocate takes nothing returns integer
    local integer i = recycle[0]
    if 0 == recycle[0] then
        set i = instances + 1
        set instances = i
    else
        set recycle[0] = recycle[i]
    endif
    return i
endfunction

function Deallocate takes integer i returns nothing
    set recycle[i] = recycle[0]
    set recycle[0] = i
endfunction
 
Level 8
Joined
Oct 12, 2011
Messages
483
Yeah, I realize my indexing is inefficient because every time I recycle I basically entirely reindex the last index.

Anyways, I don't pretend to understand your indexing method, it seems to work for only integers? Or is your indexing system kind of a guide so that when I allocate/deallocate, recycle[0] points to where I should move the data values in the array?

Otherwise I plan to use Bribe's Indexer's method where I don't actually have to move around variables around the array, since I just let new index values fill the gaps.
 
Level 8
Joined
Oct 12, 2011
Messages
483
The problem is that in your method when you deallocate, you essentially both allocate the data in the maxindex into the deallocated index and clear the maxindex. What I changed to only clears the deallocated index and stores it into an array and the next time I index, instead of incrementing the maxindex, the new data is indexed to the index stored in the variable. Basically, if I again use the 1, 2, 3, 4, 5 and I deallocate 4, I get 1, 2, 3, , 5, and the next time I index, it will be to the 4th position.
 
Hiho.

- All system related stuff should be put together in one folder.
- Using own UnitIndexer attempt is currently unacceptable. (conflict with real indexer)
- Add a guide/description for user what/how to use the system.
- The demo is not very explained and idk what to do in game.
- The system should not handle to remove units from game since that are no dummies.
- The system manipulates unit height, unit x, and unit y. Describe what the system exactly is expected to do.
 
Top