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

野球ゲームの作成 ~Delphiソースコード集

検索:

野球ゲームの作成 ~Delphiソースコード集

野球場のイラストを用意する

Pixabay 様のサイト
https://pixabay.com/ja/vectors/%E9%87%8E%E7%90%83-%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89-%E3%82%B9%E3%83%9D%E3%83%BC%E3%83%84-3778774/
から野球場のイラストをダウンロードします。

私はホームベースや1塁3塁など、少し加工させていただいたものを使用しました。

Delphiを起動してプロジェクトを作成し、オブジェクトを配置し、プロパティを設定する。

Delphiを起動し[ファイル]→[新規作成]→[マルチデバイスアプリケーション-Delphi]をクリックします。
[空のアプリケーション]を選択して[OK]ボタンを押します。

ツールパレットからTViewport3Dをドラッグ&ドロップします。

ツールパレットからTTextureMaterialSourceをドラッグ&ドロップします。
Textureプロパティの右側の(Bitmap Empty)と表示されている箇所をダブルクリックし、上記でダウンロードした野球場イラストを読み込んで設定します。

ツールパレットからTLightMaterialSourceを2個ドラッグ&ドロップします。

ツールパレットからTColorMaterialSourceをドラッグ&ドロップします。

ツールパレットからTTimerをドラッグ&ドロップします。

ツールパレットからTButtonを5個ドラッグ&ドロップします。

ツールパレットからTLabelをドラッグ&ドロップします。

ソースコードの記述

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.Controls.Presentation, FMX.StdCtrls, FMX.Viewport3D, System.Math.Vectors,
  FMX.Types3D, FMX.Controls3D, FMX.Objects3D, FMX.MaterialSources,
  FMX.ScrollBox, FMX.Memo, FMX.Memo.Types;

type

  TForm1 = class(TForm)
    Viewport3D1: TViewport3D;
    Button1: TButton;
    TextureMaterialSource1: TTextureMaterialSource;
    LightMaterialSource1: TLightMaterialSource;
    LightMaterialSource2: TLightMaterialSource;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    Button5: TButton;
    Timer1: TTimer;
    ColorMaterialSource1: TColorMaterialSource;
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { private 宣言 }
    Camera:TCamera;
    Light:TLight;
    Plane1: TPlane;
    d0,d1,d2,d3,d4,dBat:TDummy;
    r11,r12,r13,r14:TRectangle3D;
    r15,r16:TRectangle3D;
    r21,r22,r23,r24,r25,r26:TRectangle3D;
    disk:TDisk;
    s1,s2:TSphere;
    VBall:TPoint3D;//ボールの速度
    c1:TCone;
    Step:Integer;  //ボールのモーション用
    BStep:Integer; //バットのモーション用
    HitFlag:Integer;
    CamId:Integer; //カメラの位置と方位
    procedure SetCameraPos();
  public
    { public 宣言 }
  end;

var
  Form1: TForm1;

const
  //カメラの位置
  CamPos:array[0..3] of array[0..2] of Single=(
    (  0,  -6,  -66),
    (  0,  -2,  -66),
    (-40,  -4,  -40),
    (  0, -30, -100)
  );
  //カメラの向き
  CamAngle:Array[0..3] of array[0..2] of Single=(
    (-9,0,0),
    (-3,0,0),
    (0,90,0),
    (-20,0,0)
  );
  //ボールの最初の位置
  BallPosition:TPoint3D=(X:0;Y:-2;Z:-16);

implementation

{$R *.fmx}

