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

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.