Terrain (physics/normal system) struct leaking problem

aliminator8

New Member
Reaction score
3
Hi guys,
Main Problem...
Creates more (xyz) structs than it destroys.
therefore errors with unable to allocate id to object after count (global integer) reaches 18,000.

Background info and minor problems...

This system i made is meant to simulate a circular object on a slope, so it rolls down in a correct manner.
The dummy unit basically moves in relation to the normal of the slope it is on.
It works but i haven't been able to make the object gain momentum correctly.
I got the Normalization formula from http://www.fullonsoftware.co.uk/snippets/content/Math_-_Calculating_Face_Normals.pdf
i don't fully understand it but seems to be working.

So if anyone has any suggestions about coding and the physics system it would greatly be appreciated.

code below:
JASS:
library xyzvectors initializer init 
globals
    real mass = 0.1
    integer count = 0
    xyz cvel 
    real accuracy = 30
endglobals

function counter takes nothing returns nothing
    set count = count + 1
    call BJDebugMsg(I2S(count))
endfunction

function uncounter takes nothing returns nothing
    set count = count - 1
    call BJDebugMsg(I2S(count))
endfunction

function GetTerrainZ  takes real x, real y returns real z
    local unit u = CreateUnit(Player(0),'hfoo', x, y, 0)
    local location l = GetUnitLoc(u)
    local real r = GetLocationZ(l)
    call RemoveLocation(l)
    call RemoveUnit(u)
    return r
endfunction

struct xyz
//for handing points in 3d (x,y,z)
real x
real y
real z
    static method define takes real x, real y returns xyz
    local xyz vel = xyz.allocate()
    local real z1 = GetTerrainZ(x,y)
    call counter()
    set vel.x = x
    set vel.y = y
    set vel.z = z1
    return vel
    endmethod
    
    method add takes xyz a returns nothing
    set this.x = a.x + this.x
    set this.y = a.y + this.y
    set this.z = a.z + this.z
    endmethod
endstruct



function normal takes xyz a, xyz b, xyz c returns xyz
    local xyz v1 = xyz.create()
    local xyz v2 = xyz.create()
    local xyz norm = xyz.create()
    call counter()
    call counter()
    call counter()
    set v1.x = b.x - a.x
    set v1.y = b.y - a.y
    set v1.z = b.z - a.z
    set v2.x = c.x - a.x
    set v2.y = c.y - a.y
    set v2.z = c.z - a.z
    set norm.x = (v1.y * v2.z) - (v1.z * v2.y)
    set norm.y = -((v2.z * v1.x) - (v2.x * v1.z))
    set norm.z = (v1.x * v2.y) - (v1.y * v2.x)
    call v1.destroy()
    call v2.destroy()
    call uncounter()
    call uncounter()
    return norm
endfunction 

function periodic takes nothing returns nothing
local unit u = gg_unit_hfoo_0000 //testing unit
local real x = GetUnitX(u)
local real d // distance
local real y = GetUnitY(u)
local real z = GetLocationZ(GetUnitLoc(u))
local real xy = 0.00 // angle on xy plane
local real xytoz = 0.00 // angle of elevation
local xyz a = xyz.define(x,y+accuracy) //creating 3 vertices at (x+0,y+30),(x+30,y-30) and (x-30,y-30)
local xyz b = xyz.define(x+accuracy,y-accuracy) // to make a triangle
local xyz c = xyz.define(x-accuracy,y-accuracy) // and then find the normal of the triangle
local xyz vel = normal(a,b,c) //calculate normal
call counter()
call counter()
call counter()
set d = SquareRoot((vel.y*vel.y) + (vel.x*vel.x))//set d as distance of the normal on the xy plane.(xy distance or 3d distance?)
set vel.x = vel.x / d //convert to unit vector (i think...?)
set vel.y = vel.y / d
set vel.z = vel.z / d
set xy = Atan2(vel.y, vel.x) //calc angle on xy plane
set xytoz  = Atan2(SquareRoot((vel.x*vel.x)+ (vel.y *vel.y)),vel.z)//// angle of elevation
set z = d*Sin(xytoz)
set d = d*Cos(xytoz) // set distance smaller because if elevation = 90 then distance should equal 0
set y = d*Sin(xy)
set x = d*Cos(xy)
//instant velocity
call SetUnitX(u,GetUnitX(u)+(x/333+(accuracy-30)))//instantaneous movement...
call SetUnitY(u,GetUnitY(u)+(y/333+(accuracy-30)))

