/*
引用：

「反射フラグ」について
 2進数を4ビットのフラグとして使用しています。
 上位ビットから「上」「左」「右」「下」の壁を意味し、フラグがON(=1)になっている壁で反射します。
 「上=8」「左=4」「右=2」「下=1」として、反射させたい壁の数字を合計したものを引数に与えてください。
 例えば4ビットすべてがONになっている「15」を引数として与えると全ての壁で反射しますが、
 4ビットすべてがOFFになる「0」を与えるとどの壁でも反射しません。
 また、第2ビットと第3ビットがONになっている「6」を与えると、左右の壁でのみ反射します。
*/

// 関数本体
function CreateReflectShot02(PosX,PosY,Speed,Angle,Accelerate,MaxSpeed,Graphic,Delay,Wall,Count,Frame) {
    let Obj = Obj_Create(OBJ_SHOT);

    // オブジェクト弾の基本パラメータを設定します。
    Obj_SetPosition(Obj,PosX,PosY);
    Obj_SetSpeed(Obj,Speed);
    Obj_SetAngle(Obj,Angle);
    ObjShot_SetGraphic(Obj,Graphic);
    ObjShot_SetDelay(Obj,Delay);
    //ObjShot_SetBombResist(Obj,true);

    // 描画領域を超えても自動削除は行わないように設定します。
    Obj_SetAutoDelete(Obj,false);

    // タスクを呼び出して反射制御を行います。
    CreateReflectShot02Task(Obj,Accelerate,MaxSpeed,Wall,Count,Frame);

    // 生成したオブジェクトを示す値を返り値に返します。
    return Obj;
}

