An intriguing challenge with physics
Blitz3D Forums/Blitz3D Programming/An intriguing challenge with physics
Lets see if this is solvable! :)
Given two points in 2D (or 3D) space, we want to keep point two the same distance from point one, similar to simple string physics.
However as point one (p1) moves towards point two (p2), p2 will prefer to rotate around to mantain the distance rather than merely be pushed away. At no point will p1 be affected by p2 in the simulation.
Finally, p2 will be dragged into line and follow p1 if p1 moves away.
Can you envision the sort of simple physics problem I'm trying to explain? It shouldn't take much to affect only p2 (p1 is under manual control at all times) but it has me completely stumped!
SetBuffer BackBuffer()
mx# = MouseX()
my# = MouseY()
px# = mx + 100
py# = my
l# = 40.0
Repeat
Cls
mx# = MouseX()
my# = MouseY()
d# = Sqr((mx-px)^2 + (my-py)^2)
dx# = ((mx-px)/d)*l
dy# = ((my-py)/d)*l
px# = mx - dx
py# = my - dy
Line mx,my,px,py
Flip
Until KeyHit(1)
Will that do?
I think he wants it so that if you push the control point towards the child point, the child will swing round so that it is behind. (I think)
nearly perfect! I need to modify it so that it is more inclined to rotate about as you move closer - where do I do this?
thanks for the quick reply!
Well, that's what the code does :) (mostly) <-- In regards to pertubatio
found it thanks ;)
actually I got that wrong, here is the modified code that makes it turn more quickly and reponsive as we move closer:
d# = Sqr((mx-px)^2 + (my-py)^2)
If d#>l
dx# = ((mx-px)/d)*l
dy# = ((my-py)/d)*l
px# = mx - dx
py# = my - dy
ElseIf d#<l
a# = ATan2(mx-px,my-py)* 1.02
px# = mx + Sin(-a)*l
py# = my - Cos(-a)*l
End If
I just multiply a#
however it really jitters badly if you go up then down - any idea how to fix?
pertubatio's right when you get a situation where you move towards it exactly - the point moves away. Any idea how to fix this would be appreciated :)
Throw in a little randomness?
No, because you need to continue the randomness.
http://mathworld.wolfram.com/Circle-CircleIntersection.htmlA is your first point.
B is the point that should circle it.
C is the point you move A to.
D is the point to which B should move to.
R is the distance between point A and B.
E is a circle centered at point A, with radius R.
F is a circle centered at point C, with radius R.
Find the point(s) where circles E and F intersect.
If the circles intersect at one point, that point is point D.
If the circles intersect at two points, determine the squared distance of each from point B. Choose the one with the smaller squared distance. That is point D.
If the circles intersect at an imaginary point, subtract point A from point C to create a vector, calculate the length of the vector, divide the vector by it's length, and then multiply by R. That is point D.
I think.
Thats too complex for me. I'm doing a little bit of begging here, can someone help? :)
It's too complex for me too. That's why I didn't explain how to do it in code. :-)
I'm not sure how to calculate the intersections given those equations on that site.
SetBuffer BackBuffer()
mx# = MouseX()
my# = MouseY()
px# = mx + 100
py# = my
l# = 40.0
Angle# = 180
Repeat
Cls
mx# = MouseX()
my# = MouseY()
d# = Sqr((mx-px)^2 + (my-py)^2)
dx# = ((mx-px)/d)*l+Sin(Angle)*3
dy# = ((my-py)/d)*l+Cos(Angle)*3
px# = mx - dx
py# = my - dy
Line mx,my,px,py
Flip
Until KeyHit(1)
hm? :\
Um... Isn't this really really simple?
Graphics3D 640,480,16,2
MoveMouse 320,240
b1=CreateCube()
b2=CreateCube()
camera=CreateCamera()
MoveEntity camera,0,0,-20
Repeat
x#=(MouseX()-320)*.065
y#=(-MouseY()+240)*.065
PositionEntity b1,x,y,0
; the complex maths bit
PointEntity b2,b1
MoveEntity b2,0,0,EntityDistance(b1,b2)-5 ;where 5 is how far away you want it to be
UpdateWorld
RenderWorld
Flip
Until KeyHit(1)
I can still push the child around by the parent moving directly towards it.
cool piece of code, any area of use for this?
The challenge is still open as no-one has been able to solve it by rotation only as you move towards it. Moving away always pulls it into line when dragged - thats easy.
It's the rotation that has us stumped.
dudes, how aboud adding more objects, so instead of 2 we have several more?
I can see this in a commercial game:
YOU take the role as a farmer and will drive your tractor with an other vehicle attached to it:
You'll have to drive it around your farm from the garrage to certain fields to collect certain crops, coming back to garrage to change the second vehicle being different depending on the type of the crop you wish to collect.
I know - it's a hit.
=)
Lets just solve the current problem, yeah? The point of this post is to find out how to rotate a single point around another as you move towards it instead of simply pushing it away.
I know you mean well, but I'm fustrated at the moment trying to get it working :)
Graphics3D 640,480,16,1
MoveMouse 320,240
b1=CreateCube()
b2=CreateCube()
camera=CreateCamera()
MoveEntity camera,0,0,-20
Repeat
x#=(MouseX()-320)*.065
y#=(-MouseY()+240)*.065
PositionEntity b1,x,y,0
d#=EntityDistance(b1,b2)-5
PointEntity b2,b1
; this bit makes it rotate rather than move backwards
If d<0 Then MoveEntity b2,-.1,0,0:d#=EntityDistance(b1,b2)-5
MoveEntity b2,0,0,d
UpdateWorld
RenderWorld
Flip
Until KeyHit(1)
SetBuffer BackBuffer()
mx# = MouseX()
my# = MouseY()
px# = mx + 100
py# = my
l# = 40.0
Repeat
Cls
lmx# = mx#
lmy# = my#
mx# = MouseX()
my# = MouseY()
smx# = lmx-mx
smy# = lmy-my
d# = Sqr((mx-px)^2 + (my-py)^2)
If d<l
a# = ATan2(smx,smy)-ATan2(px-mx,py-my)
dx# = Sin(a)
dy# = Cos(a)
px = px + dy
py = py - dx
d# = Sqr((mx-px)^2 + (my-py)^2)
End If
dx# = ((mx-px)/d)*l
dy# = ((my-py)/d)*l
px# = mx - dx
py# = my - dy
Line mx,my,px,py
Flip
Until KeyHit(1)
Perfect Mk.III? :)
Nice one dr av!
Close, very close Fredborg, but no cigar! the line doesn't take the path of least resistance, it always attempts to rotate clockwise... can you fix it? :)
Check above, I changed it. Better?
It's the same as before! I'm not trying to annoy the hell out of you... but it would be nice, very nice :) in fact I'll even knock out some screenshots to say thanks if you get it working :)
Basically, it doesn't seem to take the shortest rotation.
This I gotta see :) Check above again!
Fredborg: It looks almost right, but if you have the line pointing to the left and move left against the child, it doesn't rotate :/
SetBuffer BackBuffer()
mx# = MouseX()
my# = MouseY()
px# = mx + 100
py# = my
l# = 40.0
f# = 2.0
Repeat
Cls
lmx# = mx#
lmy# = my#
mx# = MouseX()
my# = MouseY()
smx# = mx-px+((mx-lmx)*f)
smy# = my-py+((my-lmy)*f)
d# = Sqr(smx*smx + smy*smy)
px# = mx - ((smx/d)*l)
py# = my - ((smy/d)*l)
Line mx,my,px,py
Flip
Until KeyHit(1)
Divine Mk. I! :)
Adjust f# to set how fast it turns!
That seems to be doing it.
Ohhh he's done it! Simply Divine!
See? Thats what you get if you buy gile[s]! Everyone BUY it today ;)
Now gimme dem skweens! :D
lol ok
Ok, I've been suckered, I'm buying gile[s]... I'll call it my christmas present to myself :)
*EDIT*
But I expect lots of physics help too :)
Baaah ;) You're registration code has been sent! Enjoy :)
Why is it the simplest things are the most amusing ?
It's also strange that these seemingly simple physic kind of problems are quite the challange to implement unless you have a firm grip on this kind of thing.
It's also these seemingly simple things, when combined with other simple elements, tend to really bring a sense of realism. LifeForce/Salamander/Gradius/Nemesis have several of these kind of things that always boggled my mind to no end.
Fredborg, Have you ever played/seen the Gradius series set of games. If so, you know the segmented arms that slowly move towards the player but the whole thing is locked down at it the base by the final segment ?
Any chance you having a little more Holiday cheer in your bag of tricks and knocking that little bugger up ?
Lastly, any recommended math/physics readings?
Dr. is it something like this?
SetBuffer BackBuffer()
Type arm
Field x#,y#
Field s#,l#
Field parent.arm
End Type
parm.arm = Null
;
; s# indicates how fast each joint can turn
s# = 0.02
For i = 0 To 5
arm.arm = New arm
arm\parent = parm
If parm = Null
arm\x = 200
arm\y = 150
End If
arm\l = 20.0
arm\s = s#
;
; Set the next arm's parent to be this one
parm = arm
;
; Increase s# for each new arm
s# = s# * 1.5
Next
Repeat
Cls
a# = a+2.0
tx# = MouseX()
ty# = MouseY()
For arm.arm = Each arm
If arm\parent<>Null
;
; Vector between this arm's joint and the mouse
dx# = tx-arm\x
dy# = ty-arm\y
d# = Sqr(dx*dx + dy*dy)
If d = 0 Then d = 1.0
dx# = arm\parent\x+((dx/d)*arm\l)
dy# = arm\parent\y+((dy/d)*arm\l)
;
; Turn the arm to be closer to the mouse
arm\x = arm\x-(arm\parent\x-dx)*arm\s
arm\y = arm\y-(arm\parent\y-dy)*arm\s
;
; Make sure the arm doesn't change length
dx# = arm\x-arm\parent\x
dy# = arm\y-arm\parent\y
d# = Sqr(dx*dx + dy*dy)
If d = 0 Then d = 1.0
arm\x# = arm\parent\x+((dx/d)*arm\l)
arm\y# = arm\parent\y+((dy/d)*arm\l)
;
; Draw the arm
Oval arm\x-2,arm\y-2,5,5,True
Line arm\x,arm\y,arm\parent\x,arm\parent\y
Else
;
; Just move the first joint around in a circle
arm\x = 200+(Sin(a)*20.0)
arm\y = 150+(Cos(a)*20.0)
Oval arm\x-6,arm\y-6,13,13,False
Oval arm\x-2,arm\y-2,5,5,True
End If
Next
Flip
Until KeyHit(1)
End
And the funny thing is I don't really know what I'm doing either :) I don't really know about any books, just get some basic maths books about vectors, they will get you far if you are interested in it!
This is even more fun :D
Graphics 640,480,0,2
SetBuffer BackBuffer()
Type arm
Field x#,y#
Field s#,l#,al#
Field parent.arm
End Type
parm.arm = Null
For i = 0 To 10
arm.arm = New arm
arm\parent = parm
; Origin of the first arm
If parm = Null
arm\x = GraphicsWidth()/2.0
arm\y = GraphicsHeight()/2.0
End If
; Set the length of this arm
arm\l = 20.0
; Set the speed at which this arm can turn
arm\s = (i+1)/50.0
; angular limit
arm\al = Sqr(arm\l*arm\l + arm\l*arm\l)*1.5
; Set the next arm's parent to be this one
parm = arm
Next
Repeat
Cls
tx# = MouseX()
ty# = MouseY()
For arm.arm = Each arm
If arm\parent<>Null
;
; Vector between this arm's joint and the mouse
dx# = tx-arm\x
dy# = ty-arm\y
d# = Sqr(dx*dx + dy*dy)
If d = 0 Then d = 1.0
dx# = arm\parent\x+((dx/d)*arm\l)
dy# = arm\parent\y+((dy/d)*arm\l)
;
; Turn the arm to be closer to the mouse
arm\x = arm\x-(arm\parent\x-dx)*arm\s
arm\y = arm\y-(arm\parent\y-dy)*arm\s
;
; Make sure the arm doesn't change length
dx# = arm\x-arm\parent\x
dy# = arm\y-arm\parent\y
d# = Sqr(dx*dx + dy*dy)
If d = 0 Then d = 1.0
arm\x# = arm\parent\x+((dx/d)*arm\l)
arm\y# = arm\parent\y+((dy/d)*arm\l)
;
; Limit angle
If arm\parent\parent <> Null
dx# = arm\x-arm\parent\parent\x
dy# = arm\y-arm\parent\parent\y
d# = Sqr(dx*dx + dy*dy)
If d>0.0
If d#<arm\al
arm\x# = arm\parent\parent\x+((dx/d)*arm\al)
arm\y# = arm\parent\parent\y+((dy/d)*arm\al)
End If
End If
End If
;
; Draw the arm
Oval arm\x-2,arm\y-2,5,5,True
Line arm\x,arm\y,arm\parent\x,arm\parent\y
Else
;
; The first joint/arm
Oval arm\x-6,arm\y-6,13,13,False
Oval arm\x-2,arm\y-2,5,5,True
End If
Next
Flip
Until KeyHit(1)
End
thats ultra-cool :D
You can achieve the "swing around to the back" thingy by using verletphysics as well.
Just apply gravity to Point 2 that is opposite to Point 1's velocity.
This way you could make a very cool camera tracking thingy that tries to stay behind the player and if the player turns towards the camera and start walking at it, the camera swings around. The swing around behaviour can be controlled by setting different gravity and damping values.
The camera will also "climb the walls" if the camera is cornered and collision against walls is applied.
That is cool. You could make an octopus simulator with that :)
Sweenie, thats what it's for ;)
Rob, In that case try the verletcamera thingy, You won't be disappointed. :)
Where is the verletcamera thingy ? :)
sorry, I made it sound like there was a finished verletcamera solution.
The only one I've seen in action, is the one lurking around in some of my own half-finished games.
But it's very easy to get it up and running.
Just add the verlet code, add two verlets and put a constraint between them.
Then attach the first verlet to the object you want the camera to follow and attach the camera to the second verlet.
You know what, I think i will make an example and add it to the codearchives instead. :)
Chop chop :)
Ahh! I love it! That IS 'ultra cool' thanks.