人生

やっていきましょう

848日目

倉庫番のギミックを発展させた新たなギミックを思いついたので忘れないうちにメモに書き留めた。しかしあまりに複雑な構造をしているので、書き込んでいる内に全体像を見失い本当にこれが機能するのかどうかまったく分からなくなった。一度記録にまとめて自分の理解を確認した方が良いと判断した。

自分が実現しようとしているのは岩を所定の位置に運ぶギミックに、スイッチで切り替わる足場と岩をワープさせる床を混ぜたものだ。スイッチで切り替わる足場と倉庫番の方は以前実装しておりそれらを援用すればいいだけの話だが、問題は岩をワープさせる床にある。

ただ単に岩をワープさせる床に乗せて飛ばすだけならば話は簡単だ。倉庫番のときと同じように、ワープ地点の座標と岩の座標が一致した場合にイベントを指定の座標に移動させればよい。

問題はそのワープ地点の向こう側に岩が存在する場合である。A地点に岩を運びA地点からB地点に岩を送ったあと、自分がそのワープ床に乗るとA地点から飛ばされた岩と重なってしまう。あるいはA地点から岩を飛ばさずとも、既にB地点に岩を乗せていた場合、A地点から自分が飛ぼうとすると同じように岩と重なってしまう。そのため岩がB地点にありながら自分がA地点に入った場合、ワープが失敗するという条件を加えなければならない。

一見簡単なように見えるが、マップにあるのはA地点とB地点の1組だけではない。C~Hを含めた8つのワープ地点、4組の経路の判定を行わなければならない。更に動かす岩はひとつだけではなく、異なる3つの岩を動かす必要がある。

更にそればかりではなく、たとえばB地点に既に岩が置いてある場合、そこからその岩を動かしたらワープが失敗する判定を無効化するように条件づけなければならない。この作業を忘れると、邪魔な岩を動かしてもワープが使えないままである。またこの種のイベントをどのような呼び出し形式で行うのか、ということも考えなければならない(並列実行か?岩を押した際にその都度個別に発動させるか?)。

こうしてみると、全体を見渡せば途方もなく複雑な処理を行うことになり、頭が混乱して何も考えられなくなる。やはりワープのギミックは断念すべきだろうか。

ただとりあえずはやれるだけのことをやってみる。直感的にみて実現不可能なものではなく、論理が正しければ機能するという確信が自分にはあった。ひとつひとつ分かるところからやっていこうと思う。

 

まずそもそも、ワープに関するイベントの呼び出しをどのようにすべきか。はじめは並列実行にすればひとつのイベントで処理できて管理しやすいと考えたが、実行のタイミングが選べないのが難点だった。座標の取得、ワープの実行、ゴールの判定などは、岩を押すイベントを実行した際に行うべきだと考えた。

そしてこの処理は倉庫番の時と同様、動かす個々の岩で処理すべきだと考えた。岩を3つ用意して、岩ごとに長い処理を行わせるのはどこか無駄だと思ったが、各々の岩が押されたことを起点としてイベント処理が行われることを考えると、やはり個別に実装すべきだという考えに至った。とはいえこれらのイベントは基本的にすべて同じものであり、1つのイベントを完成させればあとはコピー&ペーストをして細部をいじるだけでいい。

 

【岩を押すイベントを実行】した際に【個々の岩】が全体の処理や判定を行う、ということは確定した。つぎにワープに関してどのような処理を行えば良いか。

基本的には倉庫番のイベントに書き加えるだけである。岩を押した後と座標取得によるゴールの判定の間にワープの判定を独立して書き加える。

処理は以下のように行う。まずすべての岩の座標を取得してその数値を各々に対応する変数に代入する。ここでは岩A~Cの3つを用意するので、座標変数Ax,Ay、座標変数Bx,By、座標変数Cx,Cyの計6つを用意して代入する(新たに変数を設けるよりは、どこかのイベントのセルフ変数を利用した方が良いだろう)。

ここで「押した岩」と「置いてある岩」を分けて考える。「押した岩」とは押すイベントを起動させたイベント本体であり、「置いてある岩」とはそれ以外の岩である。

