TViewport3Dとジョイスティックでドローン操縦シミュレーション作成(FMX) ~Delphiソースコード集
DelphiのTViewport3Dでドローン操縦シミュレーション3Dアプリケーションを作成します。
ドローンの操縦はジョイスティック(ゲームパッド)で行いますので、パソコンのUSBに接続して使用します。
- 左スティック
- 上下で上昇と下降、左右は左右回転
- 右スティック
- 前後左右に平行移動
Delphiを起動して新規作成を行い、必要なコンポーネントをドラッグ&ドロップする
Delphi起動⇒ファイル⇒新規作成⇒マルチデバイスアプリケーションを選択し、「空のアプリケーション」を選択してOKボタンをクリックします。
TTimer、TViewPort3Dをフォームへドラッグ&ドロップします。
ソースコードを記述する
Form1のイベントonCreateイベントとTimer1のonTimerイベントに以下のソースコードを記述します。
unit Unit1; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Viewport3D, FMX.MaterialSources, FMX.Controls.Presentation, FMX.Edit, System.Math.Vectors, FMX.Controls3D, FMX.Objects3D, FMX.Types3D; type TDronePos=record x,y,z:Single; vx,vy,vz:Single; turn:Single; end; TForm1 = class(TForm) Viewport3D1: TViewport3D; Timer1: TTimer; procedure Timer1Timer(Sender: TObject); procedure FormCreate(Sender: TObject); private { private 宣言 } grid:TGrid3D; cam:TCamera; mat0,mat1,mat2,mat3,mat4:TLightMaterialSource; light:TLight; drone:TDummy; r1,r2,r3,r4:TDummy; shadow:TDisk; pos:TDronePos; public { public 宣言 } end; var Form1: TForm1; const DF=32767; implementation uses Winapi.MMSystem, DirectInput; {$R *.fmx} procedure TForm1.FormCreate(Sender: TObject); var mesh:TCustomMesh; begin //軸方向 X:→、Y:↓、Z:奥方向 Timer1.Interval:=33; pos.x:=0; pos.y:=0; pos.z:=0; pos.vx:=0; pos.vy:=0; pos.vz:=0; pos.turn:=0; //材質(マテリアル)設定 mat0:=TLightMaterialSource.Create(self); mat1:=TLightMaterialSource.Create(self); mat1.Diffuse:=$FF000000; mat2:=TLightMaterialSource.Create(self); mat2.Diffuse:=$FFFF0000; mat3:=TLightMaterialSource.Create(self); mat3.Diffuse:=$FF0000FF; mat4:=TLightMaterialSource.Create(self); mat4.Diffuse:=$FF888888; //カメラの設置 cam:=TCamera.Create(self); cam.Parent:=Viewport3D1; cam.Position.SetPoint3DNoChange(Point3D(0,-50,-50)); cam.RotationAngle.X:=-45; Viewport3D1.Camera:=cam; Viewport3D1.UsingDesignCamera:=False; //点光源の設置 light:=TLight.Create(self); light.Parent:=Viewport3D1; light.LightType:=TLightType.Point; light.Position.X:=50; light.Position.Y:=-2000; light.Position.Z:=-100; light.Color:=TAlphaColorRec.White; light.Color:=$FFDDDDDD; light.Visible:=true; light.Enabled:=True; //グリッドの設置 grid:=TGrid3D.Create(self); grid.Parent:=Viewport3D1; grid.Width:=1000; grid.Height:=1000; grid.RotationAngle.X:=90; grid.Position.Y:=1; grid.LineColor:=$FF999999; //ドローン本体 drone:=TDummy.Create(self); drone.Parent:=Viewport3D1; mesh:=TCylinder.Create(self); TCylinder(mesh).Height:=4; TCylinder(mesh).Width:=10; TCylinder(mesh).Depth:=10; TCylinder(mesh).Position.Y:=-4; TCylinder(mesh).MaterialSource:=mat0; mesh.Parent:=drone; //ドローンのローターへの棒 mesh:=TCube.Create(self); TCube(mesh).Height:=1; TCube(mesh).Width:=20; TCube(mesh).Depth:=1; TCube(mesh).MaterialSource:=mat0; TCube(mesh).Position.Y:=-5.5; TCube(mesh).RotationAngle.Y:=45; mesh.Parent:=drone; mesh:=TCube.Create(self); TCube(mesh).Height:=1; TCube(mesh).Width:=20; TCube(mesh).Depth:=1; TCube(mesh).MaterialSource:=mat0; TCube(mesh).Position.Y:=-5.5; TCube(mesh).RotationAngle.Y:=-45; mesh.Parent:=drone; //ドローンの後ろ側を示す赤いキューブ mesh:=TCube.Create(self); mesh.Parent:=drone; TCube(mesh).Height:=1; TCube(mesh).Width:=1; TCube(mesh).Depth:=1; TCube(mesh).MaterialSource:=mat2; TCube(mesh).Position.Y:=-5.0; TCUbe(mesh).Position.Z:=-5; //ドローンの前側を示す青いキューブ mesh:=TCube.Create(self); mesh.Parent:=drone; TCube(mesh).Height:=1; TCube(mesh).Width:=1; TCube(mesh).Depth:=1; TCube(mesh).MaterialSource:=mat3; TCube(mesh).Position.Y:=-5.0; TCUbe(mesh).Position.Z:=5; //ドローンの左奥ローター r1:=TDummy.Create(self); r1.Parent:=drone; r1.Position.X:=-7; r1.Position.Y:=-6; r1.Position.Z:=7; mesh:=TCube.Create(self); TCube(mesh).Height:=0.6; TCube(mesh).Width:=12; TCube(mesh).Depth:=0.6; TCube(mesh).RotationAngle.Y:=0; TCube(mesh).MaterialSource:=mat0; TCube(mesh).Parent:=r1; mesh:=TCube.Create(self); TCube(mesh).Height:=0.6; TCube(mesh).Width:=12; TCube(mesh).Depth:=0.6; TCube(mesh).RotationAngle.Y:=90; TCube(mesh).MaterialSource:=mat0; TCube(mesh).Parent:=r1; //ドローンの右奥ローター r2:=TDummy.Create(self); r2.Parent:=drone; r2.Position.X:=7; r2.Position.Y:=-6; r2.Position.Z:=7; mesh:=TCube.Create(self); TCube(mesh).Height:=0.6; TCube(mesh).Width:=12; TCube(mesh).Depth:=0.6; TCube(mesh).RotationAngle.Y:=0; TCube(mesh).MaterialSource:=mat0; TCube(mesh).Parent:=r2; mesh:=TCube.Create(self); TCube(mesh).Height:=0.6; TCube(mesh).Width:=12; TCube(mesh).Depth:=0.6; TCube(mesh).RotationAngle.Y:=90; TCube(mesh).MaterialSource:=mat0; TCube(mesh).Parent:=r2; //ドローンの左手前ローター r3:=TDummy.Create(self); r3.Parent:=drone; r3.Position.X:=-7; r3.Position.Y:=-6; r3.Position.Z:=-7; mesh:=TCube.Create(self); TCube(mesh).Height:=0.6; TCube(mesh).Width:=12; TCube(mesh).Depth:=0.6; TCube(mesh).RotationAngle.Y:=0; TCube(mesh).MaterialSource:=mat1; TCube(mesh).Parent:=r3; mesh:=TCube.Create(self); TCube(mesh).Height:=0.6; TCube(mesh).Width:=12; TCube(mesh).Depth:=0.6; TCube(mesh).RotationAngle.Y:=90; TCube(mesh).MaterialSource:=mat1; TCube(mesh).Parent:=r3; //ドローンの右手前ローター r4:=TDummy.Create(self); r4.Parent:=drone; r4.Position.X:=7; r4.Position.Y:=-6; r4.Position.Z:=-7; mesh:=TCube.Create(self); TCube(mesh).Height:=0.6; TCube(mesh).Width:=12; TCube(mesh).Depth:=0.6; TCube(mesh).RotationAngle.Y:=0; TCube(mesh).MaterialSource:=mat1; TCube(mesh).Parent:=r4; mesh:=TCube.Create(self); TCube(mesh).Height:=0.6; TCube(mesh).Width:=12; TCube(mesh).Depth:=0.6; TCube(mesh).RotationAngle.Y:=90; TCube(mesh).MaterialSource:=mat1; TCube(mesh).Parent:=r4; //カメラのターゲットをドローン本体に設定 cam.Target:=drone; //ドローンの影用の円の設置 shadow:=TDisk.Create(self); shadow.Width:=10; shadow.Depth:=10; shadow.MaterialSource:=mat4; shadow.Parent:=Viewport3D1; end; procedure TForm1.Timer1Timer(Sender: TObject); var ji:TJoyInfoEx; begin pos.vx:=pos.vx*0.95; pos.vy:=pos.vy*0.90; pos.vz:=pos.vz*0.95; r1.RotationAngle.Y:=r1.RotationAngle.Y+30; r2.RotationAngle.Y:=r2.RotationAngle.Y+30; r3.RotationAngle.Y:=r3.RotationAngle.Y+30; r4.RotationAngle.Y:=r4.RotationAngle.Y+30; ji.dwSize:=SizeOf(ji); ji.dwFlags:= JOY_RETURNALL; if (joyGetPosEx(JOYSTICKID1,@ji)=JOYERR_NOERROR) then begin pos.turn:=pos.turn+ (Integer(ji.wXpos)-DF)/DF*5; pos.vy:=pos.vy+ (Integer(ji.wYpos)-DF)/DF/10; pos.vx:=pos.vx+ (Integer(ji.wZpos)-DF)/DF/10; pos.vz:=pos.vz+ (Integer(ji.dwRpos)-DF)/DF/10; pos.y:=pos.y+pos.vy; if (pos.y>0) then begin pos.y:=pos.y-pos.vy; pos.vy:=-pos.vy*0.8; end; pos.x := pos.x+ cos((-pos.turn-90)/180*Pi)*pos.vz; pos.z := Pos.z+ sin((-pos.turn-90)/180*Pi)*pos.vz; pos.x := pos.x+ cos((-pos.turn)/180*Pi)*pos.vx; pos.z := pos.z+ sin((-pos.turn)/180*Pi)*pos.vx; drone.Position.X:=pos.x; drone.Position.Z:=pos.z; drone.Position.Y:=pos.y; shadow.Position.X:=pos.x; shadow.Position.Z:=pos.z; drone.ResetRotationAngle; drone.RotationAngle.Y:=pos.turn; drone.RotationAngle.X:=pos.vz*10; drone.RotationAngle.Z:=pos.vx*10; end else begin joyConfigChanged(0); end; end; end.
実行する
実行ボタンを押して実行します。(デバッグ実行でもOKです。)
ジョイスティック(ゲームパッド)をパソコンのUSBに接続して操縦します。