はじめに
皆さんは、人生で初めて入力したプログラムを覚えているでしょうか?
私は覚えています。ポケットコンピュータ『SHARP PC-1246』の取扱説明書に載っていた 「追いかけマン」 です。悪戦苦闘しながら入力して、ちゃんとゲームとして動いた時は嬉しかったなぁ。
『PC-1246』は遠い昔に手放したのですが、最近『PC-1245』や『PC-1251』を入手したため、また「追いかけマン」を入力して遊ぶ事が出来ました。
本記事は、その「追いかけマン」を Windows アプリケーションにしてみようというものです。アプリケーションの作成には 『Embarcadero Delphi』 を使います。
Delphi のバージョンは 2009 以降を想定していますが、(可能な限り) 古い Delphi へ移植できるように考慮したコードになっています。
- Delphi (Wikipedia)
- Delphi (Embarcadero)
- DocWiki (Embarcadero)
- Delphi Community Edition (Embarcadero) <- 無償版
- OBJECT PASCAL HANDBOOK for 11 ALEXANDRIA (Embarcadero) <- 言語解説 (英語、無償)
「追いかけマン」
「追いかけマン (英語名: BUGHUNT)」 についての説明です。
ルール
10x10 のフィールドで虫と追いかけっこをするというもので、『HIT & BLOW』のようなゲームです。
[操作説明]
- 追いかけマンは
〔8〕
〔2〕
〔4〕
〔6〕
キーで移動できます。 - 追いかけマンが移動すると虫も移動します。
- 虫がフィールドの隅に来ると、任意の位置へワープします。
- 体力 (E) は初期値が 100 で、追いかけマンが移動してもしなくても 1 ずつ減ります。
- 距離 (D) は虫との距離で
ABS(X-a) + ABS(Y-b)
の関係にあります。 - 距離が 3 以下だと、BEEP が鳴ります (近さに応じて 1/2/3 回。または */**/*** による表示)。
- 虫を見つけると BEEP が 5 回鳴ります。
- 虫を退治できると体力が 5/10/15 のいずれか回復します。
- 体力が 0 になるまでに虫をどれだけ退治できたかを競います。
[画面説明]
ビジュアルなゲームだと思った?『PC-1246』は 16桁 1行でグラフィックが使えないポケコンなのよ?
左から、追いかけマンの現在位置 (X,Y)、虫との距離、体力値です。
バリエーション
「追いかけマン」にはバリエーションがあるようです。
機種 | 説明 |
---|---|
PC-1250/51/55 版 | オリジナル? |
PC-1245 版 | 16桁表示に合わせた改変 |
PC-1246/47 版 | BEEP 命令が省かれている |
PC-1260/61/62 版 | PC-125x 版と同じ? |
取扱説明書での「追いかけマン」の "虫との距離の説明" は PC-126x 版以外間違っていて、ABS(X-a) + ABS(X-b)
と書かれています。
BASIC ソースコード
次のリストは PC-1245 版のものです。
10 "A": RANDOM : WAIT 250: PRINT "** OIKAKE MAN **": BEEP 3
20 X=0:Y=0:E=100:F=100:T=0:S=0
30 A=RND 9:B=RND 9
40 L=ABS (X-A)+ABS (Y-B)
50 IF X=A AND Y=B GOTO 400
100 IF L=1 BEEP 3
110 IF L=2 BEEP 2
120 IF L=3 BEEP 1
130 WAIT 50: PRINT "(";STR$ (X);",";STR$ (Y);") D=";STR$ (L);" E=";STR$ (E)
150 S=S+1:E=F-INT (S/2)
153 IF E<=0 THEN 500
155 G$=INKEY$ : IF G$=""GOTO 130
157 BEEP 1
160 IF G$="2"LET Y=Y-1: GOTO 210
170 IF G$="4"LET X=X-1: GOTO 210
180 IF G$="6"LET X=X+1: GOTO 210
190 IF G$="8"LET Y=Y+1: GOTO 210
200 GOTO 150
210 IF X<0 LET X=0: GOTO 150
220 IF Y<0 LET Y=0: GOTO 150
230 IF X>9 LET X=9: GOTO 150
240 IF Y>9 LET Y=9: GOTO 150
250 IF X=A AND Y=B GOTO 400
260 E=F-INT (S/2)
270 IF E<=0 GOTO 500
280 R=RND 5
290 IF R=1 LET B=B-1: GOTO 340
300 IF R=2 LET A=A-1: GOTO 340
310 IF R=3 LET A=A+1: GOTO 340
320 IF R=4 LET B=B+1: GOTO 340
340 IF A<0 OR A>9 GOTO 370
350 IF B<0 OR B>9 GOTO 370
360 GOTO 40
370 BEEP 4: PAUSE "*** WARP ***": GOTO 30
400 PAUSE "HIT! HIT!"
410 BEEP 5
420 PAUSE "BANG! BANG!"
430 T=T+1:C=RND 3*5:F=F+C
435 E=F-INT (S/2)
440 WAIT 100: PRINT "SCORE ";T: PRINT "ENERGY ";E
450 GOTO 30
500 WAIT 100: PRINT "SCORE ";STR$ (T): WAIT : PRINT " *GAME OVER!!*"
510 END
PC-1246 版は、すべての BEEP 命令が省かれ、100 行目からの 3 行が次のようになっています。
100 IF L=1 PAUSE "***"
110 IF L=2 PAUSE "**"
120 IF L=3 PAUSE "*"
PC-125x 版は、24桁表示で動作するようになっていますので、一部画面表示が異なります。
10 "A": RANDOM : WAIT 250: PRINT "** OIKAKE MAN GAME **": BEEP 3
130 WAIT 50: PRINT "(";STR$ (X);",";STR$ (Y);") KYORI=";STR$ (L);" E=";STR$ (E)
440 WAIT 100: PRINT "SCORE ";T;" ENERGY ";E
500 WAIT : PRINT "SCORE "; STR$ (T);" *GAME OVER!!*"
Delphi への移植
PC-1245 版の「追いかけマン」を Delphi へ移植してみます。
画面
[ファイル | 新規作成 | Windows VCL アプリケーション]
でプロジェクトを新規作成し、フォームに TEdit と TButton を貼ります。
・フォームのプロパティ
固定サイズのウィンドウを持つフォームに指定します。
プロパティ | 値 |
---|---|
BorderIcons | [biSystemMenu,biMinimize] |
BorderStyle | bsSingle |
Caption | 追いかけマン |
Font.Size | 16 |
KeyPreview | True |
Name | frmGameMain |
Position | poScreenCenter |
Scaled | False |
・エディットボックスのプロパティ
エディットボックスのフォントは等幅が望ましいのでフォントを BIZ UDゴシック
とかにしておき、エディットボックスの幅も 16 文字入るくらいに調整しておきます。
プロパティ | 値 |
---|---|
Font.Name | BIZ UDゴシック |
Font.Size | 24 |
Height | 40 |
Name | edDisp |
Width | 266 (16桁) / 392 (24桁) |
・ボタンのプロパティ
ボタンはキャプションとサイズを設定するくらいです。
プロパティ | 値 |
---|---|
Caption | 開始 |
Height | 40 |
Name | btnStart |
Width | 120 |
・プロジェクトの保存
[ファイル | プロジェクトに名前を付けて保存]
で、一旦プロジェクトを保存します。
ファイルの種類 | ファイル名 |
---|---|
ユニットファイル | frmuGameMain.pas |
プロジェクトファイル | oikakeman.dproj |
ゲームのための土台作り
ポケコンの BASIC の命令を移植し、ゲームプログラムを移植します。まずはゲームを動かすための土台を作ります。
・BASIC ルーチン用ユニット
[ファイル | 新規作成 | ユニット]
で新規にユニットを作成し、[ファイル | 名前を付けて保存]
でそのまま保存します。
ファイルの種類 | ファイル名 |
---|---|
ユニットファイル | uPokecomUtils.pas |
「追いかけマン」を移植するのに必要な命令をレコード型のメソッドとして実装します。レコード型のメソッドにしておくとコード補完が使えて便利なのです。
次のコードを記述して、〔Ctrl〕+〔S〕
で上書き保存してください。
unit uPokecomUtils;
interface
uses
System.SysUtils, System.Math;
type
TPcRtn = record
FWait: UInt32;
function Abs(v: Double): Double; overload;
procedure &End;
function Int(v: Double): Double;
procedure Random;
function Rnd(v: Double): Double;
function Sgn(v: Double): TValueSign;
function Str(v: Double): String;
procedure Wait(v: UInt32 = 0);
end;
implementation
{ TPcRtn }
function TPcRtn.Abs(v: Double): Double;
begin
result := System.Abs(v);
end;
procedure TPcRtn.&End;
begin
Abort;
end;
function TPcRtn.Int(v: Double): Double;
begin
result := Trunc(v);
end;
procedure TPcRtn.Random;
begin
Randomize;
end;
function TPcRtn.Rnd(v: Double): Double;
begin
if v >= 1 then
result := System.Random(Trunc(v)) + 1
else if v < 0 then
result := System.Random // Need Debug
else
result := System.Random;
end;
function TPcRtn.Sgn(v: Double): TValueSign;
begin
result := Sign(v);
end;
function TPcRtn.Str(v: Double): String;
begin
result := FloatToStr(v);
end;
procedure TPcRtn.Wait(v: UInt32);
begin
FWait := v;
end;
end.
このユニットをメインフォームから使えるように、frmuGameMain
の uses に追加しておきます。
unit frmuGameMain;
interface
uses
..., uPokecomUtils;
ポケコンの BASIC で使える型は文字列型と数値 (BCD) なのですが、様々な事情を考えて、文字列 (String) 型と実数 (Double) 型をメインで使う事にします。
End() メソッドに & が付いているのは、end が Delphi (Pascal) では予約語になっているからです。
See also:
・イベントハンドラ (その1)
frmuGameMain
に戻り、[オブジェクトインスペクタ] の [イベント] タブでイベントをダブルクリックしてイベントハンドラを作成します。
frmGameMain.OnShow
雑に配置したエディットボックスやボタン、フォームのサイズを計算で設定します。「自分で配置したままの方がいい!」という方は記述しなくても構いません。
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 := '';
end;
frmGameMain.OnKeyPress
押されたキーを edDisp の Tag プロパティに数値として保存するようにします。
procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
edDisp.Tag := Integer(Key);
end;
・ゲーム用スレッド
ゲーム用のスレッドを作成します。ゲームループがあるため、スレッドを使わないとアプリケーションをマウスで移動できなかったり、動きがカクカクになったりすると思います…多分。
次の位置に、
type
{ この位置 }
TfrmGameMain = class(TForm)
以下のコードを貼り付け、このスレッドクラスの定義のどこでもいいので内側にカーソルを合わせて 〔Ctrl〕+〔Shift〕+〔C〕
を押してください。
TGameThread = class(TThread)
private
{ Private 宣言 }
FEdit: TEdit;
protected
{ Protected 宣言 }
procedure Execute; override;
public
{ public 宣言 }
constructor Create(Edit: TEdit);
end;
2 つのメソッドの実装部が自動で作成されたと思いますので、uses に必要なユニットを追加し、
uses
..., System.Diagnostics;
TfrmGameMain にフィールドを 2 つ追加し、
TfrmGameMain = class(TForm)
edDisp: TEdit;
btnStart: TButton;
procedure FormShow(Sender: TObject);
procedure FormKeyPress(Sender: TObject; var Key: Char);
private
{ Private 宣言 }
GT: TGameThread; // 追加
Buf: string; // 追加
public
{ Public 宣言 }
end;
スレッドのメソッドを記述します。
constructor TGameThread.Create(Edit: TEdit);
begin
inherited Create(False);
FEdit := Edit;
end;
{$HINTS OFF}
procedure TGameThread.Execute;
{$REGION '/* 内部ルーチン */'}
const
COLUMNS = 16; // 画面の桁数
var
A, B, C, D, E, F, G, H, I, J, K, L, M,
N, O, P, Q, R, S, T, U, V, W, X, Y, Z: Double;
A_, B_, C_, D_, E_, F_, G_, H_, I_, J_, K_, L_, M_,
N_, O_, P_, Q_, R_, S_, T_, U_, V_, W_, X_, Y_, Z_: string;
Rtn: TPcRtn;
procedure Beep(n: Integer);
begin
Synchronize(
procedure
var
i: Integer;
begin
for i := 1 to n do
Winapi.Windows.Beep(4000, 500);
end
);
end; { Beep }
function Inkey: Char;
begin
result := Char(FEdit.Tag);
FEdit.Tag := 0;
end; { Inkey }
procedure Print(v: array of const); overload;
var
i: Integer;
T, Tick: Int64;
sw: TStopWatch;
vs: string;
begin
for i:=Low(v) to High(v) do
begin
case v[i].VType of
vtChar:
vs := vs + String(v[i].VChar);
vtAnsiString:
vs := vs + String(PAnsiChar(v[i].VAnsiString));
vtWideChar:
vs:= vs + v[i].VWideChar;
vtWideString:
vs:= vs + PWideChar(v[i].VWideString);
vtUnicodeString:
vs := vs + PWideChar(v[i].VUnicodeString);
vtInteger:
vs := vs + IntToStr(v[i].VInteger);
vtInt64:
vs := vs + IntToStr(PInt64(v[i].VInt64)^);
vtCurrency:
vs := vs + CurrToStr(PCurrency(v[i].VCurrency)^);
vtExtended:
vs := vs + FloatToStr(PExtended(v[i].VExtended)^);
else
end;
end;
Synchronize(
procedure
begin
FEdit.Clear;
FEdit.Text := vs;
FEdit.Repaint;
end
);
if Rtn.FWait = 0 then
begin
while True do
begin
if Self.Terminated then Break;
if FEdit.Tag = 13 then Break;
end;
Synchronize(
procedure
begin
FEdit.Clear;
FEdit.Repaint;
end
);
end
else
begin
sw := TStopWatch.StartNew;
Tick := sw.ElapsedMilliseconds;
T := 1000 div 64 * Rtn.FWait;
while T > (sw.ElapsedMilliseconds - Tick) do
if Self.Terminated then Break;
end;
end; { Print #1 }
procedure Print(v: string); overload;
begin
Print([v]);
end; { Print #2 }
procedure Print(v: Double); overload;
var
s: string;
begin
s := FloatToStr(v);
s := Copy(s, 1, COLUMNS);
s := StringOfChar(' ', COLUMNS - Length(s)) + s;
Print(s);
end; { Print #3 }
procedure Pause(v: array of const); overload;
var
dWait: UInt32;
begin
dWait := Rtn.FWait;
Rtn.FWait := 54; // 0.85s
Print(v);
Rtn.FWait := dWait;
end; { Pause #1 }
procedure Pause(v: string); overload;
begin
Pause([v]);
end; { Pause #2 }
procedure Pause(v: Double); overload;
var
s: string;
begin
s := FloatToStr(v);
s := Copy(s, 1, COLUMNS);
s := StringOfChar(' ', COLUMNS - Length(s)) + s;
Pause(s);
end; { Pause #3 }
{$ENDREGION}
begin
try
with Rtn do
begin
{ --- ここから --- }
{ --- ここまで --- }
end;
except
end;
end;
{$HINTS ON}
Beep()
をメインスレッドで鳴らすようにしているのは、こちらの方が実機の動きに近いからです。
TGameThread.Execute 内で 1 文字変数を事前に宣言しているため、H2164 のヒントが発生します。このヒント表示を抑制するために、全体が {$HINT OFF}~{$HINT ON}
で括られています。
See also:
・イベントハンドラ (その2)
[オブジェクトインスペクタ] の [イベント] タブでイベントをダブルクリックしてイベントハンドラを作成します。
btnStart.OnClick
[開始]
ボタンが押されたらゲームスレッドを実行するようにします。
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);
GT.OnTerminate := GameEnd;
GT.FreeOnTerminate := True;
end;
ゲームスレッドが終了した時のイベントハンドラも記述しておきます。implementation 以下のどこでもいいので以下のコードを記述し、
procedure TfrmGameMain.GameEnd(Sender: TObject);
begin
btnStart.Enabled := True;
edDisp.ReadOnly := False;
edDisp.Color := clWindow;
edDisp.Font.Color := clWindowText;
edDisp.Text := Buf;
end;
このイベントハンドラのどこでもいいので内側にカーソルを合わせて 〔Ctrl〕+〔Shift〕+〔C〕
を押すと、宣言部 (interface) に宣言が追加されます。
TfrmGameMain = class(TForm)
edDisp: TEdit;
btnStart: TButton;
procedure FormShow(Sender: TObject);
procedure FormKeyPress(Sender: TObject; var Key: Char);
private
{ Private 宣言 }
procedure GameEnd(Sender: TObject); // 追加される
public
{ Public 宣言 }
end;
frmGameMain.OnCloseQuery
フォームが [x] で閉じられようとした時のイベントハンドラを記述します。
procedure TfrmGameMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if Assigned(GT) then
begin
GT.Terminate;
while not btnStart.Enabled do
Application.ProcessMessages;
end;
CanClose := True;
end;
ゲームロジック
ゲームのロジックをゲームスレッドの Execute
メソッド内に記述します。
{$REGION '/* 内部ルーチン */'}
となっている所は、行頭の [-] マークを押す事でコードを折り畳む事ができます。
[+] マークを押すとコードを元のように展開します。
コードを折り畳んでおくと、ゲームロジックの記述に専念できていいかと思います。
・ラベルと変数の宣言
Delphi (Pascal) は、var ブロックに変数を宣言する必要がありますが 1、古いポケコンは 1 文字の変数しか使えないので、1 文字変数を事前に宣言してあります。A~Z が Doubel 型、A_~Z_ (アンダーバー付き) が string 型で宣言されています。A
, B
等の数値型変数はそのまま、C$
, D$
のような文字列変数は C_
, D_
を使う事になります。
Delphi (Pascal) の goto 文ではジャンプ先にラベルしか使えないのですが、数値のみのラベルを定義できるので、疑似的な行番号を表現できます。ラベルもまた事前に宣言しておく必要がありますので、次の場所に追加します。
{$ENDREGION}
label // 追加
30, 40, 130, 150, 210, 340, 370, 400, 500; // 追加
begin
...
この位置に挿入します。
他に変数が必要になったら、var ブロックを記述して任意の変数を追加する事ができます。
{$ENDREGION}
var // 追加
ZA_: array of string; // 追加
label
30, 40, 130, 150, 210, 340, 370, 400, 500;
begin
...
・本体
BASIC を Delphi (Pascal) に移植したコードを Execute メソッド内の
{ --- ここから --- }
{ --- ここまで --- }
の間に記述します。BASIC の命令とほぼ 1 対 1 で対応するメソッドが用意されているため、移植は容易です。
...
begin
try
with Rtn do
begin
{ --- ここから --- }
Random; Wait(250); Print('** OIKAKE MAN **'); Beep(3);
X := 0; Y := 0; E := 100; F := 100; T := 0; S := 0;
30:A := Rnd(9); B := Rnd(9);
40:L := Abs(X - A) + Abs(Y - B);
if (X = A) and (Y = B) then goto 400;
if L = 1 then Beep(3); // if L=1 then Pause('***');
if L = 2 then Beep(2); // if L=2 then Pause('**');
if L = 3 then Beep(1); // if L=3 then Pause('*');
130:Wait(50); Print(['(', Str(X), ',', Str(Y), ') D=', Str(L), ' E=', Str(E)]);
150:S := S + 1; E := F - Int(S / 2);
if E <= 0 then goto 500;
G_ := INKEY; if G_ = #$00 then goto 130;
Beep(1);
IF G_ = '2' then begin Y := Y - 1; goto 210 end;
IF G_ = '4' then begin X := X - 1; goto 210 end;
IF G_ = '6' then begin X := X + 1; goto 210 end;
IF G_ = '8' then begin Y := Y + 1; goto 210 end;
goto 150;
210:if X < 0 then begin X := 0; goto 150 end;
if Y < 0 then begin Y := 0; goto 150 end;
if X > 9 then begin X := 9; goto 150 end;
if Y > 9 then begin Y := 9; goto 150 end;
if (X = A) and (Y = B) then goto 400;
E := F - Int(S / 2);
if E <= 0 then goto 500;
R := Rnd(5);
if R = 1 then begin B := B - 1; goto 340 end;
if R = 2 then begin A := A - 1; goto 340 end;
if R = 3 then begin A := A + 1; goto 340 end;
if R = 4 then begin B := B + 1; goto 340 end;
340:if (A < 0) or (A > 9) then goto 370;
if (B < 0) or (B > 9) then goto 370;
goto 40;
370:Beep(4); Pause('*** WARP ***'); goto 30;
400:Pause('HIT! HIT!');
Beep(5);
Pause('BANG! BANG!');
T := T + 1; C := Rnd(3 * 5); F := F + C;
E := F - Int(S / 2);
Wait(100); Print(['SCORE ', T]); Print(['ENERGY ', E]);
goto 30;
500:Wait(100); Print(['SCORE ', Str(T)]); Wait; Print(' *GAME OVER!!*');
&End;
{ --- ここまで --- }
end;
except
end;
end;
{$HINTS ON}
オリジナルの BASIC リストと見比べてみてください。命令がメソッド (関数) に、if 文のマルチステートメント (:
区切り) が複合文 (begin~end
) になったくらいの違いしかありません。Dephi (Pascal) ではこのような 行番号 BASIC に寄せた書き方も可能です。
Delphi (Pascal) は可変個引数を扱えないため、Print()
や Pause()
で複数の値を同時に指定するには、Print([A, 123])
のように、中括弧を使って記述します。これは 型可変オープン配列パラメータ と呼ばれるものです。
遊んでみよう!
コンパイルして実行 (〔F9〕
) してみると、次のような画面になります。エディットボックスには普通に文字を入力できますが…
[開始] ボタンを押すとゲームが開始されます。
ゲームオーバーになったら〔Enter〕キーで元の画面に戻ります。
入力されていた文字も元に戻ります。
くれぐれも仕事で使うアプリケーションに組み込まないでくださいね。バレて怒られても私は責任を取りません (w
バグ発見
ん?ゲーム中に [x]
で閉じた時にすぐにゲームが終了しませんね。スレッドの終了を調べずにキーループを回しているため、体力のカウントダウンが終わるまではスレッドを抜けられないようです。キーループ内に一行追加して、すぐにスレッドを抜けられるようにしましょう。
130:Wait(50); Print(['(', Str(X), ',', Str(Y), ') D=', Str(L), ' E=', Str(E)]);
if Terminated then Exit; // 追加
150:S := S + 1; E := F - Int(S / 2);
if E <= 0 then goto 500;
G_ := INKEY; if G_ = #$00 then goto 130;
音ウルサイ
PC-1246 相当のプログラムに改変してください。キー入力や接近時の BEEP で処理が止まらないので難易度は少し上がるかもです。
改造して遊ぶ
ソースコードのあるゲームは改造して遊ぶのも楽しいです!
- BASIC でいう 20 行目の E の値 (現在の体力) や F の値 (体力最大値) をいじると難易度を変更できます。
- BASIC でいう 130 行目の
Wait(50)
の値を小さくすると難易度が上がります (64 = 1s)。 - エディットボックスの幅を広げた上で、BASIC でいう 130 行目の
Print()
を 次のように書き換えると虫の位置が判ります。
130:Wait(50); Print(['(', Str(X), ',', Str(Y), ') D=', Str(L), ' E=', Str(E), ' (', Str(A), ',', Str(B), ')']);
おわりに
Pascal で限りなく BASIC に近いコードを書いてみましたが、いかがだったでしょうか?
Delphi Advent Calendar 2022 に間に合わせるために急いで作ったのであまりいいコードではないと思います。識者の方に添削して頂けると幸いです m(_ _)m
More ポケコンゲーム移植
グラフィック機能等を使っていなければ、他のゲームも移植可能です。この記事で使われている uPokecomUtils.pas
はすべての BASIC 命令を実装していないので、適宜命令を実装する必要はあります。
スレッドクラスの Execute メソッドに、BASIC コードの移植を書けばいいだけなので楽ちんです。Delphi (Pascal) の文法を詳しくない方でも、あのコードなら結構読めると思うんですよね。
折角なので、ポケコンゲーム移植用のスケルトンプロジェクトを用意してみました。
ゲームロジック以外は記述されていますので、
- Delphi Community Edition を DL してインストール。
- スケルトンを DL して適当な場所に解凍し、Delphi で
[ファイル | プロジェクトを開く]
で開く。 - ゲームロジックを組み込み。
-
〔F9〕
でコンパイル&実行。
これだけで「追いかけマン」が動作します 2。
FireMonkey への移植
キー入力待ちにプラットフォーム依存の機能を使わなかったので、FireMonkey への移植は難しくないと思います。面倒なのは BEEP くらい?
See also