//continuous velocity
//cvel is global xyz struct.
call cvel.add(vel)//tally current normal with old ones to create continuous velocity.... this effect semi-works but could be improved...
//continuous velocity works so if you just got of a slope and moved onto flat terrain your force will continue to move 
//you in the previous direction
set cvel.x = cvel.x / (1+mass)
set cvel.y = cvel.y / (1+mass)
call SetUnitX(u,GetUnitX(u)-(cvel.x/30+(accuracy-30)))
call SetUnitY(u,GetUnitY(u)-(cvel.y/30+(accuracy-30)))
////////////////
call vel.destroy()
call a.destroy()
call b.destroy()
call c.destroy()
call uncounter()
call uncounter()
call uncounter()
call uncounter()
endfunction

function init takes nothing returns nothing
local trigger t = CreateTrigger()
set cvel = xyz.create()
call counter()
call TriggerRegisterTimerEventPeriodic(t,0.03)
call TriggerAddAction(t,function periodic)
endfunction
endlibrary
 

Prozix

New Member
Reaction score
7
I'm not good at fixing memory leaks as I create them more often than I fix them.
I got interested by the physics system and I think you don't need to use the normal vector *not sure*
If i remember correctly we used forces for objects on slopes. (2D)

On the slope there are (without friction) three forces:
Fz (the gravitational force, calculated by m*g where m = mass in kg and g = 9.81 m/s² (gravitatieconstante in Dutch))
Fn (the counter force of the slope, (n=normal) working on your object perpendicular to the slope)

and last the force that causes the sum of Fz and Fn to be 0
Fa (a=acceleration, I just came up with that it might be a bad name because its a force, but the force does cause the acceleration of the object)

attachment.php


Forces can be split up in x and y (and z, but this is still 2D)
Fz has no x so - Fa.y = Fz.y - Fn.y
and
Fa.x = Fn.x
I soon realized that Fn wasn't gonna help me...

So on to Sin, Cos and Tan ^^

the angle (from now on alpha) of the slope with y=0 is equal to the angle between the head of Fz and the object and the head of Fz and the head of Fa

We can use this if we have the length of Fz which we have> mass * 9.81

JASS:
sin(alpha) = |Fa|/|Fz|
so
|Fa| = |Fz| * sin(alpha)


then in the triangle of Fa, with its x and y we have the same angle alpha
and we can use this:
JASS:
Fa.x = cos(alpha) * |Fa|

(we only need the x coordinate because the y coordinate will be done automaticly when placing the unit)

now with those two we can make
JASS:

Fa.x = cos(alpha)*sin(alpha)*|Fz| = cos(alpha)*sin(alpha)*m*g


Hurray we got the x coordinate of the acceleration force/vector

now we need alpha:
if you have two points on the slope, p1, p2
then you can translate them so that p1 = (0,0), then p2 would be (delta(x), delta(y))... that doesn't make any sense

euhm

ok example
JASS:
p1(200, 40)
p2(210, 39)
delta(x) = 210-200 = 10
delta(y) = 39-40 = -1

yay another triangle <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite1" alt=":)" title="Smile    :)" loading="lazy" data-shortname=":)" />
tan(alpha) = 10/-1 = delta(x) / delta(y)
alpha = atan(d(x)/d(y))


now lets test it:
JASS:
p1(2,2)
p2(0,0)
m=10kg
g=9.81m/s²

alpha = atan(-2/-2) = atan(1) = 45 deg (BIG SURPRISE:O)
Fa.x = sin(45)*cos(45)*10*9.81 = 0.5 * 10 * 9.81 = 49.1 Newton


if you draw this on scale on a piece of paper you will see that I have been putting gibberish in my post the whole time or that the sum of all forces = 0 or that you aren't the king of drawing.

There is just one little problem... converting it to 3D
I'm currently freezing alive in my room because the window is open and i'm going to take a break. I'm not sure if I'm capable of doing this in 3D but I hope to have inspired somebody :)
 

Attachments

  • Forces.bmp
    30.7 KB · Views: 423

Prozix

