tips 0023 score drum roll - cwtickle/danoniplus GitHub Wiki

^ Tips Indexに戻る

| < ステップゾーンや矢印全体を一時的に隠す | スコアドラムロールの作成 | カスタム画面の作成 > |

スコアドラムロールの作成

  • カスタムJSを使って、スコア独自計算式&プレイ画面でのドラムロールを実装します。
  • ここでは例として、izkdicさん(Type2)・FUJIさんサイト(Type3)での計算式の実装例を記載します。

タイトル画面

  • 計算に必要な基礎情報をセットします。
  • 作品によって計算式を変えるため、あらかじめカスタム譜面ヘッダーとしてscoreTypeを定義し、「Type2」「Type3」のときに独自の計算が行われるようにします。
g_customJsObj.title.push(() => {
    // 初項
    g_headerObj.calcFirstTerm = 0;
    // 公差
    g_headerObj.calcDifference = 0;
    // フリーズ基本点
    g_headerObj.calcFreeze = 0;
    // 得点率 (誤差フレーム数毎に定義)
    g_headerObj.calcScoreRates = [100, 99, 95, 80, 60, 30];

    // スコア除数(Type3用)
    g_headerObj.cutRate = 0;
    // 基準コンボ数(Type3用)
    g_headerObj.cutCombo = 0;

    // scoreTypeにより計算式を切り替える。デフォルトは"Type1"
    if (g_rootObj.scoreType === undefined) {
        g_rootObj.scoreType = `Type1`;
    } else if (g_rootObj.scoreType === `Type3`) {
        // Type3のときは判定強制変更(暫定)
        g_judgObj.arrowJ = [1, 3, 5, 7, 7];
        g_judgObj.frzJ = [1, 5, 7];
    }
});

設定画面

  • 設定画面でどの計算式かが判別できるように、Difficultyの真下にカスタムラベルを作成します。
  • 計算式が独自(Type1以外)のとき、その計算タイプを表示するようにします。
g_customJsObj.option.push(() => {
    if (g_rootObj.scoreType !== `Type1`) {
        multiAppend(difficultySprite,
            createDivCss2Label(`local_lblScType`, `Score: ${g_rootObj.scoreType}`, {
                x: 13, y: 17, w: g_sWidth, h: g_limitObj.setLblHeight, siz: 12, align: C_ALIGN_LEFT,
            })
        );
    }
});

ロード画面

  • プレイ画面で必要となる設定の下準備を行います。
  • ドラムロールの場合、実際のスコアとドラムロール上のスコアに差が生じるのでそれぞれ別変数を用意します。
  • Type2の場合は、カスタム譜面ヘッダーとして「calc_data」を使用します。
  • |calc_data=2000,40,1500|のように使い、「初項」「交差」「フリーズ基本点」を表します。
g_customJsObj.loading.push(() => {
    // 実際のスコア
    g_resultObj.realScore = 0;
    // ドラムロール上のスコア
    g_workObj.viewScore = 0;
    // 実際のスコア - ドラムロール上のスコア
    g_workObj.tempScore = 0;
    // 桜点(Type3用)
    g_workObj.sakuraScore = 0;

    // スコア機構
    if (g_rootObj.scoreType === `Type2`) {

        let scoreIdHeader = ``;
        if (g_stateObj.scoreId > 0) {
            scoreIdHeader = Number(g_stateObj.scoreId) + 1;
        }

        // 譜面データより初項、公差、フリーズ基本点を取得
        if (hasVal(g_rootObj.calc_data)) {
            const calcs = g_rootObj[`calc` + scoreIdHeader + `_data`].split(`,`);
            g_headerObj.calcFirstTerm = parseInt(calcs[0]);
            g_headerObj.calcDifference = parseInt(calcs[1]);
            g_headerObj.calcFreeze = parseInt(calcs[2]);
        }

    } else if (g_rootObj.scoreType === `Type3`) {

        // 基準コンボ数は総ノート数÷10(小数以下切り捨て)
        // 計算結果が1未満になった場合は1とする
        g_headerObj.cutCombo = (g_fullArrows > 10) ? Math.floor(g_fullArrows / 10) : 1;

        // スコア除数は総ノート数÷100
        // 計算結果が1未満になった場合は1とする
        g_headerObj.cutRate = (g_fullArrows > 100) ? g_fullArrows / 100 : 1.00;
    }
});

プレイ画面

  • 実際にドラムロールを表示する処理を実装します。

// プレイ初期時の動作
g_customJsObj.main.push(() => {
    // スコアドラムロールのラベル作成
    if (g_rootObj.scoreType === `Type2` || g_rootObj.scoreType === `Type3`) {
        const judgeSprite = document.getElementById(`judgeSprite`);

        multiAppend(judgeSprite,
            createDivCss2Label(`local_lblScore`, `Score:`, {
                x: g_sWidth * 3 / 4, y: g_headerObj.playingY + g_headerObj.playingHeight - 30, w: g_sWidth / 4 - 50, h: 30,
                siz: 14, color: `#ffffff`, align: C_ALIGN_LEFT, fontFamily: C_LBL_BASICFONT,
            }),
            createDivCss2Label(`local_lblScoreRoll`, g_workObj.viewScore, {
                x: g_sWidth / 2, y: g_headerObj.playingY + g_headerObj.playingHeight - 30, w: g_sWidth / 2 - 10, h: 30,
                siz: 14, color: `#ffffff`, align: C_ALIGN_RIGHT, fontFamily: C_LBL_BASICFONT,
            }),
        );

        // DisplayオプションでScoreが「OFF」のときは非表示にする
        if (g_stateObj.d_score === C_FLG_OFF) {
            local_lblScore.style.visibility = `hidden`;
            local_lblScoreRoll.style.visibility = `hidden`;
        }
    }
});

