トップへ(mam-mam.net/)

TViewport3Dとジョイスティックでドローン操縦シミュレーション作成(FMX) ~Delphiソースコード集

検索:

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に接続して操縦します。