野球ゲームの作成 ~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」をクリックすると視点が変わります。