// フレームごとに行う処理
g_customJsObj.mainEnterFrame.push(() => {
    // スコアドラムロール処理
    // 実スコアの乖離が大きいほど加算量を増やす
    if (g_rootObj.scoreType === `Type2` || g_rootObj.scoreType === `Type3`) {
        if (g_resultObj.realScore > g_workObj.viewScore) {
            g_workObj.tempScore = g_resultObj.realScore - g_workObj.viewScore;
            if (g_workObj.tempScore < 100) {
                g_workObj.viewScore += 1;
            } else if (g_workObj.tempScore < 1000) {
                g_workObj.viewScore += 11;
            } else if (g_workObj.tempScore < 10000) {
                g_workObj.viewScore += 111;
            } else if (g_workObj.tempScore < 100000) {
                g_workObj.viewScore += 1111;
            } else {
                g_workObj.viewScore += 11111;
            }
            local_lblScoreRoll.innerHTML = g_workObj.viewScore;
        }
    }
});

/**
 * スコア計算(回復判定)
 */
const calcArrowRcv = {
    Type1: _ => { },
    Type2: difFrame => {
        const multi = (g_resultObj.combo > 100 ? 100 : g_resultObj.combo);
        const absDifFrame = Math.abs(difFrame);
        if (absDifFrame <= 5) {
            g_resultObj.realScore += Math.floor((g_headerObj.calcFirstTerm +
            g_headerObj.calcDifference * multi) * g_headerObj.calcScoreRates[absDifFrame] / 100);
        }
    },
    Type3: (difFrame, rate = 0, plus = 0) => {
        let coeff;
        // FUJIさんソースはコンボ更新前にスコア計算を行うためその補正
        const comboTotal = g_resultObj.combo + g_resultObj.fCombo - 1;
        if (comboTotal > g_headerObj.cutCombo) {
            coeff = 2 + (comboTotal - g_headerObj.cutCombo) / g_headerObj.cutCombo / 6;
        } else {
            coeff = 1 + comboTotal / g_headerObj.cutCombo;
        }

        // スコア更新
        g_resultObj.realScore += Math.floor(coeff * rate * (100 + g_workObj.sakuraScore * 4 / g_headerObj.cutRate));
        // 桜点更新
        g_workObj.sakuraScore += plus;
    },
};

/**
 * スコア計算(ダメージ判定)
 */
const calcArrowDmg = {
    Type1: _ => { },
    Type2: _ => { },
    Type3: sakuraDif => {
        // 桜点更新、0未満になったら0にする
        g_workObj.sakuraScore -= sakuraDif;
        if (g_workObj.sakuraScore < 0) {
            g_workObj.sakuraScore = 0;
        }
    },
};

/**
 * 判定カスタム処理 (引数は共通で1つ保持)
 * @param {number} difFrame タイミング誤差(フレーム数)
 */
// イイ
g_customJsObj.judgeIi.push((difFrame) => {
    calcArrowRcv[g_rootObj.scoreType](difFrame, 1, 5);
});

// シャキン
g_customJsObj.judgeShakin.push((difFrame) => {
    calcArrowRcv[g_rootObj.scoreType](difFrame, 0.8, 4);
});

// マターリ
g_customJsObj.judgeMatari.push((difFrame) => {
    calcArrowRcv[g_rootObj.scoreType](difFrame);
});

// ショボーン
g_customJsObj.judgeShobon.push((difFrame) => {
    calcArrowDmg[g_rootObj.scoreType](50);
});

// ウワァン
g_customJsObj.judgeUwan.push((difFrame) => {
    calcArrowDmg[g_rootObj.scoreType](100);
});

// キター
g_customJsObj.judgeKita.push((difFrame) => {
    if (g_rootObj.scoreType === `Type2`) {
        g_resultObj.realScore += Math.floor(g_headerObj.calcFreeze);
    } else if (g_rootObj.scoreType === `Type3`) {
        calcArrowRcv.Type3(difFrame, 1, 5);
    }
});

// イクナイ
g_customJsObj.judgeIknai.push((difFrame) => {
    calcArrowDmg[g_rootObj.scoreType](100);
});

結果画面

  • 計算式が独自のため、結果画面にスコアを上書きします。
g_customJsObj.result.push(() => {
    // スコア計算
    if (g_rootObj.scoreType === `Type2` || g_rootObj.scoreType === `Type3`) {
        g_resultObj.score = g_resultObj.realScore;
        lblScoreS.innerHTML = g_resultObj.score;
    }
});

ページ作成者

  • ティックル

^ Tips Indexに戻る

| < ステップゾーンや矢印全体を一時的に隠す | スコアドラムロールの作成 | カスタム画面の作成 > |