Delphi で書いた「軟着陸ゲーム」をちょっとだけビジュアル化する

# はじめに

昨日の [Delphi で「軟着陸ゲーム」の Windows アプリケーションを作る](https://qiita.com/ht_deko/items/580631cdf3f12ef46664) という記事ですが、いかんせん地味すぎるので、ちょっとビジュアル化してみたいと思います。

# ビジュアル化？
とはいえ、普通にロケットを描画したら地味プログラムが台無しとなります。見た目何が何だかわからないようにビジュアル化します。

## フォーム

フォームに TScrollBar を貼り付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/0852a768-d6b0-8589-ea4e-8cdb9c708a46.png)
スクロールバーのプロパティの値は次の通りです。

| プロパティ | 値 |
|:---|:---|
| Align | alRight |
| Kind | sbVertical |
| Name | ScrollBar1 |
 
フォームの OnShow イベントの最後に一行追記します。

```pas:frmuGameMain.pas
procedure TfrmGameMain.FormShow(Sender: TObject);
begin
  OnShow        := nil;
  edDisp.Top    := 16;
  edDisp.Left   := 16;
  ClientWidth   := edDisp.Left  + edDisp.Width    + 16;
  btnStart.Top  := edDisp.Top   + edDisp.Height   + 16;
  btnStart.Left := edDisp.Width - btnStart.Width  + 16;
  ClientHeight  := btnStart.Top + btnStart.Height + 16;
  edDisp.Text   := '';

  ClientWidth := ClientWidth + ScrollBar1.Width; // 追加
end;
```

縦にしたスクロールバーのツマミの位置をロケットの高度に見立てようという作戦です。フォームは見切れないようにスクロールバーの分だけ幅を広げます。

## ゲームスレッド
スクロールバーにアクセスできるように、フィールドに TScrollbar を追加し、コンストラクタで TScrollbar を指定できるようにします。

```pas:frmuGameMain.pas
type
  TGameThread = class(TThread)
  private
    { Private 宣言 }
    FEdit: TEdit;
    FScrollBar: TScrollBar; // 追加
  protected
    { Protected 宣言 }
    procedure Execute; override;
  public
    { public 宣言 }
    constructor Create(Edit: TEdit; ScrollBar: TScrollBar); // 変更
  end;

constructor TGameThread.Create(Edit: TEdit; ScrollBar: TScrollBar); // 変更
begin
  inherited Create(False);
  FEdit := Edit;
  FScrollBar := ScrollBar; // 追加
end;
```

## ゲームロジック
ゲームスレッドのコンストラクタを変更したので、btnStart のクリックイベントハンドラ内の呼び出しも変更します。

```pas:frmuGameMain.pas
procedure TfrmGameMain.btnStartClick(Sender: TObject);
begin
  btnStart.Enabled := False;
  edDisp.ReadOnly := True;
  edDisp.Color := $0080B090;
  edDisp.Font.Color := $00303020;
  Buf := edDisp.Text;
  GT := TGameThread.Create(edDisp, ScrollBar1); // 変更
  GT.OnTerminate := GameEnd;
  GT.FreeOnTerminate := True;
end;
```

内部ルーチン (ゲームスレッドの Execute メソッド内ルーチン) に、ロケットの初期位置と現在位置を設定するメソッドを追加します。

```pas:frmuGameMain.pas
  ...
  procedure Input(var v: Double); overload;
  var
    value: string;
  begin
    Input('', v);
  end; { INPUT #4 }
  procedure InitRocket(n: Integer);
  begin
    Synchronize(
      procedure
      begin
        FScrollBar.Max := n;
        FScrollBar.Position := 0;
      end
    );
  end; { InitRocket }
  procedure MoveRocket(n: Integer);
  begin
    Synchronize(
      procedure
      begin
        FScrollBar.Position := FScrollBar.Max - n;
      end
    );
  end; { MoveRocket }
{$ENDREGION}
```

ロケットの位置を通知するコードを書きます。

```pas:frmuGameMain.pas
   10:Wait(50); Clear; Using; S:=-50; A:=0; D_ := '';
      Beep(3); Print(' *** START ***');
      Restore;
      Read(B_); Read(W); Read(B_); Read(F); Read(B_); Read(H);
      InitRocket(Trunc(H)); // 追加
      Wait(W);
   70:Print_Using('####', [H, S, F, C]);
      MoveRocket(Trunc(H)); // 追加
      if Terminated then Exit;
```

## 遊んでみよう
右側にスクロールバーがありますよね？これがロケットの高度を示しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/09ffe8c7-c324-ffbb-1f32-38cf277bc954.png)
放っておくと高度がみるみる下がります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/bbd4f1c8-bf21-40f2-464c-0f0249b50757.png)
あぁ、激突してしまいました (>_<)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/c0410d50-5c5f-f0cc-11db-cefd4373b655.png)
...とまぁこんな感じで、**「見た目何やってんのかワカンナイゲーム」を維持したままビジュアル化**できました (w

# おわりに
ちょっとした改造でしたが、多少は遊びやすくなったのではないでしょうか？