「押した岩」は倉庫番関連のイベントと「岩をワープ床に移動させた際のイベント」、そして「ワープ床から岩を移動させた際のイベント」で扱い、「置いてある岩」は「ワープ床に岩が乗っているかどうかの判定」を行うために扱う。それぞれの操作は岩のイベント内で行うが互いに干渉しない独立した条件であり、何か不具合が発生した場合は越境して影響を及ぼすことがまずないと考えられる。

はじめに「置いてある岩」の処理を行う。ここでは先に述べたように「ワープ床に岩が乗っているかどうかの判定」を行う。まず「置いてある岩の座標が8つのワープ地点のいずれかと一致しているか」という条件を判定する。すなわち岩A、岩B、岩Cの座標が、各々ワープ地点A~Hの座標のいずれかと一致するかどうかを判定する(途方もなく面倒だが地点Aから地点Hまでひとつひとつ判定を行う)。

一致する場合、そのワープ地点とそれに対応するワープ地点の2つを起動できないようにするために、新たな管理用の変数を設けそこに1を代入する。1が代入されている限りこのワープ経路は使用できない。

(はじめ自分は個々の地点に対して移動制限を管理する変数を設け、ワープ床の上に障害物がある場合に1を代入、ない場合には0を代入して、ワープ床で制限が発動する条件が管理変数が1であるようにすることを考えたが、わざわざ8つの地点を網羅する必要はなく、1つの組で考えれば手間が省けるということに気づいた。すなわち地点Aに制限がかかれば地点Bにも制限がかかるというように地点A,B間で管理変数を共有するということである)

一致しない場合、処理はそこで終わり何もしない。

これで「置いてある岩」の処理は終わる。つぎに「押した岩」の処理を行う。ここでは「岩をワープ床に移動させた際のイベント」、「ワープ床から岩を移動させた際のイベント」のいずれかを行う。

まず一番はじめに次のような条件を判定する。すなわち「押した岩の座標が8つのワープ地点のいずれかと一致するか」である。

一致する場合、新たな条件を判定する。その条件とは「一致した地点の座標と対応するワープ経路の管理変数に1が代入されているか」である。もし1が代入されているのであれば既に岩が対応するワープ地点に置かれているということであり、岩がワープすることはできない。よって処理はそこで終わり床の上に乗っても岩はワープしない。1が代入されていないのであれば、対応するワープ地点に岩が置かれていないということなので、岩を対応するワープ地点に送り管理変数に1を代入する。

一致しない場合、次の条件を判定する。すなわち「押される前の岩の座標が8つのワープ地点のいずれかと一致するか」である。一致する場合、岩を押す前に既にワープ地点にあったことを示しており、押したことによってワープ地点から外れたことを意味するので、対応するワープ経路の管理変数に0を代入する。一致しない場合、岩は既にワープ地点には存在しなかったことが明らかになるので、処理はそこで終わり何もしない。

これまで書いたことをまとめると以下のようになる。ここでは分かりやすく

 

 

●岩A、岩B、岩Cの座標を取得
 押した岩(岩A)と置いてある岩(像B,C)を分けて考える


>>置いてある岩の判定
●【条件】置いてある岩が8つのワープ地点のいずれかの座標と一致するか?
│ この場合、岩B,C,Dがワープ地点の座標と一致するか各々判定

●一致する場合、その組のワープ経路が使えなくなるよう管理変数に1を代入
●一致しない場合、何もしない
(この条件は独立させる)


>>押した岩の判定
●【条件】押した岩が8つのワープ地点のいずれかの座標と一致するか?
│この場合、岩Aがワープ地点の座標と一致するか各々判定

●一致する場合、更につぎの条件を判定する
│【条件】一致した座標と対応するワープ経路の管理変数に1が代入されているか?
│ │
│ │
│ ●1が代入されている場合、処理はそこで終わり岩はワープしない
│ ●1が代入されていない場合、対応するワープ地点に岩を飛ばし管理変数に1を代入する


●一致しない場合、次の条件を判定する
 【条件】押される前の岩の座標が8つのワープ地点のいずれかと一致するか
  │
  │
  ●一致する場合、対応するワープ経路の管理変数に0を代入する
  ●一致しない場合、処理はそこで終わり何もしない

 

これでおそらく機能するはずである。と書いてみたがこれでうまくいく自信がまったくない。全体像を見えないまま処理を行う自信がなかったのでテストプレーをする前にこれを書き記した。いまからこの処理を岩に書き込み、うまく機能するかどうかテストする。明日にはその結果を書き記す。