some math help please?


Forum: Programming and Scripting
Topic: some math help please?
started by: mikshaw

Posted by mikshaw on Jan. 23 2008,00:42
I don't know how to describe this issue concisely, so that would explain the crappy title. Sorry.

Also, this is a cross-post from the murgaLua forums.  I know there are some brilliant minds here so I'm trying to increase my odds of finding a solution.

Quote

I've been messing around with a "gravity" test today, and although I came up with something cool to look at, it's not what I was trying for.

I can get the x,y position of the mouse, the x,y position of the object I want to move, and from there get the distance between the two points:
xdistance=math.abs(Fl:event_x()-object:x())
ydistance=math.abs(Fl:event_y()-object:y())
distance=math.sqrt(xdistance*xdistance+ydistance*ydistance)

What I would really like to do now is use that distance as a way to increase the motion of the object toward the mouse as the distance gets shorter. Essentially I'm looking for a single (floating point?) value that gradually increases as distance decreases. The problems I'm having are as follows:
1) I suck at math
2) The target speed should get larger as the distance gets smaller
3) The target speed should always be a fairly small non-negative number

Is there anyone who might be able to help?
Thanks.

Posted by mikshaw on Jan. 23 2008,01:53
I got a quick answer from Juergen on the murgaLua forum that seems to fit nicely:
speed=<minimum speed>+<maximum speed>/distance

This is really cool!

Posted by roberts on Jan. 23 2008,05:48
Please post it. We want to see it too.
Posted by mikshaw on Jan. 23 2008,13:32
I posted beta1 of the murgaLua widgets collection last night, over at Murga's place, and the 3 stages of gravity tests up to this point have been included.

I still want to improve it over time, maybe turn it into some sort of interactive screensaver thing, and have to work out some kinks.

Code Sample
#!/bin/murgaLua

balls=250
bsize=10

function grav_loop()
local my_x,bx=Fl:event_x(),0
local my_y,by=Fl:event_y(),0
local c=math.random(1,255)
local b=math.random(1,balls)
ball[b]:color(c)
 for i=1,balls do
   local xdistance=math.abs(my_x-ball[i]:x())
   local ydistance=math.abs(my_y-ball[i]:y())
   local distance=math.sqrt(xdistance*xdistance+ydistance*ydistance)
   local speed=max_slider:value()/distance
   if distance > 0 then
     if my_x > ball[i]:x() then
       bx=ball[i]:x()+speed
     else
       bx=ball[i]:x()-speed
     end
     if my_y > ball[i]:y() then
       by=ball[i]:y()+speed
     else
       by=ball[i]:y()-speed
     end
     ball[i]:position(bx,by)
   end
 end
w:redraw()
grav_timer:doWait(.05)
end

w=fltk:Fl_Double_Window(640,480,"gravity test")
w:color(0)
fltk.fl_define_FL_OVAL_BOX()
math.randomseed(os.time())
max_x=w:w()-bsize
max_y=w:h()-bsize
ball={}
for i=1,balls do
ball[i]=fltk:Fl_Box(math.random(1,max_x),math.random(1,max_y),bsize,bsize)
if fltk._FL_OFLAT_BOX then ball[i]:box(fltk._FL_OFLAT_BOX) else ball[i]:box(fltk.FL_OFLAT_BOX) end
end

max_slider=fltk:Fl_Hor_Value_Slider(0,w:h()-20,w:w(),20)
max_slider:minimum(50)
max_slider:maximum(5000)
max_slider:value(500)
max_slider:step(10)

grav_timer = murgaLua.createFltkTimer()
grav_timer:callback(grav_loop)
grav_timer:do_callback()

w:show()
Fl:run()

Edit: I replaced the plastic with a flat oval box after seeing how poorly it runs in fullscreen

Posted by ^thehatsrule^ on Jan. 23 2008,16:51
Interesting use of murgalua...  looking good.  Took a quick look.

misc. math note:
since you're taking the squares of the distance, you don't need to take the absolute values of each component (unless you prefer to keep it consistent with the variable name)

Also, it seems that there is always a gravity point at the top left corner (0,0)?

Posted by mikshaw on Jan. 23 2008,20:03
Quote
since you're taking the squares of the distance, you don't need to take the absolute values of each component
I didn't know that. Thanks.
EDIT: seems like it is needed after a quick test

Quote
Also, it seems that there is always a gravity point at the top left corner (0,0)?
I'd seen that in other tests as well. Since I don't know real math, I just ignored that. I think I've got that fixed, though, as well as the problem with all objects always moving at 45 degree angles.

I messed around with the numbers for a while and came up with something else I like. So far I see one problem with it, that the objects gravitate toward a single x,y intersection over time if you don't move the mouse.
Code Sample
balls=1500
bsize=2
min_grav=0
max_grav=6

function grav_loop()
local my_x,bx=Fl:event_x(),0
local my_y,by=Fl:event_y(),0
local c=math.random(1,255) -- random color
 for i=1,balls do
   local xdistance=math.abs(my_x-ball[i]:x())
   local ydistance=math.abs(my_y-ball[i]:y())
   local distance=math.sqrt(xdistance*xdistance+ydistance*ydistance)
   local xspeed=(min_grav+max_grav)/distance*xdistance
   local yspeed=(min_grav+max_grav)/distance*ydistance
   if distance <= 25 then -- warp it offscreen
     ball[i]:color(c)
     xspeed=xspeed*max_x/distance*math.random(2,3)
     yspeed=yspeed*max_y/distance*math.random(2,3)
   end      
   if my_x > ball[i]:x() then bx=ball[i]:x()+xspeed else bx=ball[i]:x()-xspeed end
   if my_y > ball[i]:y() then by=ball[i]:y()+yspeed else by=ball[i]:y()-yspeed end
   ball[i]:position(bx,by)
 end
