0_0_57D

 obake   specification   version 

デバッグ中。条件が絞られ、直すべき位置も把握できつつある。

PK_Set_WTimer() から mv_Exits_B のつながりまでは見えてきた。

Physics がキャンセルされたら、この mv_Exits_B 関数が次ステップに機能するらしい( 半年前のコードなので、完全に忘れている ) 。ここで更に追跡して行くと、a.TiD と a.TiDBak が共に -4 == noone となる位置が判明。すると PK_Set_WTimer 関数での処理を一部修正すれば対応できる。

デバッガでの追跡は諦めた

バグがあることはわかっているので、潜んでいるバグを追跡し追い詰めるためには工夫が必要に成る。エンバグ条件が絞られたのは幸い。

特定オブジェクトの変数値を常時監視するデバッグ用関数を作成。

監視したいオブジェクトにカーソルをあわせて、マウスのミドルボタンクリック、もしくはキーボードの CTRL キーを押しながらカーソルをあわせれば、そのオブジェクトを「監視対象」にできる。

「監視対象」となったオブジェクトは特定の変数だけを毎 STEP チェック、値が不正になった時点でエンバグ。つまり関数の実行されるタイミングをコード内で様々変えながら範囲を求め、求められた範囲を徐々に狭めながら、値が不正になる瞬間まで追い詰め正確な位置を特定する作業へとりかかった。

以下がデバッグ用の専用関数。簡単な仕組みだ。

Check_TiDandTiDBak();/* Debug for 0_0_57C */

///Check_TiDandTiDBak();
var a;

a = global.FiXeDVaLuE;

if (a != noone)
{
with (a)
{
if (TiD == noone)
{
if (TiDBak == noone)
{

show_message("#Check_TiDandTiDBak: both TiD & TiDBak are noone!");


};
};
};
};

Get_SpecificObjectID

///Get_SpecificObjectID();
if (mouse_check_button_pressed(mb_middle) or keyboard_check_pressed(vk_control))
{
    var a;
    a = collision_point(mouse_x,mouse_y,tile,false,true);
    if (a != noone) 
    {
         global.FiXeDVaLuE = a; 
    };
//show_message(a);
};

global.FiXeDVaLuE = noone;

トレース用のロジックは簡単な関数の組み合わせでできている。デバッグ用にグローバル変数を一つ宣言。トレースするオブジェクトと変数の内容は状況に応じて随時変更していく。

その後

mv_Exits_B で処理がおかしい部分を修正したが、まだ値をどこかで弄っている関数がある。値を狂わせている処理が二重ではなく、三重になっているっぽい。一箇所コードを直しても次のバグが生まれるのはここか、簡単に見つからないわけだ。それも追い詰めつつある。

重力機能が終了する際に、動かしたタイルの値を初期化しなおす処理が Phy_SToppinG 関数であり、ここにも不具合があった。少し変数に追加が必要となったため、タイルのオブジェクトに PHyCanFLG == false; をインスタンス変数として追加。

この変数は PK_Set_WTimer 関数で例外が検出された場合にフラグが TRUE 化され、mv_Exits_B 関数はこのフラグの状態で例外が検出されたことを知ってから、実行される変数処理の内容を変える。

PK_Set_WTimer 関数は結果的に条件を探す処理が大幅に増えた。

PK_Set_WTimer

    if (TAFlag == true)
    {
      AddVspeeD = true; /*  to Physics Canseller.  */
        if (a == ev.PickTiID)
        {
            if (DownWell  == false)
            {
                //Check_TiDandTiDBak();/* # D E B U G #     for 0_0_57C  */
                d      = TiDBak;// (d   = noone;)
                TiDBak = TiD;
                TiD    = d;     // (TiD = noone;)
                }
            else
            {
                //Check_TiDandTiDBak();/* # D E B U G #     for 0_0_57C  */
                show_message("PK_Set_WTimer.DownWell == true: ??");
            };
        }
        else
        {
            d = ev.PickTiID;
              if (d != noone)
              {
                   if (instance_exists(d) == true)
                   {
                       with (d) 
                       {
                           if (TAFlag == true)//mv_Action() or PickTileQueA or mv_A()
                           {
                               //Check_TiDandTiDBak();/* # D E B U G #     for 0_0_57C  */
                               AddVspeeD   = false;// Physics Canncelled. >> will be run the function of "mv_Exits_B()".
                               PHyCanFLG   = true;
                           }
                           else 
                           {
                               show_message("#PK_Set_WTimer.ELSE: TAFlag = false & SwaPID = "+string(SwaPID));
                           };
                                       
                       };            
                   };
              }
              else
              {
                  show_message("#PK_Set_WTimer: ev.PickTiID is noone; & id is "+string(a)+" : SwaPID = "+string(SwaPID));
              };
        }; 
    }
    else

