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!
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
-------- 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 --------
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
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...
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.
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
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.
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.
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.
i am not entirely sure about all the options to create a new thread. i know using a TriggerSleepAction does. but im not sure what else does. if u ask in WEHZ mybe someone will know them.
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.
For something like this to be approvable, you ought to have Z velocity/gravity as well, also the loop shoul;d run every 0.03 seconds not 0.01, and this should be reduced to 3 triggers max. And where is the deallocation?
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.
Ah yes I see it, though, if you're using dynamic indexing, then from what I can tell, the indexing is actually incorrectly done, normally you decrease the index size -after- recycling, as well as the current index number is decreased by one.
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.
Actually if I have 5 values stored, my current_index is sitting at the non-allocated 6th value. I know it's kind of awkward, but that's just how my indexing system works. For now.
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.
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.
every time u loop / increase the iteration it recalculates this current index - 1 to see if the loop should end.
so if u loop 8000 times u do 8000 extra math operations.
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
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.
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.
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
- 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.
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.