procedure TForm1.Button1Click(Sender: TObject);
begin
  //バットを振る
  if BStep=0 then BStep:=1;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  //カメラの位置と向きを設定
  CamId:=0;
  SetCameraPos();
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  //カメラの位置と向きを設定
  CamId:=1;
  SetCameraPos();
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  //カメラの位置と向きを設定
  CamId:=2;
  SetCameraPos();
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
  //カメラの位置と向きを設定
  CamId:=3;
  SetCameraPos();
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  LightMaterialSource2.Diffuse:=TAlphaColorRec.Brown;
  Plane1:=TPlane.Create(self);
  Plane1.MaterialSource:=TextureMaterialSource1;
  Plane1.Parent:=Viewport3D1;

  //カメラの設定
  Camera:=TCamera.Create(self);
  Camera.Parent:=Viewport3D1;
  Camera.AngleOfView:=26;
  Viewport3D1.Camera:=Camera;
  Viewport3D1.Color:=$FFCCDDFF;
  Viewport3D1.UsingDesignCamera:=False;
  CamId:=0;
  SetCameraPos();

  //ライトの設定
  Light:=TLight.Create(self);
  Light.Parent:=Viewport3D1;
  Light.RotationAngle.X:=-30;
  Light.RotationAngle.Y:=-60;

  //地面の設定
  Plane1.MaterialSource:=TextureMaterialSource1;
  Plane1.RotationAngle.X:=270;
  Plane1.Position.X:=0;
  Plane1.Position.Y:=0;
  Plane1.Position.Z:=0;
  Plane1.Width:=140;
  Plane1.Height:=140;
  Plane1.Scale.X:=1;
  Plane1.Scale.Y:=1;
  plane1.Scale.Z:=1;

  //ピッチャー
  d0:=TDummy.Create(self);
  d0.Parent:=Viewport3D1;
  d0.Position.X:=0.6;
  d0.Position.Y:=0;
  d0.Position.Z:=-16;
  r11:=TRectangle3D.Create(self);
  r11.Parent:=d0;
  r11.Width:=0.2;
  r11.Height:=1;
  r11.Depth:=0.2;
  r11.Position.X:=-0.2;
  r11.Position.Y:=-0.5;
  r11.Position.Z:=0;
  r11.MaterialSource:=LightMaterialSource1;
  r11.MaterialBackSource:=LightMaterialSource1;
  r11.MaterialShaftSource:=LightMaterialSource1;
  r12:=TRectangle3D.Create(self);
  r12.Parent:=d0;
  r12.Width:=0.2;
  r12.Height:=1;
  r12.Depth:=0.2;
  r12.Position.X:=0.2;
  r12.Position.Y:=-0.5;
  r12.Position.Z:=0;
  r12.MaterialSource:=LightMaterialSource1;
  r12.MaterialBackSource:=LightMaterialSource1;
  r12.MaterialShaftSource:=LightMaterialSource1;
  r13:=TRectangle3D.Create(self);
  r13.Parent:=d0;
  r13.Width:=0.6;
  r13.Height:=1;
  r13.Depth:=0.2;
  r13.Position.X:=0;
  r13.Position.Y:=-1.5;
  r13.Position.Z:=0;
  r13.MaterialSource:=LightMaterialSource1;
  r13.MaterialBackSource:=LightMaterialSource1;
  r13.MaterialShaftSource:=LightMaterialSource1;
  r14:=TRectangle3D.Create(self);
  r14.Parent:=d0;
  r14.Width:=0.3;
  r14.Height:=0.3;
  r14.Depth:=0.3;
  r14.Position.X:=0;
  r14.Position.Y:=-2.1;
  r14.Position.Z:=0;
  r14.MaterialSource:=LightMaterialSource1;
  r14.MaterialBackSource:=LightMaterialSource1;
  r14.MaterialShaftSource:=LightMaterialSource1;

  //ピッチャーの左腕
  d1:=TDummy.Create(self);
  d1.Parent:=Viewport3D1;
  r15:=TRectangle3D.Create(self);
  r15.Width:=0.2;
  r15.Height:=0.8;
  r15.Depth:=0.2;
  r15.Position.X:=0;
  r15.Position.Y:=0.4;
  r15.Position.Z:=0;
  r15.Parent:=d1;
  r15.MaterialSource:=LightMaterialSource1;
  r15.MaterialBackSource:=LightMaterialSource1;
  r15.MaterialShaftSource:=LightMaterialSource1;
  d1.Position.X:=0.9;
  d1.Position.Y:=-1.94;
  d1.Position.Z:=-16;
  d1.RotationAngle.Z:=-180 div 8;

  //ピッチャーの右腕
  d2:=TDummy.Create(self);
  d2.Parent:=Viewport3D1;
  r16:=TRectangle3D.Create(self);
  r16.Width:=0.2;
  r16.Height:=0.8;
  r16.Depth:=0.2;
  r16.Position.X:=0.1;
  r16.Position.Y:=0.4;
  r16.Position.Z:=0;
  r16.Parent:=d2;
  r16.MaterialSource:=LightMaterialSource1;
  r16.MaterialBackSource:=LightMaterialSource1;
  r16.MaterialShaftSource:=LightMaterialSource1;
  d2.Position.X:=0.2;
  d2.Position.Y:=-1.96;
  d2.Position.Z:=-16;
  d2.RotationAngle.Z:=180 div 8;

  //ボール
  d3:=TDummy.Create(self);
  d3.Parent:=Viewport3D1;
  d3.Position.X:=BallPosition.X;
  d3.Position.Y:=BallPosition.Y;
  d3.Position.Z:=BallPosition.Z;
  s1:=TSphere.Create(self);
  s1.Parent:=d3;
  s1.Position.X:=0;
  s1.Position.Y:=0.8;
  s1.Position.Z:=0;
  s1.Width:=0.4;
  s1.Height:=0.4;
  s1.Depth:=0.4;
  s1.MaterialSource:=LightMaterialSource1;
  //ボールの影
  disk:=TDisk.Create(self);
  disk.Width:=0.4;
  disk.Height:=0.4;
  disk.Position.Y:=-0.01;
  disk.Position.X:=BallPosition.X;
  disk.Position.Z:=BallPosition.Z;
  disk.Parent:=Viewport3D1;
  disk.Opacity:=0.3;
  ColorMaterialSource1.Color:=$ff000000;
  disk.MaterialSource:=ColorMaterialSource1;

  //バッター
  d4:=TDummy.Create(self);
  d4.Parent:=Viewport3D1;
  d4.Position.X:=-1.8;
  d4.Position.Y:=0;
  d4.Position.Z:=-46;
  d4.RotationAngle.Y:=-90;
  r21:=TRectangle3D.Create(self);
  r21.Parent:=d4;
  r21.Width:=0.2;
  r21.Height:=1;
  r21.Depth:=0.2;
  r21.Position.X:=-0.2;
  r21.Position.Y:=-0.5;
  r21.Position.Z:=0;
  r21.MaterialSource:=LightMaterialSource1;
  r21.MaterialBackSource:=LightMaterialSource1;
  r21.MaterialShaftSource:=LightMaterialSource1;
  r22:=TRectangle3D.Create(self);
  r22.Parent:=d4;
  r22.Width:=0.2;
  r22.Height:=1;
  r22.Depth:=0.2;
  r22.Position.X:=0.2;
  r22.Position.Y:=-0.5;
  r22.Position.Z:=0;
  r22.MaterialSource:=LightMaterialSource1;
  r22.MaterialBackSource:=LightMaterialSource1;
  r22.MaterialShaftSource:=LightMaterialSource1;
  r23:=TRectangle3D.Create(self);
  r23.Parent:=d4;
  r23.Width:=0.6;
  r23.Height:=1;
  r23.Depth:=0.2;
  r23.Position.X:=0;
  r23.Position.Y:=-1.5;
  r23.Position.Z:=0;
  r23.MaterialSource:=LightMaterialSource1;
  r23.MaterialBackSource:=LightMaterialSource1;
  r23.MaterialShaftSource:=LightMaterialSource1;
  r24:=TRectangle3D.Create(self);
  r24.Parent:=d4;
  r24.Width:=0.3;
  r24.Height:=0.3;
  r24.Depth:=0.4;
  r24.Position.X:=0;
  r24.Position.Y:=-2.1;
  r24.Position.Z:=0;
  r24.MaterialSource:=LightMaterialSource1;
  r24.MaterialBackSource:=LightMaterialSource1;
  r24.MaterialShaftSource:=LightMaterialSource1;
  r25:=TRectangle3D.Create(self);
  r25.Parent:=d4;
  r25.Width:=0.2;
  r25.Height:=0.8;
  r25.Depth:=0.2;
  r25.Position.X:=0.2;
  r25.Position.Y:=-1.6;
  r25.Position.Z:=-0.3;
  r25.RotationAngle.X:=-180 div 3;
  r25.RotationAngle.Z:=180 div 6;
  r25.MaterialSource:=LightMaterialSource1;
  r25.MaterialBackSource:=LightMaterialSource1;
  r25.MaterialShaftSource:=LightMaterialSource1;
  r26:=TRectangle3D.Create(self);
  r26.Parent:=d4;
  r26.Width:=0.2;
  r26.Height:=0.8;
  r26.Depth:=0.2;
  r26.Position.X:=-0.5;
  r26.Position.Y:=-1.6;
  r26.Position.Z:=-0.3;
  r26.RotationAngle.X:=-180 div 3;
  r26.RotationAngle.Z:=180 div 6;
  r26.MaterialSource:=LightMaterialSource1;
  r26.MaterialBackSource:=LightMaterialSource1;
  r26.MaterialShaftSource:=LightMaterialSource1;

  //バット
  dBat:=TDummy.Create(self);
  dBat.Parent:=Viewport3D1;
  dBat.Position.X:=-1.2;
  dBat.Position.Y:=-1.45;
  dBat.Position.Z:=-46;
  s2:=TSphere.Create(self);
  s2.Parent:=dBat;
  s2.Width:=0.3;
  s2.Height:=0.1;
  s2.Depth:=0.3;
  s2.MaterialSource:=LightMaterialSource2;
  c1:=TCone.Create(self);
  c1.Parent:=dBat;
  c1.Width:=0.16;
  c1.Height:=1.6;
  c1.Depth:=0.16;
  c1.Position.X:=0;
  c1.Position.Y:=-0.75;
  c1.Position.Z:=0;
  c1.RotationAngle.X:=180;
  c1.MaterialSource:=LightMaterialSource2;

  //ヒットかホームラン時に使用するボールの速度ベクトル
  VBall.X:=0;
  VBall.Y:=0;
  VBall.Z:=0;

  Step:=0;
  BStep:=0;
  //ストライクかヒットかホームランか
  HitFlag:=0;