New Member
Reaction score
7
Hmm i've been thinking of doing this in 3D and guess what: you need the normal ^^
btw, in your periodic function
JASS:
local xyz a = xyz.define(x,y+accuracy) //creating 3 vertices at (x+0,y+30),(x+30,y-30) and (x-30,y-30)
local xyz b = xyz.define(x+accuracy,y-accuracy) // to make a triangle
local xyz c = xyz.define(x-accuracy,y-accuracy) // and then find the normal of the triangle
local xyz vel = normal(a,b,c) //calculate normal
call counter()
call counter()
call counter()

don't you create 4 xyz structs? (doesn't fix a memory leak but still)

I need to make some calculations and check if my (maybe correct new) way of calculating the acceleration works...
 

aliminator8

New Member
Reaction score
3
Hmm i've been thinking of doing this in 3D and guess what: you need the normal ^^

This part here finds the normal
JASS:
local xyz a = xyz.define(x,y+accuracy) //creating 3 vertices at (x+0,y+30),(x+30,y-30) and (x-30,y-30)
local xyz b = xyz.define(x+accuracy,y-accuracy) // to make a triangle
local xyz c = xyz.define(x-accuracy,y-accuracy) // and then find the normal of the triangle
local xyz vel = normal(a,b,c) //calculate normal


Thanks also for the tips on physics i understand what you have said but how do you do it in 3d and incorporate gravity, mass, and friction. Perhaps i should make a 3d force system where i can apply vectors in any direction therefore if i apply gravity and normal forces it would result in the resultant, but im not really sure if thats correct.

Also the normal function counts its own leaks.
 

Prozix

New Member
Reaction score
7
Yeah I saw the normal calculation function. But I dislike it because I don't know why its supposed to work :p
JASS:
say we have 2 vectors:
v1 (2, 0 , 2) 
and
v2 (0, 1, 1)

If I use your function doing calculations in my head I get this normal:
(-2, -2, 0) which is not a correct one because
JASS:

v1*n = -4 + 0 + 0 = -4 and not 0
and
v2*n = 0 + 0 + 2 = 2 and not 0

however the calculation does work for (2, 3, 4) and (5, 6, 7): n=(-3, 6, -3)

back to v1 and v2
JASS:

v1 : 2a + 2c = 0
v2 : 1b + 1c = 0
lets say a = 1
c = -b
so 2*1 + 2c = 0
c = -2/2 = -1
b = 1
normal: (1, 1, -1)

v1 * normal = 1*2 + 1*0 + -1*2 = 0
v2 * normal = 1*0 + 1*1 + -1*1 = 0


so, maybe the normal function should be improved to take zero's in account.

Further more, my little scribble booklet has been filled with 4 pages of odd drawings, hurray. I think I've got a way to calculate the resultant vector if I have Fz and Fn (without friction, but friction can be applied rather easily by multipling the acceleration vector of an object by a number between 0 and 1)

JASS:

we have:
Fz = m*g
n = normal on the surface
alpha = angle between normal and the surface z=0
   =   atan (n.z/sqrt(n.x²+n.y²))

then we have a multiplication variable which i will call &quot;p&quot;
Fz.z = p * (n.z + n.z (tan(90-alpha)/tan(alpha)))
so p becomes
p = m * g / (n.z + n.z (tan(90-alpha)/tan(alpha)))
then 
Fres = p * n
so:
Fres.x = p * n.x
Fres.y = p * n.y
Fres.z = p * n.z


I'm sorry for the lack of explanation on how I got to the fancy formulas but my paint skills are not good enough to create images that make things clear, they would probably just confuse everyone.
 

Prozix

New Member
Reaction score
7
Normal function leak

Also the normal function counts its own leaks.

Are you sure?

JASS:
    call uncounter()
    call uncounter()

i see 3 counter()
and 2 uncounter()
so after a normal(...) call you need to call uncounter after destroying that normal vector, am I right?
 

aliminator8

New Member
Reaction score
3
JASS:

ation variable which i will call &quot;p&quot;
Fz.z = p * (n.z + n.z (tan(90-alpha)/tan(alpha)))
so p becomes
p = m * g / (n.z + n.z (tan(90-alpha)/tan(alpha)))
I dont quite understand what you are doing here.
Shouldn't the 90-alpha be PI - alpha?
since you are using tan and not TanBJ() and using radians would make more sense.
 

