An intriguing challenge with physics

Blitz3D Forums/Blitz3D Programming/An intriguing challenge with physics

Rob(Posted 2003) [#1]
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!


fredborg(Posted 2003) [#2]
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?


Perturbatio(Posted 2003) [#3]
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)


Rob(Posted 2003) [#4]
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!


fredborg(Posted 2003) [#5]
Well, that's what the code does :) (mostly) <-- In regards to pertubatio


Rob(Posted 2003) [#6]
found it thanks ;)


Rob(Posted 2003) [#7]
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?


Rob(Posted 2003) [#8]
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 :)


WolRon(Posted 2003) [#9]
Throw in a little randomness?


Rob(Posted 2003) [#10]
No, because you need to continue the randomness.


sswift(Posted 2003) [#11]
http://mathworld.wolfram.com/Circle-CircleIntersection.html

A 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.


Rob(Posted 2003) [#12]
Thats too complex for me. I'm doing a little bit of begging here, can someone help? :)


sswift(Posted 2003) [#13]
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.


ShadowTurtle(Posted 2003) [#14]
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? :\


Rob Farley(Posted 2003) [#15]
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)



Perturbatio(Posted 2003) [#16]
I can still push the child around by the parent moving directly towards it.


BerhanK(Posted 2003) [#17]
cool piece of code, any area of use for this?


Rob(Posted 2003) [#18]
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.


BerhanK(Posted 2003) [#19]
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.

=)


Rob(Posted 2003) [#20]
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 :)


Rob Farley(Posted 2003) [#21]
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)



fredborg(Posted 2003) [#22]
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? :)


Rob(Posted 2003) [#23]
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? :)


fredborg(Posted 2003) [#24]
Check above, I changed it. Better?


Rob(Posted 2003) [#25]
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.


fredborg(Posted 2003) [#26]
This I gotta see :) Check above again!


Perturbatio(Posted 2003) [#27]
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 :/


fredborg(Posted 2003) [#28]
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!


Perturbatio(Posted 2003) [#29]
That seems to be doing it.


Rob(Posted 2003) [#30]
Ohhh he's done it! Simply Divine!

See? Thats what you get if you buy gile[s]! Everyone BUY it today ;)


fredborg(Posted 2003) [#31]
Now gimme dem skweens! :D


Rob(Posted 2003) [#32]
lol ok


Perturbatio(Posted 2003) [#33]
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 :)


fredborg(Posted 2003) [#34]
Baaah ;) You're registration code has been sent! Enjoy :)


CyberPackRat(Posted 2003) [#35]
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?


fredborg(Posted 2003) [#36]
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!


fredborg(Posted 2003) [#37]
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



Rob(Posted 2003) [#38]
thats ultra-cool :D


Sweenie(Posted 2003) [#39]
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.


Perturbatio(Posted 2003) [#40]
That is cool. You could make an octopus simulator with that :)


Rob(Posted 2003) [#41]
Sweenie, thats what it's for ;)


Sweenie(Posted 2003) [#42]
Rob, In that case try the verletcamera thingy, You won't be disappointed. :)


Rob(Posted 2003) [#43]
Where is the verletcamera thingy ? :)


Sweenie(Posted 2003) [#44]
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. :)


Rob(Posted 2003) [#45]
Chop chop :)


CyberPackRat(Posted 2003) [#46]
Ahh! I love it! That IS 'ultra cool' thanks.