end;

procedure TForm1.SetCameraPos;
begin
  Camera.Position.X:=CamPos[CamId][0];
  Camera.Position.Y:=CamPos[CamId][1];
  Camera.Position.Z:=CamPos[CamId][2];
  Camera.ResetRotationAngle;
  Camera.RotationAngle.X:=CamAngle[CamId][0];
  Camera.RotationAngle.Y:=CamAngle[CamId][1];
  Camera.RotationAngle.Z:=CamAngle[CamId][2];
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var xx:Integer;
begin
  if (HitFlag=0) or (HitFlag=1) then
  begin
    if Step<100 then
    begin
      //何もしない
    end
    else if Step<120 then
    begin
      d2.RotationAngle.X:=d2.RotationAngle.X+180/20;
      d3.RotationAngle.X:=d3.RotationAngle.X+180/20;
    end
    else if Step<140 then
    begin
      d2.RotationAngle.X:=d2.RotationAngle.X+180/20;
      d3.Position.Z:=d3.Position.Z-0.3;
      d3.Position.Y:=d3.Position.Y+0.012;
      disk.Position.Z:=d3.Position.Z;
    end
    else if Step<=250 then
    begin
      d2.ResetRotationAngle;
      d3.Position.Z:=d3.Position.Z-0.3;
      d3.Position.Y:=d3.Position.Y+0.012;
      disk.Position.Z:=d3.Position.Z;
    end
    else if Step<=320 then
    begin
      d2.ResetRotationAngle;
      d3.Position.Z:=d3.Position.Z-0.3;
      d3.Position.Y:=d3.Position.Y+0.012;
      disk.Position.Z:=d3.Position.Z;
      if HitFlag=0 then
      begin
        HitFlag:=1;
      end;
    end
    else
    begin
      d2.ResetRotationAngle;
      d3.ResetRotationAngle;
      d3.Position.X:=BallPosition.X;
      d3.Position.Y:=BallPosition.Y;
      d3.Position.Z:=BallPosition.Z;
      disk.Position.Z:=d3.Position.Z;
      Step:=0;
      HitFlag:=0;
    end;
  end
  else if (HitFlag=2) or (HitFlag=3) then
  begin
    VBall.Y:=VBall.Y+0.005;
    d3.Position.X:=d3.Position.X+VBall.X;
    d3.Position.Y:=d3.Position.Y+VBall.Y;
    d3.Position.Z:=d3.Position.Z+VBall.Z;
    disk.Position.X:=d3.Position.X;
    disk.Position.Z:=d3.Position.Z;
    if d3.Position.Y>0.5 then
    begin
      d3.Position.Y:=0.5;
      VBall.X:=VBall.X*0.8;
      VBall.Y:=-VBall.Y*0.5;
      VBall.Z:=VBall.Z*0.8;
    end;
    if Step>300 then
    begin
      HitFlag:=0;
      Step:=0;
      d2.ResetRotationAngle;
      d3.ResetRotationAngle;
      d3.Position.X:=BallPosition.X;
      d3.Position.Y:=BallPosition.Y;
      d3.Position.Z:=BallPosition.Z;
      disk.Position.X:=d3.Position.X;
      disk.Position.Z:=d3.Position.Z;
      camera.Target:=nil;
      Label1.Text:='';
    end;
  end;
  inc(Step);

  if BStep=0 then
  begin
    dBat.ResetRotationAngle;
  end
  else
  begin
    if BStep<7 then
    begin
      xx:=BStep;
    end
    else
    begin
      xx:=6;
      if (BStep=7) and ((HitFlag<>2) and (HitFlag<>3)) then
      begin
        if(d3.Position.Z<-45.7) and (d3.Position.Z>-46.3) then
        begin
          camera.Target:=d3;
          HitFlag:=3;
          VBall.X:=-(d3.Position.Z+50)/20;
          VBall.Y:=-0.5;
          VBall.Z:=0.5;
          Step:=0;
          Label1.Text:='ホームラン';
        end
        else if(d3.Position.Z<-44.2) and (d3.Position.Z>-47.8) then
        begin
          camera.Target:=d3;
          HitFlag:=2;
          VBall.X:=-(d3.Position.Z+46)/40;
          VBall.Y:=-0.3;
          VBall.Z:=0.4;
          Step:=0;
          Label1.Text:='ヒット';
        end
        else
        begin
          HitFlag:=1;
          Label1.Text:='ストライク';
        end;
      end;
    end;
    dBat.ResetRotationAngle;
    dBat.RotationAngle.X:=180/2/6*xx;
    dBat.RotationAngle.Z:=180/2/6*BStep;

    inc(BStep);
    if BStep>18 then BStep:=0;
  end;
end;

end.

実行ボタンを押す

実行ボタンを押すと、コンパイルして起動します。
「Button1」をクリックすると、バットを振ります。
「Button2」~「Button5」をクリックすると視点が変わります。