Prozix

New Member
Reaction score
7
I dont quite understand what you are doing here.
Shouldn't the 90-alpha be PI - alpha?
since you are using tan and not TanBJ() and using radians would make more sense.

I don't understand it either, and I'm 99% sure that it's incorrect.
I tend to use degrees because I'm an radian newb, but wouldn't 90Deg equal 1/4th of a circle so 2PI/4 = .5PI?

anyway I made a picture using paint and it rocks!

attachment.php
 

Attachments

  • Forces on a slope.GIF
    Forces on a slope.GIF
    8 KB · Views: 360

aliminator8

New Member
Reaction score
3
Thanks Prozix for the help, i think i understand now and i will try to recode/make a new vector system that will either add the normal + gravity vectors together, or calculate the resultant vector and add that, which ever one works better. will post up tomorrow afternoon... time to get some sleep :p
 

aliminator8

New Member
Reaction score
3
Thanks Prozix for the help, i think i understand now and i will try to recode/make a new vector system that will either add the normal + gravity vectors together, or calculate the resultant vector and add that, which ever one works better. will post up tomorrow afternoon... time to get some sleep :p

edit
- oh yeah you are right, instead of 90-alpha it should be pi/2 - alpha......
 

aliminator8

New Member
Reaction score
3
looks like its working alot better now with this code :)
JASS:
local unit u = gg_unit_hfoo_0000 //testing unit
local real x = GetUnitX(u)
local real alpha = 0 // angle between normal and z axis
local real mg = 98 //mass*gravity = 9.8*10
local real d // distance
local real y = GetUnitY(u)
local real z = GetLocationZ(GetUnitLoc(u))
local real xy = 0.00 // angle on xy plane
local real xytoz = 0.00 // angle of elevation
local xyz a = xyz.define(x,y+accuracy) //creating 3 vertices at (x+0,y+30),(x+30,y-30) and (x-30,y-30)
local xyz b = xyz.define(x+accuracy,y-accuracy) // to make a triangle
local xyz c = xyz.define(x-accuracy,y-accuracy) // and then find the normal of the triangle
local xyz vel = normal(a,b,c) //calculate normal
set alpha = 3.142/2-Atan((vel.z)/(SquareRoot((vel.x*vel.x)+(vel.y*vel.y))))
set d = SquareRoot((vel.x*vel.x) + (vel.y*vel.y) + (vel.z*vel.z))
call vel.scaler_divide(d)//unit vector normal
set d = mg*Cos(alpha)//normal size
call vel.scaler_divide(1/d) // convert normal unit vector --&gt; normal vector by mulitplying by its correct size (d)
////////
set a.x = 0 
set a.y = 0 //mass*grav vector
set a.z = mg
//////// 
call vel.add(a)
call cvel.add(vel)
/////////
set cvel.x = cvel.x / friction
set cvel.y = cvel.y / friction
call SetUnitX(u,GetUnitX(u)+(cvel.x/10))
call SetUnitY(u,GetUnitY(u)+(cvel.y/10))


and added some xyz methods

JASS:
struct xyz
//for handing points in 3d (x,y,z)
real x
real y
real z
    static method define takes real x, real y returns xyz
    local xyz vel = xyz.allocate()
    local real z1 = GetTerrainZ(x,y)
    call counter()
    set vel.x = x
    set vel.y = y
    set vel.z = z1
    return vel
    endmethod
    
    method add takes xyz a returns nothing
    set this.x = a.x + this.x
    set this.y = a.y + this.y
    set this.z = a.z + this.z
    endmethod
    
    method scaler_divide takes real r returns nothing
    set this.x = this.x/r
    set this.y = this.y/r
    set this.z = this.z/r
    endmethod
    
endstruct


still needs some tidying, but its working well. Now all i really need to to check for leaks and fix if its still leaking.
 

Prozix

New Member
Reaction score
7
Glad I could help ^^, I'm very interested in how this will end up! I would like to get a demo map if you happen to have that, or just the complete code if I may. Good luck (close to) perfectioning it :p
 

aliminator8

New Member
Reaction score
3
heres an example using the system http://www.epicwar.com/maps/120400/
and ill post code below too.