Phy_SToppinG 関数はこれで状態が改善したので mv_Exits_B にも同じロジックを導入。

セキュリティを多めに配置、アニメーション切替時に noone だった場合は TiDBak から値を引っ張る保険をかけておいた。

mv_Exits_B

b     = TiDBak;
    if (AddVspeeD == false)      /*      F A L S E      */
    {
        //show_message("TiD = " + string(TiD)+" && TiDBak = "+string(TiDBak));
        
            if (PHyCanFLG = true)                        /*      T R U E       */
            {
                if (b == noone) 
                {
                    b = TiD;
                    //show_message("b ="+string(b));
                };
            }
            else                                         /*      F A L S E      */
            {
                if (TiD == noone) 
                {
                    b = TiDBak;
                    //show_message("b ="+string(b));
                };
            };
        TiD    = b;
        TiDBak = noone;
        TiDID  = 0;
        b      = TiD;
        TAFlag = false;
        //show_message("TiD = " + string(TiD)+" && TiDBak = "+string(TiDBak));
    }
    else                        /*      T R U E       */
    {
        //show_message("TiD     = " + string(TiD)+"#       && #TiDBak = "+string(TiDBak));
            if (b == noone)
            {
                b   = TiD;
            };
    };

最後に Phy_SToppinG 関数を修正。

ここでは重力操作で盤面を移動させられたタイルのインスタンス変数を適切な値へ初期化する処理が含まれている。

Phy_SToppinG

//Check_TiDandTiDBak();/* # D E B U G #     for 0_0_57C  */

with(d)
{   
    /*    Clear all Status    */
    
    vspeed    = 0;
    PWaTimer  = 0;
    PEnTimer  = 0;
    PHeight   = 0;
    PPSkipCT  = 0;
    PPSkipCTD = 0;
    DownWell  = false;
    AddVspeeD = false;
    TAFlag    = false;
    
        if (PHyCanFLG == false) /*   F A L S E    */
        {
            if (TiDBak != noone)
            {
                TiD       = TiDBak;
                TiDBak    = noone;
            };
        }
        else                    /*    T R U E    */
        {
            PHyCanFLG = true;
                if (TiD == noone) 
                { 
                    TiD    = TiDBak;
                    TiDBak = noone;
                };
        };
    
    x         = ev.TDX[TX];
    y         = ev.TDY[TY];
    xstart    = x;
    ystart    = y;
    
 };

//Check_TiDandTiDBak();/* # D E B U G #     for 0_0_57C  */

重要なのは特殊なフラグ PHyCanFLG = true; が有効化された後、フラグ解除する処理は唯一 PK_Set_WTimer でしか行われないという点。

重力処理の例外を定義するフラグ

PHyCanFLG = false; がデフォルトだが、このフラグ状態の場合にはパズル操作によってタイルは重力の影響を受けて下へ落下する。

PHyCanFLG = true; の場合は例外、重力が機能することを一時的に拒否するものとして扱われる。

このフラグ定義は重要なので値を設定する場所も、再度 false 化する場所も各一箇所に決まっている。

PK_Set_WTimer —– true 化する

Phy_SToppinG —– false 化する

PK_Set_WTimer 関数で検出された例外にだけ対応しているため、その他一般的な例外にこのフラグは用いられていない。

条件はかなり特殊な操作をしない限り一般的には発生しない。ものすごく高速な操作でタイル移動させる場合に発生する処理なので、ちまちまゆっくりと操作している間はこの処理が利用されることはほぼ無い。

8-コンボとか達成、あるいはそれ以上のコンボでお化けを盤面から一気に消す場合、相当正確に毎回タイルを移動させなければならない。一見で達成できるのは CPU しかありえないが、固定マップで何度も同じパターンをプレイする場合、人間でも 8-コンボ以上は達成できる。そのレベルの難易度で操作していない限り発生しないバグと言える。




次へ

前へ