En dépit des apparences, cela n'a rien à voir avec le double pendule.
C'est ce qui est utilisé (dans le principe) en modélisation 3D pour bouger un squelettes ou pour animer un bras robotique en le déplaçant par son extrémité.
Code : Tout sélectionner
#x=600:#y=400
#nbBones=5 ;nombres de segments
#lengthBone=50 ;longueur des segments
#FixX=#X/2:#FixY=#Y/2 ;Coordonnées du point fixe
If InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0 Or OpenWindow(0, 0, 0, #X, #Y, "Backward kinematic", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)=0 Or OpenWindowedScreen(WindowID(0),0,0,#X,#Y,0,0,0,#PB_Screen_WaitSynchronization)=0
MessageRequester("Error", "Can't open the sprite system", 0)
End
EndIf
Structure Bone
x1.i
y1.i
x2.i
y2.i
length.i
Angle.f
EndStructure
NewList Bone.Bone()
Procedure AddBone(List Bone.Bone(),length.i,angle.f)
If ListIndex(Bone())=-1
AddElement(Bone())
Bone()\x1=#FixX
Bone()\y1=#FixY
Else
xold.i=Bone()\x2
yold.i=Bone()\y2
AddElement(Bone())
Bone()\x1=xold
Bone()\y1=yold
EndIf
Bone()\Angle=angle:Bone()\length=length
Bone()\x2=Bone()\x1+Bone()\length*Cos(angle)
Bone()\y2=Bone()\y1+Bone()\length*Sin(angle)
EndProcedure
Procedure follow(List Bone.Bone(),targetX.i,targetY.i)
Bone()\Angle=ATan2(targetX-Bone()\x1,targetY-Bone()\y1)
Bone()\x2=Bone()\x1+Bone()\length*Cos(Bone()\Angle)
Bone()\y2=Bone()\y1+Bone()\length*Sin(Bone()\Angle)
a.i=Bone()\x2-Bone()\x1
b.i=Bone()\y2-Bone()\y1
Bone()\x2=targetx
Bone()\y2=targety
Bone()\x1=targetx-a
Bone()\y1=targety-b
EndProcedure
Procedure Update(List Bone.Bone(),xold.i,yold.i)
If LastElement(Bone())
Repeat
follow(Bone(),xold,yold)
xold=Bone()\x1
yold=Bone()\y1
Until PreviousElement(Bone())=0
;shift back to fix point
deltax.i=Bone()\x1-#FixX
deltay.i=Bone()\y1-#FixY
ForEach Bone()
Bone()\x1-deltax
Bone()\y1-deltay
Bone()\x2-deltax
Bone()\y2-deltay
Next
EndIf
EndProcedure
;create some bones...
For i=1 To #nbBones
AddBone(Bone(),#lengthBone,Radian(-90))
Next i
Dx.i=2:Dy.i=2:x.i=Random(#X):y.i=Random(#Y)
Repeat
FlipBuffers()
ClearScreen(RGB(0,0,0))
ExamineKeyboard()
;bouncing box
If x>#x Or x<0:Dx=-Dx:EndIf
If y>#y Or y<0:Dy=-Dy:EndIf
x+Dx:y+Dy
Update(Bone(),x,y)
StartDrawing(ScreenOutput())
Circle(x,y,10,#Red)
ForEach Bone()
LineXY(Bone()\x1,Bone()\y1,Bone()\x2,Bone()\y2,#Blue)
Circle(Bone()\x2,Bone()\y2,2,#White)
Next
Circle(#FixX,#FixY,3,#Green)
StopDrawing()
Repeat:Event = WindowEvent():If event= #PB_Event_CloseWindow:End:EndIf:Until event=0
Until KeyboardPushed(#PB_Key_Escape)