w:redraw()
grav_timer:doWait(.05)
end

w=fltk:Fl_Double_Window(Fl:w(),Fl:h(),"gravity test")
w:color(0)

math.randomseed(os.time())
max_x=w:w()-bsize
max_y=w:h()-bsize
ball={}
for i=1,balls do
ball[i]=fltk:Fl_Box(math.random(1,max_x),math.random(1,max_y),bsize,bsize)
ball[i]:box(fltk.FL_FLAT_BOX)
end

grav_timer = murgaLua.createFltkTimer()
grav_timer:callback(grav_loop)
grav_timer:do_callback()

w:fullscreen()
w:show()
Fl:run()

EDIT: fixed a typo

Posted by curaga on Jan. 23 2008,20:20
Quote
I messed around with the numbers for a while and came up with something else I like. So far I see one problem with it, that the objects gravitate toward a single x,y intersection over time if you don't move the mouse.
If you could decide that point, it could be desired behavior. I suggest setting it to the center of the display.

Posted by mikshaw on Jan. 23 2008,20:25
That wouldn't be very useful, though, If this turns into something I might want to use as a screensaver.  When I say an intersection, I mean all objects gravitate to travelling along either a single x coordinate or a single y coordinate, so what you have on screen is essentially just two lines that intersect at the location of the cursor.
Posted by ^thehatsrule^ on Jan. 23 2008,20:37
Quote (mikshaw @ Jan. 23 2008,15:03)
Quote
since you're taking the squares of the distance, you don't need to take the absolute values of each component
I didn't know that. Thanks.
EDIT: seems like it is needed after a quick test

That was just for your first one where you only used the direct distance.

Your 2nd one is looking better too - but seeing the same problems that you have described.

Took at look at your 2nd one... not sure if you already have something like this:
Code Sample
-- snip
  local yspeed=(min_grav+max_grav)/distance*ydistance
-- cut out if statement
  if my_x > ball[i]:x() then bx=ball[i]:x()+xspeed else bx=ball[i]:x()-xspeed end
  if my_y > ball[i]:y() then by=ball[i]:y()+yspeed else by=ball[i]:y()-yspeed end
-- add back warp
  if distance <= 25 then -- warp it
    ball[i]:color(b)
    bx = math.random(1,max_x)
    by = math.random(1,max_y)
  end
-- /snip
This doesn't make the new dots offscreen though... did you want to specifically do that?

Posted by mikshaw on Jan. 23 2008,20:59
Quote
This doesn't make the new dots offscreen though... did you want to specifically do that?
Yeah, It pretty much just shoots them forward a ways, but I don't really understand how much. It looks like somewher between halfway across the screen to waaay outside the screen.  I'm working on a different method now that should place them just offscreen and also hopefully cut down on the processing a little.

Posted by ^thehatsrule^ on Jan. 23 2008,21:10
Well at least the one based on my last "patch" doesn't seem to have the "line-grav" anymore...
Code Sample
-- based on last code "patch"
 if distance <= 25 then -- warp it offscreen
   ball[i]:color(b)
-- delete old 2 lines, add
   if math.random(0,1) == 0 then
      bx = math.random(0,1)*max_x
      by = math.random(1,max_y)
   else
      bx = math.random(1,max_x)
      by = math.random(0,1)*max_y
   end
 end
This one make them warp offscreen, but looks 'square-ish' unless you add an additional offset to it (due to choosing a coordinate on the edges of the window box).  Not sure how many random()'s you'd want to use.

My previous post's warp just copied the random code that was used at the start where it chooses a coordinate anywhere in the window.

Posted by mikshaw on Jan. 23 2008,21:58
Quote
This one make them warp offscreen, but looks 'square-ish' unless you add an additional offset to it (due to choosing a coordinate on the edges of the window box).  Not sure how many random()'s you'd want to use.
That's exactty the issue I was trying to solve from my most recent test (I'm up to version "3e" now)

btw, color(b) is a typo. The b variable was a leftover from a previous script. The color should be c

Posted by roberts on Jan. 23 2008,22:41
mikshaw, Thanks for posting/sharing. It is really cool!
Posted by spark-o-matic on Jan. 30 2008,06:49
I have played with things like this on and off dating back to 1992.
One thing i like to do is use sin() to move the object more slowly as it reaches its objective or move it in a non-strait line.  logrithems behave similarly but a different pattern.
i also like to reposition the object to a random location at a random time with the odds of it being repositioned increasing as it gets closer to the objective.  this can be done with a simple
Code Sample
(Distance From Objective) < (Random Number)

And this random number would not need to be generated again until the object reaches it.  This can reduce the number of objects close together where their all headed to.
You can also weight the occurences of where it is repositioned(maybe you want more to end up at the edge of the screen).

Sorry this is pretty general, but i dont recognise enough of the sytnax to give good code.  maybe it might give you some ideas.

sparks

Powered by Ikonboard 3.1.2a
Ikonboard © 2001 Jarvis Entertainment Group, Inc.