i apologize in advance for the monocode, tabs not working in the relpy window thing...
JASS:
function periodic takes nothing returns nothing
///////////////////////////////////////////new////////////////////
//////////////////////////////////////////////////////////////////
local unit u
local real x
local real alpha = 0 // angle between normal and z axis
local real mg
local real d 
local real y
local location l
local real z
local real array a
local real array b
local real array c
local real array norm 
local real temp
local integer i = 0 
loop
exitwhen i &gt; 10
set u = hero<i>
set x = GetUnitX(u)
set mg = 9.8*mass<i>
set y = GetUnitY(u)
set l = GetUnitLoc(u)
set z = GetLocationZ(l)
set a[0] = x
set a[1] = y+accuracy
set a[2] = GetTerrainZ(a[0],a[1])
set b[0] = x+accuracy
set b[1] = y-accuracy
set b[2] = GetTerrainZ(b[0],b[1])
set c[0] = x-accuracy
set c[1] = y-accuracy
set c[2] = GetTerrainZ(c[0],c[1])
set norm[0] = calc_normal_x(a[0],a[1],a[2],b[0],b[1],b[2],c[0],c[1],c[2])
set norm[1] = calc_normal_y(a[0],a[1],a[2],b[0],b[1],b[2],c[0],c[1],c[2])
set norm[2] = calc_normal_z(a[0],a[1],a[2],b[0],b[1],b[2],c[0],c[1],c[2])
set temp = SquareRoot((norm[0]*norm[0])+(norm[1]*norm[1]))
set temp = norm[2] / (temp+0.01)
set temp = Atan(temp)
set temp = (3.142/2) - temp
set alpha = temp
set d = SquareRoot((norm[0]*norm[0])+(norm[1]*norm[1])+(norm[2]*norm[2]))
set norm[0] = norm[0] / d
set norm[1] = norm[1] / d
set norm[2] = norm[2] / d
set d = mg*Cos(alpha) //normal size
set norm[0] = norm[0] * d
set norm[1] = norm[1] * d
set norm[2] = norm[2] * d
set norm[2] = norm[2] - mg
set force_bank<i>[0] = (force_bank<i>[0] + norm[0])/friction<i>
set force_bank<i>[1] = (force_bank<i>[1] + norm[1])/friction<i>
set force_bank<i>[2] = (force_bank<i>[2] + norm[2])/friction<i>

set vel_bank<i>[0] = (vel_bank<i>[0] + (force_bank<i>[0]/mass<i>)*period)/friction<i>
set vel_bank<i>[1] = (vel_bank<i>[1] + (force_bank<i>[1]/mass<i>)*period)/friction<i>
set vel_bank<i>[2] = (vel_bank<i>[2] + (force_bank<i>[2]/mass<i>)*period)/friction<i>
//f = ma, a = f/m
//v=u + at, t = (0.1, the period)
//and v = u + (f/m)t 
call SetUnitX(u,GetUnitX(u)+(vel_bank<i>[0]))
call SetUnitY(u,GetUnitY(u)+(vel_bank<i>[1]))
call RemoveLocation(l)
set i = i + 1
endloop
endfunction</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>


i stopped using structs and it stopped leaking...
 

Prozix

New Member
Reaction score
7
Played your map, and it works quite good.

In your code, you create the real z but I can't see where you actually use it.
 

Prozix

New Member
Reaction score
7
Hey I just coded my own ^^.
It's actually pretty funny.
I'm using structs but I don't know if it is leaking, I think it doesn't.
 

Attachments

  • Physics0.1Prot.w3x
    19.1 KB · Views: 257

aliminator8

New Member
Reaction score
3
yeh z wasnt working, but i dont really need it ;p
your system is awesome, for some reason my system seems to slow down real quick at uphill slopes...
 

Prozix

New Member
Reaction score
7
I haven't noticed that when testing your map:p
But I'm having a problem: I don't like the way my object gains momentum, for some reason it appears to be a 1 gram object and when going down a steep hill, it looks like it's 1000kg :O
Maybe I just need to do some balancing or something with the friction and weight. I can post my code if you want (I used your GetTerrainZ function but I used a locust, invunerable, no model, collision size=1, flying, unit to get the Z. It is way more. accurate because it doesn't get displaced. )
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top