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
|