パックマンが上がると、ピンキーとインキーの動作が異なるのはなぜですか?

ゲームPac-Man(および多くのクローンと続編)で、PinkyとInkyの幽霊がPac-Manを追いかけ、彼が移動する方向を考慮して、追従するポイントを決定することがわかりました。 たとえば、ピンキーは通常、ポイントの後に続きます。このポイントは、パックマンアから移動方向に4ユニットのところにあります。 ただし、パックマンが上に移動した場合、この目的地は、パックマンに対して4ユニット上および4ユニット左にあるポイントになります。 パックマンが上に移動するとき、ゴーストインクは同様の動作をします。 パックマンが上がると、ピンキーとインキーの動作が異なるのはなぜですか?



要するに、私の意見では、ソフトウェアのバグが原因です。 これが証拠です。







パックマンは、少なくとも2つの方法で方向をエンコードします。 1つの方法Pac-Manは、1バイトを使用して、右= 0、下= 1、左= 2、上= 3の値で方向を書き込みます。



別の方法は、パックマンが2バイトのペアを使用して方向を書き込み、次の方法で方向ベクトルを書き込む場合です。 すべての16進値は接頭辞#で書き込まれ、アドレス#32FFから#3306までのメモリ位置で表示できます。



右=(#FF、00)



ダウン=(00、01)



左=(01、00)



アップ=(00、#FF)



#FF(10進数の255)は、8ビットのZ80数学では-1として使用されます。 例を考えてみましょう:







ポイントの座標(XX、YY)は16進表記で示されます。 パックマンをポイント(#26、#2F)にします。



ゲームは、指定されたポイントの座標に2バイトの方向ベクトルを追加することにより、指定されたポイントを囲む4つのポイントの位置を計算します。



Pac-Man´aの右側のポイントの位置を計算するには、2バイトの数字「右」(#FF、00)を(#26、#2F)に追加する必要があります。 FFは-1として使用されるため、Pac-Man´aの右側にあるポイント(#25、#2F)の座標を取得します。 パックマン以下のポイントを計算するには、2バイトの数字「下」(00.01)を(#26、#2F)に追加する必要があります。 パックマンの真下にあるポイント(#26、#30)を取得します。 Pac-Man’aの左側のポイントの位置を計算するには、2バイトの数字「左」(01.00)を(#26、#2F)に追加する必要があります。 Pac-Man´aの左側にあるポイント(#27、#2F)を取得します。 パックマンの上にあるポイントの位置を計算するには、2バイトの「アップ」番号(00、#FF)を(#26、#2F)に追加します。 FFは-1として使用されるため、ポイントの座標(#26、#2E)を取得します。これは、パックマンの真上にあります。



これらはすべて、単位座標を個別に操作する場合にのみ正しく機能します。これは、可能な負の数の存在を考慮して、これらの算術演算を実行する唯一の正しい方法です。 たとえば、#2000のコードには、これらのアクションを正しく実行する手順があります。



 2000 FD7E00 LD A、(IY +#00);  Y座標をレジスタAにロードします
 2003 DD8600 ADD A、(IX +#00); 変位ベクトルのy座標を追加します
 2006 6F LD L、A; 結果をLに保存
 2007 FD7E01 LD A、(IY +#01);  X座標をレジスタAにロードします
 200A DD8601 ADD A、(IX +#01); 変位ベクトルのx座標を追加します
 200 D 67 LD H、A; 結果をHに保存
 200E C9 RET; 帰る




この手順は、2バイトのレジスタペアHLの新しい位置を、レジスタIYで指定された特定の初期位置と、レジスタIXで指定された方向ベクトルにロードするために使用されます。 X座標とY座標の追加は別々に行われるため、正常に機能します。



この問題は、たとえば、ピンキーのターゲットポイントをゲームが計算しようとすると発生します。 ゲームコードでは、ピンキーのターゲットを、パックマンの移動方向に対して4ポイントのポイントとして定義しています。



この点を計算するために、コードはPac-Manの方向ベクトルを取得し、それをそれ自体に追加して、それを倍にします。 次に、結果を2倍にして、元の値の4倍の値を取得します。 問題は、X座標とY座標が別々に加算されず、同時に加算されることです。 アップベクトルを計算すると、バグが発生します。 以下は、パックマンのZ80用アセンブラコードからの抜粋です。コードを含むコードが強調表示されています。



 ; パックマンピンキーターゲティングサブルーチン

 278E ED5B394D LD DE、(#4D39);  DEのPac-Man´aの位置にロードする
 2792 2A1C4D LD HL、(#4D1C);  HLパックマンの方向ベクトルにアップロードする
 2795 29 ADD HL、HL;  [バグ!!!]ダブルパックマンの方向ベクトル
 2796 29 ADD HL、HL;  [バグ!!!] 4倍のパックマンの方向ベクトル
 2797 19 ADD HL、DE;  [バグ!!!]目標位置を取得するために結果を位置に追加します




次の表に、この手順の結果を示します(パックマンのゼロポジションに対する)。

ベクター名 HLの初期値と結果 2xHLと結果 4xHLと結果
右へ #FF00(-1.0) #FE00(-2.0) #FC00(-4.0)
ダウン #0001(0,1) #0002(0.2) #0004(0.4)
左へ #0100(1,0) #0200(2,0) #0400(4.0)
上へ #00FF(1、-1) #01FE(2、-2) #03FC(4、-4)




HLは、Z80の2バイトのレジスタペアです。 行#2792では、ベクトルのX座標がHにロードされ、ベクトルのY座標がLにロードされます。



右方向のベクトルが処理されているとき、HLには#FF00が含まれます。 行2792の命令はこの値を単独で追加します。その後、レジスタペアHLには#FE00が含まれ、レジスタHのオーバーフローにより転送フラグが設定されます。ただし、プログラムは転送フラグを無視し、数値のみを使用します。 。 行番号2796で2倍になると、HLに値#FC00が表示されます。これは正しい値-4です。 キャリーフラグは無視されます。 Pac-Manの位置で加算が発生すると、転送の結果として転送フラグが再度設定されます。これは、他の問題では、プログラムによって再び無視されます。 目的の結果が達成されます。新しいポイントは、Pac-Man´aの4ユニット右にあります。



アクションのバグ





ただし、上方向のベクトルが使用されると、行#2792で#00FFがレジスタペアHLにロードされます。 次の行でダブリングが発生すると、HLには#01FEが含まれます。 「右」方向のベクトルを処理するときのようにオーバーフローフラグを破棄する代わりに、Y座標を2倍にすると、転送フラグがX座標に転送されてオーバーフローが発生します。左へ。 次の2倍にすると、値#03FCが得られます。これは、パックマンの座標に追加すると、4ポイント上および左に新しいポイントになります。







これはバグであり 、同じコマンドが4つの方向すべてに使用されるため、 意図的なものではないと考えています。 言い換えると、 コードは「上」方向を処理するための別個の手順を開始しませんが、「上」方向については、手順は他の方向とは異なる予期しない結果をもたらします。 問題の低レベルの性質を考えると、プログラマーがこれを認識していたとは思えません。 彼らがこれを知っていたなら、彼らは明らかにこの問題を無視した。 それにもかかわらず、私は彼らがそれについて知っていたら彼らがこのバグを残すことを疑う。



All Articles