danoniplus 51.1.1 → 51.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/js/danoni_main.js CHANGED
@@ -4,12 +4,12 @@
4
4
  *
5
5
  * Source by tickle
6
6
  * Created : 2018/10/08
7
- * Revised : 2026/09/29
7
+ * Revised : 2026/10/03
8
8
  *
9
9
  * https://github.com/cwtickle/danoniplus
10
10
  */
11
- const g_version = `Ver 51.1.1`;
12
- const g_revisedDate = `2026/09/29`;
11
+ const g_version = `Ver 51.2.0`;
12
+ const g_revisedDate = `2026/10/03`;
13
13
 
14
14
  // カスタム用バージョン (danoni_custom.js 等で指定可)
15
15
  let g_localVersion = ``;
@@ -267,11 +267,7 @@ const g_workObj = {
267
267
  };
268
268
 
269
269
  // 歌詞制御
270
- let g_wordSprite;
271
-
272
270
  const g_wordObj = {
273
- wordDir: 0,
274
- wordDat: ``,
275
271
  fadeInFlg0: false,
276
272
  fadeInFlg1: false,
277
273
  fadeOutFlg0: false,
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2019/11/19
8
- * Revised : 2026/09/29 (v51.1.1)
8
+ * Revised : 2026/10/03 (v51.2.0)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -1580,6 +1580,29 @@ const g_transPriority = {
1580
1580
  scale: 200,
1581
1581
  };
1582
1582
 
1583
+ /**
1584
+ * transform情報の連結
1585
+ * - 優先度の降順 (同一優先度は登録順) で半角スペース区切りに連結
1586
+ * - 要素数1・2 (矢印・フリーズアローの root / rootX) は配列生成・ソートを省略
1587
+ * @param {Map} _transformMap
1588
+ * @returns {string}
1589
+ */
1590
+ const joinTransforms = _transformMap => {
1591
+ if (_transformMap.size === 1) {
1592
+ return _transformMap.values().next().value.transform;
1593
+ }
1594
+ if (_transformMap.size === 2) {
1595
+ const it = _transformMap.values();
1596
+ const a = it.next().value;
1597
+ const b = it.next().value;
1598
+ return b.priority > a.priority ? `${b.transform} ${a.transform}` : `${a.transform} ${b.transform}`;
1599
+ }
1600
+ return Array.from(_transformMap.values())
1601
+ .sort((a, b) => b.priority - a.priority)
1602
+ .map(v => v.transform)
1603
+ .join(` `);
1604
+ };
1605
+
1583
1606
  /**
1584
1607
  * idごとのtransformを追加・変更
1585
1608
  * - _transformIdごとに transform情報を管理
@@ -1589,14 +1612,18 @@ const g_transPriority = {
1589
1612
  * @param {number} [_priority=1000] transformの優先度(数値が小さいほど優先される。デフォルトは1000)
1590
1613
  */
1591
1614
  const addTransform = (_id, _transformId, _transform, _priority = 1000) => {
1592
- if (g_transforms[_id] === undefined) {
1593
- g_transforms[_id] = new Map();
1615
+ let transforms = g_transforms[_id];
1616
+ if (transforms === undefined) {
1617
+ transforms = g_transforms[_id] = new Map();
1594
1618
  }
1595
- g_transforms[_id].set(_transformId, { transform: _transform, priority: _priority });
1596
- $id(_id).transform = Array.from(g_transforms[_id].values())
1597
- .sort((a, b) => b.priority - a.priority)
1598
- .map(v => v.transform)
1599
- .join(` `);
1619
+ const current = transforms.get(_transformId);
1620
+ if (current !== undefined && current.priority === _priority) {
1621
+ // 既存エントリは値のみ更新 (登録順は変わらない)
1622
+ current.transform = _transform;
1623
+ } else {
1624
+ transforms.set(_transformId, { transform: _transform, priority: _priority });
1625
+ }
1626
+ $id(_id).transform = joinTransforms(transforms);
1600
1627
  };
1601
1628
 
1602
1629
  /**
@@ -1605,17 +1632,15 @@ const addTransform = (_id, _transformId, _transform, _priority = 1000) => {
1605
1632
  * @param {string} _transformId
1606
1633
  */
1607
1634
  const delTransform = (_id, _transformId) => {
1608
- if (g_transforms[_id]) {
1609
- g_transforms[_id].delete(_transformId);
1610
- if (g_transforms[_id].size === 0) {
1635
+ const transforms = g_transforms[_id];
1636
+ if (transforms) {
1637
+ transforms.delete(_transformId);
1638
+ if (transforms.size === 0) {
1611
1639
  delete g_transforms[_id];
1612
1640
  $id(_id).transform = ``;
1613
1641
  return;
1614
1642
  }
1615
- $id(_id).transform = Array.from(g_transforms[_id].values())
1616
- .sort((a, b) => b.priority - a.priority)
1617
- .map(v => v.transform)
1618
- .join(` `);
1643
+ $id(_id).transform = joinTransforms(transforms);
1619
1644
  }
1620
1645
  };
1621
1646
 
@@ -1877,10 +1902,11 @@ const g_motionAlphaFunc = new Map([
1877
1902
 
1878
1903
  const motionAlphaToggle = (_obj, _property) => {
1879
1904
  const dir = (_property.y - _property.prevY) * _property.dir;
1880
- if (($id(_obj).opacity === ``) && dir > 0) {
1881
- $id(_obj).opacity = g_settings.motionAlpha;
1882
- } else if (Number($id(_obj).opacity) === g_settings.motionAlpha && dir < 0) {
1883
- $id(_obj).opacity = ``;
1905
+ const style = $id(_obj);
1906
+ if ((style.opacity === ``) && dir > 0) {
1907
+ style.opacity = g_settings.motionAlpha;
1908
+ } else if (Number(style.opacity) === g_settings.motionAlpha && dir < 0) {
1909
+ style.opacity = ``;
1884
1910
  }
1885
1911
  };
1886
1912
 
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2026/09/13
8
- * Revised : 2026/09/23 (v51.0.0)
8
+ * Revised : 2026/10/03 (v51.2.0)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -25,8 +25,6 @@ const mainInit = () => {
25
25
 
26
26
  g_currentArrows = 0;
27
27
  const wordMaxLen = g_scoreObj.wordMaxDepth + 1;
28
- g_workObj.fadeInNo = fillArray(wordMaxLen);
29
- g_workObj.fadeOutNo = fillArray(wordMaxLen);
30
28
  g_workObj.lastFadeFrame = fillArray(wordMaxLen);
31
29
  g_workObj.wordFadeFrame = fillArray(wordMaxLen);
32
30
  const mainCommonPos = { w: g_headerObj.playingWidth, h: g_posObj.arrowHeight };
@@ -176,7 +174,6 @@ const mainInit = () => {
176
174
  // 開始位置、楽曲再生位置の設定
177
175
  const firstFrame = g_scoreObj.frameNum;
178
176
  let musicStartFrame = firstFrame + g_headerObj.blankFrame;
179
- const fadeFlgs = { fadein: [`In`, `Out`], fadeout: [`Out`, `In`] };
180
177
  g_audio.volume = (firstFrame === 0 ? g_stateObj.volume / 100 : 0);
181
178
 
182
179
  // 曲時間制御変数
@@ -675,7 +672,7 @@ const mainInit = () => {
675
672
  const judgeObjDelete = {};
676
673
  g_typeLists.arrow.forEach(type =>
677
674
  judgeObjDelete[type] = (_j, _deleteName) => {
678
- delTransform(_deleteName, `root`);
675
+ delete g_transforms[_deleteName];
679
676
  g_workObj[`judg${toCapitalize(type)}Cnt`][_j]++;
680
677
  document.getElementById(_deleteName).remove();
681
678
  delete g_attrObj[_deleteName];
@@ -882,32 +879,60 @@ const mainInit = () => {
882
879
  };
883
880
 
884
881
  /**
885
- * 矢印生成
886
- * @param {object} _attrs 矢印個別の属性
882
+ * 矢印・フリーズアロー種類別の処理関数
883
+ * - AutoPlay設定(g_stateObj.autoAll)は譜面中に変わらないため、ここで解決しておき
884
+ * フレーム毎の文字列結合・プロパティ検索を避ける
885
+ * - colorChangeKey: 全体色変化の判定キー (g_workObj[colorChangeKey][フレーム数])
886
+ */
887
+ const objFuncs = {};
888
+ [`arrow`, `dummyArrow`].forEach(name => {
889
+ objFuncs[name] = {
890
+ colorChangeKey: `mk${toCapitalize(name)}ColorChangeAll`,
891
+ judgeMotion: judgeMotionFunc[`${name}${g_stateObj.autoAll}`],
892
+ judgeNext: judgeNextFunc[`${name}${g_stateObj.autoAll}`],
893
+ };
894
+ });
895
+ [`frz`, `dummyFrz`].forEach(name => {
896
+ objFuncs[name] = {
897
+ colorChangeKey: `mk${toCapitalize(name)}ColorChangeAll`,
898
+ judgeNext: judgeNextFunc[`${name}${g_stateObj.autoAll}`],
899
+ checkKeyUp: checkKeyUpFunc[`${name}${g_stateObj.autoAll}`],
900
+ judgeOK: judgeMotionFunc[`${name}OK`],
901
+ judgeNG: judgeMotionFunc[`${name}NG`],
902
+ judgeKeyUp: judgeMotionFunc[`${name}KeyUp`],
903
+ judgeDelete: judgeObjDelete[name],
904
+ };
905
+ });
906
+
907
+ /**
908
+ * 全体色変化の実行
909
+ * - 全体色変化があるフレームのみ処理を行う
910
+ * @param {number} _j
911
+ * @param {number} _k
912
+ * @param {string} _name 矢印・フリーズアローの種類 (arrow, dummyArrow, frz, dummyFrz)
913
+ * @param {string} _state Normal: 通常時, Hit: ヒット時 (フリーズアローのみ)
914
+ */
915
+ const changeColorOnFrame = (_j, _k, _name, _state) => {
916
+ if (g_workObj[objFuncs[_name].colorChangeKey]?.[g_scoreObj.frameNum]) {
917
+ changeColorFunc[_name](_j, _k, _state);
918
+ }
919
+ };
920
+
921
+ /**
922
+ * 矢印・フリーズアロー共通の属性情報の生成
923
+ * - 初期表示位置(y)もここで算出する
924
+ * @param {object} _attrs 矢印・フリーズアロー個別の属性
887
925
  * (pos: 矢印種類, arrivalFrame: 到達フレーム数, initY: 初期表示位置,
888
926
  * initBoostY: Motion有効時の初期表示位置加算, motionFrame: アニメーション有効フレーム数)
889
- * @param {number} _arrowCnt 現在の判定矢印順
890
- * @param {string} _name 矢印名
891
- * @param {string} _color 矢印色
892
- * @param {string} _shadowColor 矢印塗りつぶし部分の色
927
+ * @param {number} _j 矢印位置
928
+ * @returns {object}
893
929
  */
894
- const makeArrow = (_attrs, _arrowCnt, _name, _color, _shadowColor) => {
895
- const _j = _attrs.pos;
930
+ const makeBaseAttr = (_attrs, _j) => {
896
931
  const dividePos = g_workObj.dividePos[_j] % 2;
897
- const colorPos = g_keyObj[`color${keyCtrlPtn}`][_j];
898
-
899
- const arrowName = `${_name}${_j}_${_arrowCnt}`;
900
932
  const stepY = C_STEP_Y + g_posObj.reverseStepY * dividePos;
901
933
  const firstPosY = stepY + (_attrs.initY * _attrs.boostSpd +
902
934
  _attrs.initBoostY * _attrs.boostDir) * g_workObj.scrollDir[_j];
903
-
904
- const arrowRoot = createEmptySprite(arrowSprite[g_workObj.dividePos[_j]], arrowName, {
905
- x: 0, y: 0, w: C_ARW_WIDTH, h: C_ARW_WIDTH,
906
- });
907
- /**
908
- * 矢印毎の属性情報
909
- */
910
- g_attrObj[arrowName] = {
935
+ return {
911
936
  // 生存フレーム数
912
937
  cnt: _attrs.arrivalFrame + 1,
913
938
  // 生存フレーム数 (ストップ分除去、個別加速/Motionオプション用)
@@ -920,40 +945,105 @@ const mainInit = () => {
920
945
  dir: g_workObj.scrollDir[_j],
921
946
  // 個別加速方向 (1: 順方向加速, -1: 逆方向加速)
922
947
  boostDir: _attrs.boostDir,
923
- // 前フレーム時の位置 (判定で使用)
948
+ // 前フレーム時の位置 (判定、Motion適用中のアルファ値制御で使用)
924
949
  prevY: firstPosY,
925
950
  // 現フレーム時の位置
926
951
  y: firstPosY,
927
952
  // 移動ロックフラグ(矢印モーション設定後に再設定)
928
953
  movLockFlg: false,
929
954
  };
955
+ };
930
956
 
931
- // 矢印色の設定
932
- // - 枠/塗りつぶし色: g_attrObj[arrowName].Arrow / ArrowShadow
933
- g_typeLists.arrowColor.forEach(val => g_attrObj[arrowName][`Arrow${val}`] = g_workObj[`${_name}${val}Colors`][_j]);
934
-
935
- // g_attrObj定義後のカスタムイベント
936
- safeExecuteCustomHooks(`g_customJsObj.preMakeArrow`, g_customJsObj.preMakeArrow, _attrs, arrowName, _name, _arrowCnt);
937
-
938
- arrowSprite[g_workObj.dividePos[_j]].appendChild(arrowRoot);
939
- const arrowSubRoot = createEmptySprite(arrowRoot, `sub${arrowName}`, { x: 0, y: 0, w: C_ARW_WIDTH, h: C_ARW_WIDTH });
940
-
957
+ /**
958
+ * 矢印・フリーズアローのCSSモーション設定
959
+ * @param {string} _name 矢印・フリーズアローの種類 (arrow, dummyArrow, frz, dummyFrz)
960
+ * @param {number} _j 矢印位置
961
+ * @param {number} _arrivalFrame 到達フレーム数
962
+ * @param {HTMLDivElement} _subRoot 矢印・フリーズアローのサブルート
963
+ * @param {HTMLDivElement[]} [_arrowRoots] フリーズアローの矢印部分のルート (開始矢印, 後発矢印)
964
+ */
965
+ const setCssMotions = (_name, _j, _arrivalFrame, _subRoot, _arrowRoots = []) => {
966
+ const duration = `${_arrivalFrame / g_fps}s`;
941
967
  if (g_workObj[`${_name}CssMotions`][_j] !== ``) {
942
- arrowSubRoot.classList.add(g_workObj[`${_name}CssMotions`][_j]);
943
- arrowSubRoot.style.animationDuration = `${_attrs.arrivalFrame / g_fps}s`;
968
+ _subRoot.classList.add(g_workObj[`${_name}CssMotions`][_j]);
969
+ _subRoot.style.animationDuration = duration;
944
970
  }
945
- g_attrObj[arrowName].movLockFlg = g_workObj[`${_name}MovLock`][_j] || g_workObj.movLockEnabled;
971
+ if (_arrowRoots.length > 0 && g_workObj[`${_name}ArrowCssMotions`][_j] !== ``) {
972
+ _arrowRoots.forEach(obj => {
973
+ obj.classList.add(g_workObj[`${_name}ArrowCssMotions`][_j]);
974
+ obj.style.animationDuration = duration;
975
+ });
976
+ }
977
+ };
978
+
979
+ /**
980
+ * 矢印・フリーズアローの初期位置設定
981
+ * - 移動ロックフラグの確定、初期Y位置・X位置の設定を行う
982
+ * @param {string} _objName 矢印・フリーズアローのオブジェクト名
983
+ * @param {string} _name 矢印・フリーズアローの種類 (arrow, dummyArrow, frz, dummyFrz)
984
+ * @param {number} _j 矢印位置
985
+ * @param {number} _firstPosY 初期表示位置
986
+ * @param {number} _dividePos ステップゾーン位置 (0: デフォルト, 1: リバース)
987
+ */
988
+ const setInitArrowPos = (_objName, _name, _j, _firstPosY, _dividePos) => {
989
+ const stepY = C_STEP_Y + g_posObj.reverseStepY * _dividePos;
990
+ const movLockFlg = g_workObj[`${_name}MovLock`][_j] || g_workObj.movLockEnabled;
946
991
  const initManualFlg = g_workObj[`${_name}InitManual`][_j] || g_workObj.initManualEnabled;
947
- const setArrowYCondition = `${String(g_attrObj[arrowName].movLockFlg)}_${String(initManualFlg)}`;
948
- setArrowY.get(setArrowYCondition)(arrowName, firstPosY, stepY);
992
+ g_attrObj[_objName].movLockFlg = movLockFlg;
993
+ setArrowY.get(`${String(movLockFlg)}_${String(initManualFlg)}`)(_objName, _firstPosY, stepY);
949
994
  if (!initManualFlg) {
950
- addTransform(arrowName, `rootX`, `translateX(${wUnit(g_workObj.stepX[_j])})`);
995
+ addTransform(_objName, `rootX`, `translateX(${wUnit(g_workObj.stepX[_j])})`);
996
+ }
997
+ };
998
+
999
+ /**
1000
+ * 矢印・フリーズアロー(移動中)の位置更新
1001
+ * - 個別加速・Motion、移動ロック、Motion適用中のアルファ値制御を含む
1002
+ * - 速度が0(ストップ中)のときは何もしない
1003
+ * @param {string} _objName 矢印・フリーズアローのオブジェクト名
1004
+ * @param {object} _attr g_attrObj[_objName]
1005
+ */
1006
+ const updateArrowPos = (_objName, _attr) => {
1007
+ if (g_workObj.currentSpeed === 0) {
1008
+ return;
951
1009
  }
1010
+ _attr.prevY = _attr.y;
1011
+ _attr.y -= (g_workObj.currentSpeed * _attr.boostSpd +
1012
+ (g_workObj.motionOnFrames[_attr.boostCnt] || 0) * _attr.boostDir) * _attr.dir;
1013
+ movArrowY.get(_attr.movLockFlg)(_objName, _attr.y);
1014
+ g_motionAlphaFunc.get(g_stateObj.motion)(_objName, _attr);
1015
+ _attr.boostCnt--;
1016
+ };
1017
+
1018
+ /**
1019
+ * 矢印属性情報の生成
1020
+ * @param {object} _attrs 矢印個別の属性
1021
+ * @param {string} _name 矢印名
1022
+ * @param {number} _j 矢印位置
1023
+ * @returns {object}
1024
+ */
1025
+ const makeArrowAttr = (_attrs, _name, _j) => {
1026
+ const attr = makeBaseAttr(_attrs, _j);
1027
+
1028
+ // 矢印色の設定
1029
+ // - 枠/塗りつぶし色: attr.Arrow / ArrowShadow
1030
+ g_typeLists.arrowColor.forEach(val => attr[`Arrow${val}`] = g_workObj[`${_name}${val}Colors`][_j]);
1031
+ return attr;
1032
+ };
1033
+
1034
+ /**
1035
+ * 矢印オブジェクトの生成
1036
+ * - 後で生成されたものが手前に表示されるため、塗りつぶし ⇒ 枠の順で作成
1037
+ * @param {HTMLDivElement} _arrowSubRoot 矢印のサブルート
1038
+ * @param {string} _name 矢印名
1039
+ * @param {number} _j 矢印位置
1040
+ * @param {number} _arrowCnt 現在の判定矢印順
1041
+ * @param {string} _color 矢印色
1042
+ * @param {string} _shadowColor 矢印塗りつぶし部分の色
1043
+ */
1044
+ const makeArrowSprites = (_arrowSubRoot, _name, _j, _arrowCnt, _color, _shadowColor) => {
1045
+ const colorPos = g_keyObj[`color${keyCtrlPtn}`][_j];
952
1046
 
953
- /**
954
- * 矢印オブジェクトの生成
955
- * - 後で生成されたものが手前に表示されるため、塗りつぶし ⇒ 枠の順で作成
956
- */
957
1047
  // 矢印の内側を塗りつぶすか否か
958
1048
  if (g_headerObj.setShadowColor[colorPos] !== ``) {
959
1049
  // 矢印 (塗りつぶし)
@@ -964,13 +1054,49 @@ const mainInit = () => {
964
1054
  if (_shadowColor === `Default`) {
965
1055
  arrShadow.style.opacity = 0.5;
966
1056
  }
967
- arrowSubRoot.appendChild(arrShadow);
1057
+ _arrowSubRoot.appendChild(arrShadow);
968
1058
  }
969
1059
 
970
1060
  // 矢印 (枠)
971
- arrowSubRoot.appendChild(createColorObject2(`${_name}Top${_j}_${_arrowCnt}`, {
1061
+ _arrowSubRoot.appendChild(createColorObject2(`${_name}Top${_j}_${_arrowCnt}`, {
972
1062
  background: _color, rotate: g_workObj.arrowRtn[_j],
973
1063
  }));
1064
+ };
1065
+
1066
+ /**
1067
+ * 矢印生成
1068
+ * @param {object} _attrs 矢印個別の属性
1069
+ * (pos: 矢印種類, arrivalFrame: 到達フレーム数, initY: 初期表示位置,
1070
+ * initBoostY: Motion有効時の初期表示位置加算, motionFrame: アニメーション有効フレーム数)
1071
+ * @param {number} _arrowCnt 現在の判定矢印順
1072
+ * @param {string} _name 矢印名
1073
+ * @param {string} _color 矢印色
1074
+ * @param {string} _shadowColor 矢印塗りつぶし部分の色
1075
+ */
1076
+ const makeArrow = (_attrs, _arrowCnt, _name, _color, _shadowColor) => {
1077
+ const _j = _attrs.pos;
1078
+ const arrowName = `${_name}${_j}_${_arrowCnt}`;
1079
+
1080
+ const arrowRoot = createEmptySprite(arrowSprite[g_workObj.dividePos[_j]], arrowName, {
1081
+ x: 0, y: 0, w: C_ARW_WIDTH, h: C_ARW_WIDTH,
1082
+ });
1083
+
1084
+ // 矢印毎の属性情報
1085
+ g_attrObj[arrowName] = makeArrowAttr(_attrs, _name, _j);
1086
+
1087
+ // 初期位置の設定用に、カスタムイベント実行前の値を保持
1088
+ const { dividePos, y: firstPosY } = g_attrObj[arrowName];
1089
+
1090
+ // g_attrObj定義後のカスタムイベント
1091
+ safeExecuteCustomHooks(`g_customJsObj.preMakeArrow`, g_customJsObj.preMakeArrow, _attrs, arrowName, _name, _arrowCnt);
1092
+
1093
+ arrowSprite[g_workObj.dividePos[_j]].appendChild(arrowRoot);
1094
+ const arrowSubRoot = createEmptySprite(arrowRoot, `sub${arrowName}`, { x: 0, y: 0, w: C_ARW_WIDTH, h: C_ARW_WIDTH });
1095
+
1096
+ setCssMotions(_name, _j, _attrs.arrivalFrame, arrowSubRoot);
1097
+ setInitArrowPos(arrowName, _name, _j, firstPosY, dividePos);
1098
+ makeArrowSprites(arrowSubRoot, _name, _j, _arrowCnt, _color, _shadowColor);
1099
+
974
1100
  safeExecuteCustomHooks(`g_customJsObj.makeArrow`, g_customJsObj.makeArrow, _attrs, arrowName, _name, _arrowCnt);
975
1101
  };
976
1102
 
@@ -983,22 +1109,109 @@ const mainInit = () => {
983
1109
  const movArrow = (_j, _k, _name) => {
984
1110
  const arrowName = `${_name}${_j}_${_k}`;
985
1111
  const currentArrow = g_attrObj[arrowName];
1112
+ const funcs = objFuncs[_name];
986
1113
 
987
1114
  // 全体色変化 (移動時)
988
- changeColorFunc[_name](_j, _k);
1115
+ changeColorOnFrame(_j, _k, _name);
989
1116
 
990
1117
  // 移動
991
- if (g_workObj.currentSpeed !== 0) {
992
- const boostCnt = currentArrow.boostCnt;
993
- currentArrow.prevY = currentArrow.y;
994
- currentArrow.y -= (g_workObj.currentSpeed * currentArrow.boostSpd +
995
- (g_workObj.motionOnFrames[boostCnt] || 0) * currentArrow.boostDir) * currentArrow.dir;
996
- movArrowY.get(currentArrow.movLockFlg)(arrowName, currentArrow.y);
997
- g_motionAlphaFunc.get(g_stateObj.motion)(arrowName, currentArrow);
998
- currentArrow.boostCnt--;
999
- }
1000
- judgeMotionFunc[`${_name}${g_stateObj.autoAll}`](_j, arrowName, --currentArrow.cnt);
1001
- judgeNextFunc[`${_name}${g_stateObj.autoAll}`](_j, _k, currentArrow.cnt);
1118
+ updateArrowPos(arrowName, currentArrow);
1119
+
1120
+ funcs.judgeMotion(_j, arrowName, --currentArrow.cnt);
1121
+ funcs.judgeNext(_j, _k, currentArrow.cnt);
1122
+ };
1123
+
1124
+ /**
1125
+ * フリーズアロー属性情報の生成
1126
+ * @param {object} _attrs フリーズアロー個別の属性
1127
+ * @param {string} _name フリーズアロー名
1128
+ * @param {number} _j 矢印位置
1129
+ * @param {number} _firstBarLength 初期のフリーズアロー(帯)の長さ
1130
+ * @returns {object}
1131
+ */
1132
+ const makeFrzAttr = (_attrs, _name, _j, _firstBarLength) => {
1133
+ const attr = makeBaseAttr(_attrs, _j);
1134
+ Object.assign(attr, {
1135
+ // 判定終了フラグ (false: 未判定, true: 判定済)
1136
+ judgEndFlg: false,
1137
+ // 移動中フラグ (false: 押しっぱなしの状態, true: 移動中)
1138
+ isMoving: true,
1139
+ // フリーズアローの長さ
1140
+ frzBarLength: _firstBarLength,
1141
+ // キーを離していたフレーム数 (基準値超えでNG判定)
1142
+ keyUpFrame: 0,
1143
+ // フリーズアロー(帯)の相対位置
1144
+ barY: C_ARW_WIDTH / 2 - _firstBarLength * attr.dividePos,
1145
+ // フリーズアロー(対矢印)の相対位置
1146
+ btmY: _firstBarLength * attr.dir,
1147
+ });
1148
+
1149
+ // フリーズアロー色の設定
1150
+ // - 通常時 (矢印枠/矢印塗りつぶし/帯): attr.Normal / NormalShadow / NormalBar
1151
+ // - ヒット時 (矢印枠/矢印塗りつぶし/帯): attr.Hit / HitShadow / HitBar
1152
+ // - ヒット時(矢印枠/矢印塗りつぶし/帯別の生成時全体色): attr.HitAll / HitShadowAll / HitBarAll
1153
+ g_typeLists.frzColor.forEach(val => {
1154
+ attr[val] = g_workObj[`${_name}${val}Colors`][_j];
1155
+ if (val.startsWith(`Hit`)) {
1156
+ attr[`${val}All`] = g_workObj[`${_name}${val}ColorsAll`][_j];
1157
+ }
1158
+ });
1159
+ return attr;
1160
+ };
1161
+
1162
+ /**
1163
+ * フリーズアローオブジェクトの生成
1164
+ * @param {HTMLDivElement} _frzSubRoot フリーズアローのサブルート
1165
+ * @param {object} _attr フリーズアロー属性情報
1166
+ * @param {string} _frzNo 位置_順 (例: 0_1)
1167
+ * @param {string} _name フリーズアロー名
1168
+ * @param {number} _j 矢印位置
1169
+ * @param {number} _firstBarLength 初期のフリーズアロー(帯)の長さ
1170
+ * @param {object} _colors 色 (normal: 矢印, bar: 帯, shadow: 塗りつぶし)
1171
+ * @returns {{frzBar: HTMLDivElement, frzTopRoot: HTMLDivElement, frzBtmRoot: HTMLDivElement}}
1172
+ */
1173
+ const makeFrzSprites = (_frzSubRoot, _attr, _frzNo, _name, _j, _firstBarLength, _colors) => {
1174
+ const shadowColor = _colors.shadow === `Default` ? _colors.normal : _colors.shadow;
1175
+ const rotate = g_workObj.frzArrowInitRtn[_j];
1176
+
1177
+ // フリーズアロー帯(frzBar)
1178
+ const frzBar = createColorObject2(`${_name}Bar${_frzNo}`, {
1179
+ x: 5, y: _attr.barY, w: C_ARW_WIDTH - 10, h: _firstBarLength, background: _colors.bar, styleName: `frzBar`,
1180
+ opacity: 0.75,
1181
+ });
1182
+ multiAppend(_frzSubRoot, frzBar);
1183
+
1184
+ const frzTopRoot = createEmptySprite(_frzSubRoot, `${_name}TopRoot${_frzNo}`,
1185
+ { x: 0, y: 0, w: C_ARW_WIDTH, h: C_ARW_WIDTH });
1186
+ const frzBtmRoot = createEmptySprite(_frzSubRoot, `${_name}BtmRoot${_frzNo}`,
1187
+ { x: 0, y: _attr.btmY, w: C_ARW_WIDTH, h: C_ARW_WIDTH });
1188
+
1189
+ multiAppend(frzTopRoot,
1190
+
1191
+ // 開始矢印の塗り部分。ヒット時は前面に表示
1192
+ createColorObject2(`${_name}TopShadow${_frzNo}`, {
1193
+ background: shadowColor, rotate: rotate, styleName: `Shadow`,
1194
+ }, g_cssObj.main_objShadow),
1195
+
1196
+ // 開始矢印。ヒット時は非表示
1197
+ createColorObject2(`${_name}Top${_frzNo}`, {
1198
+ background: _colors.normal, rotate: rotate,
1199
+ }),
1200
+ );
1201
+
1202
+ multiAppend(frzBtmRoot,
1203
+
1204
+ // 後発矢印の塗り部分
1205
+ createColorObject2(`${_name}BtmShadow${_frzNo}`, {
1206
+ background: shadowColor, rotate: rotate, styleName: `Shadow`,
1207
+ }, g_cssObj.main_objShadow),
1208
+
1209
+ // 後発矢印
1210
+ createColorObject2(`${_name}Btm${_frzNo}`, {
1211
+ background: _colors.normal, rotate: rotate,
1212
+ }),
1213
+ );
1214
+ return { frzBar, frzTopRoot, frzBtmRoot };
1002
1215
  };
1003
1216
 
1004
1217
  /**
@@ -1014,12 +1227,8 @@ const mainInit = () => {
1014
1227
  */
1015
1228
  const makeFrzArrow = (_attrs, _arrowCnt, _name, _normalColor, _barColor, _shadowColor) => {
1016
1229
  const _j = _attrs.pos;
1017
- const dividePos = g_workObj.dividePos[_j] % 2;
1018
1230
  const frzNo = `${_j}_${_arrowCnt}`;
1019
1231
  const frzName = `${_name}${frzNo}`;
1020
- const stepY = C_STEP_Y + g_posObj.reverseStepY * dividePos;
1021
- const firstPosY = stepY + (_attrs.initY * _attrs.boostSpd +
1022
- _attrs.initBoostY * _attrs.boostDir) * g_workObj.scrollDir[_j];
1023
1232
  const firstBarLength = g_workObj[`mk${toCapitalize(_name)}Length`][_j][(_arrowCnt - 1) * 2] * _attrs.boostSpd;
1024
1233
 
1025
1234
  const frzRoot = createEmptySprite(arrowSprite[g_workObj.dividePos[_j]], frzName, {
@@ -1031,120 +1240,106 @@ const mainInit = () => {
1031
1240
  _barColor = `#00000000`;
1032
1241
  }
1033
1242
 
1034
- /**
1035
- * フリーズアロー毎の属性情報
1036
- */
1037
- g_attrObj[frzName] = {
1038
- // 生存フレーム数
1039
- cnt: _attrs.arrivalFrame + 1,
1040
- // 生存フレーム数 (ストップ分除去、個別加速/Motionオプション用)
1041
- boostCnt: _attrs.motionFrame,
1042
- // 判定終了フラグ (false: 未判定, true: 判定済)
1043
- judgEndFlg: false,
1044
- // 移動中フラグ (false: 押しっぱなしの状態, true: 移動中)
1045
- isMoving: true,
1046
- // フリーズアローの長さ
1047
- frzBarLength: firstBarLength,
1048
- // キーを離していたフレーム数 (基準値超えでNG判定)
1049
- keyUpFrame: 0,
1050
- // 個別加速量
1051
- boostSpd: _attrs.boostSpd,
1052
- // ステップゾーン位置 (0: デフォルト, 1: リバース)
1053
- dividePos: dividePos,
1054
- // スクロール方向 (1: デフォルト, -1: リバース)
1055
- dir: g_workObj.scrollDir[_j],
1056
- // 個別加速方向 (1: 順方向加速, -1: 逆方向加速)
1057
- boostDir: _attrs.boostDir,
1058
- // 現フレーム時のフリーズアロー本体の位置
1059
- y: firstPosY,
1060
- // フリーズアロー(帯)の相対位置
1061
- barY: C_ARW_WIDTH / 2 - firstBarLength * dividePos,
1062
- // フリーズアロー(対矢印)の相対位置
1063
- btmY: firstBarLength * g_workObj.scrollDir[_j],
1064
- // 移動ロックフラグ(矢印モーション設定後に再設定)
1065
- movLockFlg: false,
1066
- };
1243
+ // フリーズアロー毎の属性情報
1244
+ g_attrObj[frzName] = makeFrzAttr(_attrs, _name, _j, firstBarLength);
1245
+ const frzAttr = g_attrObj[frzName];
1067
1246
 
1068
- // フリーズアロー色の設定
1069
- // - 通常時 (矢印枠/矢印塗りつぶし/帯): g_attrObj[frzName].Normal / NormalShadow / NormalBar
1070
- // - ヒット時 (矢印枠/矢印塗りつぶし/帯): g_attrObj[frzName].Hit / HitShadow / HitBar
1071
- // - ヒット時(矢印枠/矢印塗りつぶし/帯別の生成時全体色): g_attrObj[frzName].HitAll / HitShadowAll / HitBarAll
1072
- g_typeLists.frzColor.forEach(val => {
1073
- g_attrObj[frzName][val] = g_workObj[`${_name}${val}Colors`][_j];
1074
- if (val.startsWith(`Hit`)) {
1075
- g_attrObj[frzName][`${val}All`] = g_workObj[`${_name}${val}ColorsAll`][_j];
1076
- }
1077
- });
1247
+ // 初期位置の設定用に、カスタムイベント実行前の値を保持
1248
+ const { dividePos, y: firstPosY } = frzAttr;
1078
1249
 
1079
1250
  // g_attrObj定義後のカスタムイベント
1080
1251
  safeExecuteCustomHooks(`g_customJsObj.preMakeFrzArrow`, g_customJsObj.preMakeFrzArrow, _attrs, frzName, _name, _arrowCnt);
1081
1252
 
1082
1253
  arrowSprite[g_workObj.dividePos[_j]].appendChild(frzRoot);
1083
- let shadowColor = _shadowColor === `Default` ? _normalColor : _shadowColor;
1084
1254
  const frzSubRoot = createEmptySprite(frzRoot, `sub${frzName}`, { x: 0, y: 0, w: C_ARW_WIDTH, h: C_ARW_WIDTH + firstBarLength });
1255
+ const { frzBar, frzTopRoot, frzBtmRoot } = makeFrzSprites(frzSubRoot, frzAttr, frzNo, _name, _j, firstBarLength,
1256
+ { normal: _normalColor, bar: _barColor, shadow: _shadowColor });
1085
1257
 
1086
- /**
1087
- * フリーズアローオブジェクトの生成
1088
- * - 後で生成されたものが手前に表示されるため、以下の順で作成
1089
- */
1090
- multiAppend(frzSubRoot,
1258
+ // ヒット中の描画更新(movFrzHolding)用に、帯・後発矢印の style を保持
1259
+ frzAttr.barStyle = frzBar.style;
1260
+ frzAttr.btmRootStyle = frzBtmRoot.style;
1091
1261
 
1092
- // フリーズアロー帯(frzBar)
1093
- createColorObject2(`${_name}Bar${frzNo}`, {
1094
- x: 5, y: g_attrObj[frzName].barY, w: C_ARW_WIDTH - 10, h: firstBarLength, background: _barColor, styleName: `frzBar`,
1095
- opacity: 0.75,
1096
- }),
1097
- );
1098
- const frzTopRoot = createEmptySprite(frzSubRoot, `${_name}TopRoot${frzNo}`,
1099
- { x: 0, y: 0, w: C_ARW_WIDTH, h: C_ARW_WIDTH });
1100
- const frzBtmRoot = createEmptySprite(frzSubRoot, `${_name}BtmRoot${frzNo}`,
1101
- { x: 0, y: g_attrObj[frzName].btmY, w: C_ARW_WIDTH, h: C_ARW_WIDTH });
1262
+ setCssMotions(_name, _j, _attrs.arrivalFrame, frzSubRoot, [frzTopRoot, frzBtmRoot]);
1263
+ setInitArrowPos(frzName, _name, _j, firstPosY, dividePos);
1102
1264
 
1103
- multiAppend(frzTopRoot,
1265
+ safeExecuteCustomHooks(`g_customJsObj.makeFrzArrow`, g_customJsObj.makeFrzArrow, _attrs, frzName, _name, _arrowCnt);
1266
+ };
1104
1267
 
1105
- // 開始矢印の塗り部分。ヒット時は前面に表示
1106
- createColorObject2(`${_name}TopShadow${frzNo}`, {
1107
- background: shadowColor, rotate: g_workObj.frzArrowInitRtn[_j], styleName: `Shadow`,
1108
- }, g_cssObj.main_objShadow),
1268
+ /**
1269
+ * フリーズアロー処理: 移動中 (未ヒット)
1270
+ * @param {number} _j
1271
+ * @param {number} _k
1272
+ * @param {string} _name
1273
+ * @param {string} _frzName
1274
+ * @param {object} _frz g_attrObj[_frzName]
1275
+ */
1276
+ const movFrzMoving = (_j, _k, _name, _frzName, _frz) => {
1109
1277
 
1110
- // 開始矢印。ヒット時は非表示
1111
- createColorObject2(`${_name}Top${frzNo}`, {
1112
- background: _normalColor, rotate: g_workObj.frzArrowInitRtn[_j],
1113
- }),
1114
- );
1278
+ // 全体色変化 (通常時)
1279
+ changeColorOnFrame(_j, _k, _name, `Normal`);
1115
1280
 
1116
- multiAppend(frzBtmRoot,
1281
+ // 移動
1282
+ updateArrowPos(_frzName, _frz);
1283
+ _frz.cnt--;
1117
1284
 
1118
- // 後発矢印の塗り部分
1119
- createColorObject2(`${_name}BtmShadow${frzNo}`, {
1120
- background: shadowColor, rotate: g_workObj.frzArrowInitRtn[_j], styleName: `Shadow`,
1121
- }, g_cssObj.main_objShadow),
1285
+ // 次フリーズアローへ判定を移すかチェック
1286
+ objFuncs[_name].judgeNext(_j, _k, _frz.cnt);
1287
+ };
1122
1288
 
1123
- // 後発矢印
1124
- createColorObject2(`${_name}Btm${frzNo}`, {
1125
- background: _normalColor, rotate: g_workObj.frzArrowInitRtn[_j],
1126
- }),
1289
+ /**
1290
+ * フリーズアロー処理: ヒット中 (押しっぱなし)
1291
+ * @param {number} _j
1292
+ * @param {number} _k
1293
+ * @param {string} _name
1294
+ * @param {string} _frzName
1295
+ * @param {object} _frz g_attrObj[_frzName]
1296
+ * @param {number} _movY 1フレームあたりの移動量
1297
+ */
1298
+ const movFrzHolding = (_j, _k, _name, _frzName, _frz, _movY) => {
1299
+ const funcs = objFuncs[_name];
1127
1300
 
1128
- );
1129
- if (g_workObj[`${_name}CssMotions`][_j] !== ``) {
1130
- frzSubRoot.classList.add(g_workObj[`${_name}CssMotions`][_j]);
1131
- frzSubRoot.style.animationDuration = `${_attrs.arrivalFrame / g_fps}s`;
1301
+ // 全体色変化 (ヒット時)
1302
+ changeColorOnFrame(_j, _k, _name, `Hit`);
1303
+
1304
+ if (_frz.frzBarLength <= 0) {
1305
+ funcs.judgeOK(_j, _k, _frzName, _frz.cnt);
1306
+ return;
1132
1307
  }
1133
- if (g_workObj[`${_name}ArrowCssMotions`][_j] !== ``) {
1134
- [frzTopRoot, frzBtmRoot].forEach(obj => {
1135
- obj.classList.add(g_workObj[`${_name}ArrowCssMotions`][_j]);
1136
- obj.style.animationDuration = `${_attrs.arrivalFrame / g_fps}s`;
1137
- });
1308
+
1309
+ // 帯の短縮 (ストップ中は変化しないため描画更新を省略)
1310
+ if (_movY !== 0) {
1311
+ _frz.frzBarLength -= _movY * _frz.dir;
1312
+ _frz.barY -= _movY * _frz.dividePos;
1313
+ _frz.btmY -= _movY;
1314
+
1315
+ _frz.barStyle.height = wUnit(_frz.frzBarLength);
1316
+ _frz.barStyle.top = wUnit(_frz.barY);
1317
+ _frz.btmRootStyle.top = wUnit(_frz.btmY);
1138
1318
  }
1139
- g_attrObj[frzName].movLockFlg = g_workObj[`${_name}MovLock`][_j] || g_workObj.movLockEnabled;
1140
- const initManualFlg = g_workObj[`${_name}InitManual`][_j] || g_workObj.initManualEnabled;
1141
- const setArrowYCondition = `${String(g_attrObj[frzName].movLockFlg)}_${String(initManualFlg)}`;
1142
- setArrowY.get(setArrowYCondition)(frzName, firstPosY, stepY);
1143
- if (!initManualFlg) {
1144
- addTransform(frzName, `rootX`, `translateX(${wUnit(g_workObj.stepX[_j])})`);
1319
+
1320
+ // キーを離したときの処理
1321
+ if (!funcs.checkKeyUp(_j)) {
1322
+ _frz.keyUpFrame++;
1323
+ funcs.judgeKeyUp(_j, _k, _frzName, _frz.cnt);
1145
1324
  }
1325
+ };
1146
1326
 
1147
- safeExecuteCustomHooks(`g_customJsObj.makeFrzArrow`, g_customJsObj.makeFrzArrow, _attrs, frzName, _name, _arrowCnt);
1327
+ /**
1328
+ * フリーズアロー処理: 判定終了後 (枠外へ流れるまで)
1329
+ * @param {number} _j
1330
+ * @param {string} _name
1331
+ * @param {string} _frzName
1332
+ * @param {object} _frz g_attrObj[_frzName]
1333
+ * @param {number} _movY 1フレームあたりの移動量
1334
+ */
1335
+ const movFrzEnded = (_j, _name, _frzName, _frz, _movY) => {
1336
+ _frz.frzBarLength -= _movY * _frz.dir;
1337
+ if (_frz.frzBarLength > 0) {
1338
+ _frz.y -= _movY;
1339
+ movArrowY.get(_frz.movLockFlg)(_frzName, _frz.y);
1340
+ } else {
1341
+ objFuncs[_name].judgeDelete(_j, _frzName);
1342
+ }
1148
1343
  };
1149
1344
 
1150
1345
  /**
@@ -1154,65 +1349,99 @@ const mainInit = () => {
1154
1349
  * @param {string} _name
1155
1350
  */
1156
1351
  const movFrzArrow = (_j, _k, _name) => {
1157
- const frzNo = `${_j}_${_k}`;
1158
- const frzName = `${_name}${frzNo}`;
1352
+ const frzName = `${_name}${_j}_${_k}`;
1159
1353
  const currentFrz = g_attrObj[frzName];
1160
1354
  const movY = g_workObj.currentSpeed * currentFrz.boostSpd * currentFrz.dir;
1161
1355
 
1162
- if (!currentFrz.judgEndFlg) {
1163
- if (currentFrz.isMoving) {
1356
+ if (currentFrz.judgEndFlg) {
1357
+ movFrzEnded(_j, _name, frzName, currentFrz, movY);
1358
+ return;
1359
+ }
1164
1360
 
1165
- // 全体色変化 (通常時)
1166
- changeColorFunc[_name](_j, _k, `Normal`);
1361
+ if (currentFrz.isMoving) {
1362
+ movFrzMoving(_j, _k, _name, frzName, currentFrz);
1363
+ } else {
1364
+ movFrzHolding(_j, _k, _name, frzName, currentFrz, movY);
1365
+ }
1167
1366
 
1168
- // 移動
1169
- if (g_workObj.currentSpeed !== 0) {
1170
- currentFrz.prevY = currentFrz.y;
1171
- currentFrz.y -= movY + (g_workObj.motionOnFrames[currentFrz.boostCnt] || 0) * currentFrz.dir * currentFrz.boostDir;
1172
- movArrowY.get(currentFrz.movLockFlg)(frzName, currentFrz.y);
1173
- g_motionAlphaFunc.get(g_stateObj.motion)(frzName, currentFrz);
1174
- currentFrz.boostCnt--;
1175
- }
1176
- currentFrz.cnt--;
1367
+ // フリーズアローが枠外に出たときの処理
1368
+ objFuncs[_name].judgeNG(_j, _k, frzName, currentFrz.cnt);
1369
+ };
1177
1370
 
1178
- // 次フリーズアローへ判定を移すかチェック
1179
- judgeNextFunc[`${_name}${g_stateObj.autoAll}`](_j, _k, currentFrz.cnt);
1371
+ /**
1372
+ * 歌詞表示の更新
1373
+ * - 歌詞データは [深度, 歌詞 or 制御コマンド, (フェード時間フレーム)] の形式
1374
+ * - 制御コマンド: [fadein], [fadeout], [left], [center], [right], [fontSize=n]
1375
+ * 制御コマンド以外は歌詞として表示する
1376
+ * @param {Array} _wordData 歌詞データ
1377
+ * @param {number} _currentFrame 現在のフレーム数
1378
+ */
1379
+ const updateWord = (_wordData, _currentFrame) => {
1380
+ const [wordDir, wordDat, wordFadeFrame] = _wordData;
1381
+ const wordDepth = Number(wordDir);
1382
+ const targetId = `lblword${wordDepth}`;
1383
+ const styWord = $id(targetId);
1384
+
1385
+ const wordFadeCmds = new Map([
1386
+ [`[fadein]`, [`In`, `Out`]],
1387
+ [`[fadeout]`, [`Out`, `In`]],
1388
+ ]);
1389
+ const alignCmds = [`[left]`, `[center]`, `[right]`];
1390
+
1391
+ const fadeTypes = wordFadeCmds.get(wordDat);
1392
+ if (fadeTypes !== undefined) {
1393
+
1394
+ // フェードイン・アウト開始(フェードイン中はフェードアウト処理を無効にする。その逆も同様)
1395
+ const [onType, offType] = fadeTypes;
1396
+ g_wordObj[`fade${onType}Flg${wordDepth}`] = true;
1397
+ g_wordObj[`fade${offType}Flg${wordDepth}`] = false;
1398
+
1399
+ const animationName = `fade${onType}0`;
1400
+ const isRepeatedFade =
1401
+ styWord.animationName === animationName &&
1402
+ g_workObj.lastFadeFrame[wordDepth] !== _currentFrame;
1403
+
1404
+ if (isRepeatedFade) {
1405
+ styWord.animationName = `none`;
1406
+
1407
+ // 幅の読み取りにより、未反映のスタイル・レイアウトを更新する
1408
+ // 幅の値そのものは使わない
1409
+ void document.getElementById(targetId).offsetWidth;
1410
+ }
1411
+ styWord.animationName = animationName;
1180
1412
 
1181
- } else {
1413
+ const fadeFrame = setIntVal(wordFadeFrame, C_WOD_FRAME);
1414
+ g_workObj.lastFadeFrame[wordDepth] = _currentFrame;
1415
+ g_workObj.wordFadeFrame[wordDepth] = fadeFrame;
1182
1416
 
1183
- // 全体色変化 (ヒット時)
1184
- changeColorFunc[_name](_j, _k, `Hit`);
1417
+ styWord.animationDuration = `${fadeFrame / g_fps}s`;
1418
+ styWord.animationTimingFunction = `linear`;
1419
+ styWord.animationFillMode = `forwards`;
1185
1420
 
1186
- // フリーズアローがヒット中の処理
1187
- if (currentFrz.frzBarLength > 0) {
1421
+ } else if (alignCmds.includes(wordDat)) {
1188
1422
 
1189
- currentFrz.frzBarLength -= movY * currentFrz.dir;
1190
- currentFrz.barY -= movY * currentFrz.dividePos;
1191
- currentFrz.btmY -= movY;
1423
+ // 歌詞位置変更
1424
+ styWord.textAlign = wordDat.slice(1, -1);
1192
1425
 
1193
- $id(`${_name}Bar${frzNo}`).height = wUnit(currentFrz.frzBarLength);
1194
- $id(`${_name}Bar${frzNo}`).top = wUnit(currentFrz.barY);
1195
- $id(`${_name}BtmRoot${frzNo}`).top = wUnit(currentFrz.btmY);
1426
+ } else if (/\[fontSize=\d+\]/.test(wordDat)) {
1196
1427
 
1197
- if (!checkKeyUpFunc[`${_name}${g_stateObj.autoAll}`](_j)) {
1198
- currentFrz.keyUpFrame++;
1199
- judgeMotionFunc[`${_name}KeyUp`](_j, _k, frzName, currentFrz.cnt);
1200
- }
1201
- } else {
1202
- judgeMotionFunc[`${_name}OK`](_j, _k, frzName, currentFrz.cnt);
1203
- }
1204
- }
1205
- // フリーズアローが枠外に出たときの処理
1206
- judgeMotionFunc[`${_name}NG`](_j, _k, frzName, currentFrz.cnt);
1428
+ // フォントサイズ変更
1429
+ const fontSize = setIntVal(wordDat.match(/\d+/)[0], g_limitObj.mainSiz);
1430
+ styWord.fontSize = wUnit(fontSize);
1207
1431
 
1208
1432
  } else {
1209
- currentFrz.frzBarLength -= movY * currentFrz.dir;
1210
- if (currentFrz.frzBarLength > 0) {
1211
- currentFrz.y -= movY;
1212
- movArrowY.get(currentFrz.movLockFlg)(frzName, currentFrz.y);
1213
- } else {
1214
- judgeObjDelete[_name](_j, frzName);
1433
+
1434
+ // フェードイン・アウトが完了していれば、アニメーションを解除してから歌詞を表示
1435
+ const fadeFinished = _currentFrame - g_workObj.lastFadeFrame[wordDepth] >= g_workObj.wordFadeFrame[wordDepth];
1436
+ if (fadeFinished) {
1437
+ [`Out`, `In`].forEach(type => {
1438
+ if (g_wordObj[`fade${type}Flg${wordDepth}`]) {
1439
+ styWord.animationName = `none`;
1440
+ g_wordObj[`fade${type}Flg${wordDepth}`] = false;
1441
+ }
1442
+ });
1215
1443
  }
1444
+ document.getElementById(targetId).innerHTML = wordDat;
1216
1445
  }
1217
1446
  };
1218
1447
 
@@ -1365,52 +1594,7 @@ const mainInit = () => {
1365
1594
  }
1366
1595
 
1367
1596
  // 歌詞表示
1368
- g_scoreObj.wordData[currentFrame]?.forEach(tmpObj => {
1369
- g_wordObj.wordDir = tmpObj[0];
1370
- g_wordObj.wordDat = tmpObj[1];
1371
- g_wordSprite = document.getElementById(`lblword${g_wordObj.wordDir}`);
1372
-
1373
- const wordDepth = Number(g_wordObj.wordDir);
1374
- if (g_wordObj.wordDat.substring(0, 5) === `[fade`) {
1375
-
1376
- // フェードイン・アウト開始
1377
- const fkey = fadeFlgs[Object.keys(fadeFlgs).find(flg => g_wordObj.wordDat === `[${flg}]`)];
1378
- g_wordObj[`fade${fkey[0]}Flg${wordDepth}`] = true;
1379
- g_wordObj[`fade${fkey[1]}Flg${wordDepth}`] = false;
1380
- g_wordSprite.style.animationName =
1381
- `fade${fkey[0]}${(++g_workObj[`fade${fkey[0]}No`][wordDepth] % 2)}`;
1382
-
1383
- g_workObj.lastFadeFrame[wordDepth] = currentFrame;
1384
- g_workObj.wordFadeFrame[wordDepth] = (tmpObj.length > 2 ?
1385
- setIntVal(tmpObj[2], C_WOD_FRAME) : C_WOD_FRAME);
1386
-
1387
- g_wordSprite.style.animationDuration = `${g_workObj.wordFadeFrame[wordDepth] / g_fps}s`;
1388
- g_wordSprite.style.animationTimingFunction = `linear`;
1389
- g_wordSprite.style.animationFillMode = `forwards`;
1390
-
1391
- } else if ([`[center]`, `[left]`, `[right]`].includes(g_wordObj.wordDat)) {
1392
-
1393
- // 歌詞位置変更
1394
- g_wordSprite.style.textAlign = g_wordObj.wordDat.slice(1, -1);
1395
-
1396
- } else if (/\[fontSize=\d+\]/.test(g_wordObj.wordDat)) {
1397
-
1398
- // フォントサイズ変更
1399
- const fontSize = setIntVal(g_wordObj.wordDat.match(/\d+/)[0], g_limitObj.mainSiz);
1400
- g_wordSprite.style.fontSize = wUnit(fontSize);
1401
-
1402
- } else {
1403
-
1404
- // フェードイン・アウト処理後、表示する歌詞を表示
1405
- const fadingFlg = currentFrame - g_workObj.lastFadeFrame[wordDepth] >= g_workObj.wordFadeFrame[wordDepth];
1406
- [`Out`, `In`].filter(pattern => g_wordObj[`fade${pattern}Flg${g_wordObj.wordDir}`] && fadingFlg).forEach(pattern => {
1407
- g_wordSprite.style.animationName = `none`;
1408
- g_wordObj[`fade${pattern}Flg${g_wordObj.wordDir}`] = false;
1409
- });
1410
- g_workObj[`word${g_wordObj.wordDir}Data`] = g_wordObj.wordDat;
1411
- g_wordSprite.innerHTML = g_wordObj.wordDat;
1412
- }
1413
- });
1597
+ g_scoreObj.wordData[currentFrame]?.forEach(wordData => updateWord(wordData, currentFrame));
1414
1598
 
1415
1599
  // 判定キャラクタ消去
1416
1600
  jdgGroups.forEach(jdg => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "danoniplus",
3
- "version": "51.1.1",
3
+ "version": "51.2.0",
4
4
  "description": "Dancing☆Onigiri (CW Edition) - Web-based Rhythm Game",
5
5
  "main": "./js/danoni_main.js",
6
6
  "jsdelivr": "./js/danoni_main.js",