// 反射制御を行うサブタスク
task CreateReflectShot02Task(Obj,Accelerate,MaxSpeed,Wall,argCount,argFrame) {
    let Count = argCount;
    let CountFlag = (Count > 0);
    let Frame = argFrame;
    let FrameFlag = (Frame > 0);
    let Top = (floor(Wall / 8) == 1);
    let Left = (floor((Wall % 8) / 4) == 1);
    let Right = (floor((Wall % 4) / 2) == 1);
    let Bottom = (Wall % 2 == 1);
    let X = Obj_GetX(Obj);
    let Y = Obj_GetY(Obj);
    let Speed = Obj_GetSpeed(Obj);
    let Angle = Obj_GetAngle(Obj);

    // 弾が画面外に生成されていた場合、
    // 　弾の速度と角度から、弾が画面内に入れるかどうかを計算します。

    // X軸方向、Y軸方向それぞれに1フレームごとに進む量を計算します。
    let OneStepX = cos(Angle) * Speed;
    let OneStepY = sin(Angle) * Speed;

    // X軸方向で弾が画面内に入るフレーム、画面外に出るフレームを計算します。
    let InFrameX = (GetClipMinX - X) / OneStepX;
    let OutFrameX = (GetClipMaxX - X) / OneStepX;
    if (InFrameX > OutFrameX) {
        let Work = InFrameX;
        InFrameX = OutFrameX;
        OutFrameX = Work;
    }

    // Y軸方向で弾が画面内に入るフレーム、画面外に出るフレームを計算します。
    let InFrameY = (GetClipMinY - Y) / OneStepY;
    let OutFrameY = (GetClipMaxY - Y) / OneStepY;
    if (InFrameY > OutFrameY) {
        let Work = InFrameY;
        InFrameY = OutFrameY;
        OutFrameY = Work;
    }

    // X軸方向に入る前にY軸方向から抜けてしまう場合、
    // またはY軸方向に入る前にX軸方向から抜けてしまう場合、
    // 弾は画面内に入る弾道ではないため、弾オブジェクトを削除します。
    if ((InFrameX > OutFrameY)||(InFrameY > OutFrameX)) {
        Obj_Delete(Obj);
    }

    // 弾が削除されるか、画面内に入るまで待ちます。
    while (Obj_BeDeleted(Obj) == false) {
        X = Obj_GetX(Obj);
        Y = Obj_GetY(Obj);
        Speed = Obj_GetSpeed(Obj);

        // 弾が画面内に入った場合、ループを抜けます。
        if ((X >= GetClipMinX)&&(X <= GetClipMaxX)&&(Y >= GetClipMinY)&&(Y <= GetClipMaxY)) {
            break;
        }

        // 弾の加速処理を行います。
        if (Accelerate > 0) {
            if (Speed + Accelerate < MaxSpeed) {
                Obj_SetSpeed(Obj,Speed + Accelerate);
            }
        } else if (Accelerate < 0) {
            if (Speed + Accelerate > MaxSpeed) {
                Obj_SetSpeed(Obj,Speed + Accelerate);
            }
        }

        yield;

        // 生存フレーム判定フラグがオンになっている場合、
        // 　弾の生存フレーム数を更新します。
        // 　生存フレーム数が尽きた場合、オブジェクトを削除します。
        if (FrameFlag == true) {
            Frame -= 1;
            if (Frame <= 0) {
                ObjShot_FadeDelete(Obj);
            }
        }
    }

    // 弾が削除されるまで、反射判定と反射処理を繰り返します。
    while (Obj_BeDeleted(Obj) == false) {
        X = Obj_GetX(Obj);
        Y = Obj_GetY(Obj);
        Speed = Obj_GetSpeed(Obj);
        Angle = Obj_GetAngle(Obj);

        // 反射したかどうかを判定します。
        // 　①座標が描画範囲を超えていること（＝弾が壁を越えたこと）
        // 　②座標が越えた壁が、反射対象になっていること
        // 　③反射回数が残っていること、または反射回数判定フラグがオフになっていること
        // この３つの条件をすべて満たした場合のみ、反射処理を行います。
        if (Y < GetClipMinY) {
            if ((Top == true)&&((Count > 0)||(CountFlag == false))) {
                Y = (GetClipMinY * 2) - Y;
                Angle = 0 - Angle;
                Count -= 1;
            } else {
                ObjShot_FadeDelete(Obj);
            }
        }
        if (Y > GetClipMaxY) {
            if ((Bottom == true)&&((Count > 0)||(CountFlag == false))) {
                Y = (GetClipMaxY * 2) - Y;
                Angle = 0 - Angle;
                Count -= 1;
            } else {
                ObjShot_FadeDelete(Obj);
            }
        }
        if (X < GetClipMinX) {
            if ((Left == true)&&((Count > 0)||(CountFlag == false))) {
                X = (GetClipMinX * 2) - X;
                Angle = 180 - Angle;
                Count -= 1;
            } else {
                ObjShot_FadeDelete(Obj);
            }
        }
        if (X > GetClipMaxX) {
            if ((Right == true)&&((Count > 0)||(CountFlag == false))) {
                X = (GetClipMaxX * 2) - X;
                Angle = 180 - Angle;
                Count -= 1;
            } else {
                ObjShot_FadeDelete(Obj);
            }
        }

        // 弾の加速処理を行います。
        if (Accelerate > 0) {
            if (Speed + Accelerate < MaxSpeed) {
                Obj_SetSpeed(Obj,Speed + Accelerate);
            }
        } else if (Accelerate < 0) {
            if (Speed + Accelerate > MaxSpeed) {
                Obj_SetSpeed(Obj,Speed + Accelerate);
            }
        }

        Obj_SetPosition(Obj,X,Y);
        Obj_SetAngle(Obj,Angle);

        yield;

        // 生存フレーム判定フラグがオンになっている場合、
        // 　弾の生存フレーム数を更新します。
        // 　生存フレーム数が尽きた場合、オブジェクトを削除します。
        if (FrameFlag == true) {
            Frame -= 1;
            if (Frame <= 0) {
                ObjShot_FadeDelete(Obj);
            }
        }
    }
}

