Skip to content

Commit

Permalink
0.6.0.27 - support stretching bar roll as in TaikoJiro (#757)
Browse files Browse the repository at this point in the history
- [Feat] Make bar drumrolls stretchable
- [Feat] Detect and hide screen-obscuring bar drumrolls when any tips are out of screen
- [Fix] fix bar drumroll end stuck at judgement mark if occurred at 0ms since #START
- [Fix] fix fuze rolls stretched back when exploded
- [Fix] fix balloon-type notes not stayed on judgement mark vertically during their duration
- [Fix] fix wrong drawn position of rotated bar-type roll tails
  • Loading branch information
IepIweidieng authored Dec 9, 2024
1 parent b35a4d3 commit 1aa4f58
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 112 deletions.
4 changes: 4 additions & 0 deletions OpenTaiko/src/Songs/CTja.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5016,6 +5016,10 @@ private void InsertNoteAtDefCursor(int noteType, int iDiv, int divsPerMeasure, E
chipHead.nNoteEndPosition = chip.nNoteEndPosition = chip.n発声位置;
chipHead.nNoteEndTimems = chip.nNoteEndTimems = chip.n発声時刻ms;
chipHead.fBMSCROLLTime_end = chip.fBMSCROLLTime_end = chip.fBMSCROLLTime;
chipHead.dbBPM_end = chip.dbBPM_end = chip.dbBPM;
chipHead.dbSCROLL_end = chip.dbSCROLL_end = chip.dbSCROLL;
chipHead.dbSCROLL_Y_end = chip.dbSCROLL_Y_end = chip.dbSCROLL_Y;
chipHead.eScrollMode_end = chip.eScrollMode_end = chip.eScrollMode;

chip.nノーツ出現時刻ms = chipHead.nノーツ出現時刻ms;
chip.nノーツ移動開始時刻ms = chipHead.nノーツ移動開始時刻ms;
Expand Down
10 changes: 7 additions & 3 deletions OpenTaiko/src/Songs/TJA/CChip.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace OpenTaiko;

internal class CChip : IComparable<CChip>, ICloneable {
public EScrollMode eScrollMode;
public EScrollMode eScrollMode_end;
public bool bHit;
public bool bVisible = true;
public bool bHideBarLine = true;
Expand All @@ -15,11 +16,14 @@ internal class CChip : IComparable<CChip>, ICloneable {
public double dbChipSizeRatio = 1.0;
public double db実数値;
public double dbBPM;
public double dbBPM_end;
public float fNow_Measure_s = 4.0f;//強制分岐のために追加.2020.04.21.akasoko26
public float fNow_Measure_m = 4.0f;//強制分岐のために追加.2020.04.21.akasoko26
public bool IsEndedBranching = false;//分岐が終わった時の連打譜面が非可視化になってしまうためフラグを追加.2020.04.21.akasoko26
public double dbSCROLL;
public double dbSCROLL_Y;
public double dbSCROLL_end;
public double dbSCROLL_Y_end;
public ECourse nBranch;
public int nSenote;
public int nState;
Expand Down Expand Up @@ -173,12 +177,12 @@ public void t初期化() {
this.nHorizontalChipDistance = 0;
this.nNoteTipDistance_X = 0;
this.nNoteTipDistance_Y = 0;
this.dbBPM = 120.0;
this.dbBPM_end = this.dbBPM = 120.0;
this.fNow_Measure_m = 4.0f;
this.fNow_Measure_s = 4.0f;
this.nScrollDirection = 0;
this.dbSCROLL = 1.0;
this.dbSCROLL_Y = 0.0f;
this.dbSCROLL_end = this.dbSCROLL = 1.0;
this.dbSCROLL_Y_end = this.dbSCROLL_Y = 0.0f;
}
public override string ToString() {

Expand Down
21 changes: 14 additions & 7 deletions OpenTaiko/src/Stages/07.Game/CStage演奏画面共通.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2868,13 +2868,19 @@ protected bool t進行描画_チップ(EInstrumentPad ePlayMode, int nPlayer) {
CChip pChip = dTX.listChip[nCurrentTopChip];
//Debug.WriteLine( "nCurrentTopChip=" + nCurrentTopChip + ", ch=" + pChip.nチャンネル番号.ToString("x2") + ", 発音位置=" + pChip.n発声位置 + ", 発声時刻ms=" + pChip.n発声時刻ms );
long time = pChip.n発声時刻ms - n現在時刻ms;

double _scrollSpeed = pChip.dbSCROLL * (dbCurrentScrollSpeed[nPlayer] + 1.0) / 10.0;
double _scrollSpeed_Y = pChip.dbSCROLL_Y * (dbCurrentScrollSpeed[nPlayer] + 1.0) / 10.0;
pChip.nHorizontalChipDistance = NotesManager.GetNoteX(pChip, time * pChip.dbBPM, _scrollSpeed, OpenTaiko.Skin.Game_Notes_Interval, play_bpm_time, pChip.eScrollMode, false);
if (pChip.nNoteEndTimems != 0) {
pChip.nNoteTipDistance_X = NotesManager.GetNoteX(pChip, (pChip.nNoteEndTimems - n現在時刻ms) * pChip.dbBPM, _scrollSpeed, OpenTaiko.Skin.Game_Notes_Interval, play_bpm_time, pChip.eScrollMode, true);
pChip.nNoteTipDistance_Y = NotesManager.GetNoteY(pChip, (pChip.nNoteEndTimems - n現在時刻ms) * pChip.dbBPM, _scrollSpeed_Y, OpenTaiko.Skin.Game_Notes_Interval, play_bpm_time, pChip.eScrollMode, true);
double th16DBeat = pChip.fBMSCROLLTime - play_bpm_time;
double _scroll_rate = (dbCurrentScrollSpeed[nPlayer] + 1.0) / 10.0;

double _scrollSpeed = pChip.dbSCROLL * _scroll_rate;
double _scrollSpeed_Y = pChip.dbSCROLL_Y * _scroll_rate;
pChip.nHorizontalChipDistance = NotesManager.GetNoteX(time, th16DBeat, pChip.dbBPM, _scrollSpeed, pChip.eScrollMode);
if (NotesManager.IsGenericRoll(pChip)) {
long msDTime_end = pChip.nNoteEndTimems - n現在時刻ms;
double th16DBeat_end = pChip.fBMSCROLLTime_end - play_bpm_time;
double _scrollSpeed_end = pChip.dbSCROLL_end * _scroll_rate;
double _scrollSpeed_Y_end = pChip.dbSCROLL_Y_end * _scroll_rate;
pChip.nNoteTipDistance_X = NotesManager.GetNoteX(msDTime_end, th16DBeat_end, pChip.dbBPM_end, _scrollSpeed_end, pChip.eScrollMode_end);
pChip.nNoteTipDistance_Y = NotesManager.GetNoteY(msDTime_end, th16DBeat_end, pChip.dbBPM_end, _scrollSpeed_Y_end, pChip.eScrollMode_end);
}


Expand Down Expand Up @@ -4498,6 +4504,7 @@ public void t演奏位置の変更(int nStartBar, int nPlayer) {

dTX.listChip[i].bHit = false;
dTX.listChip[i].bShow = true;
dTX.listChip[i].bShowRoll = true;
dTX.listChip[i].bProcessed = false;
dTX.listChip[i].bVisible = true;
dTX.listChip[i].IsHitted = false;
Expand Down
113 changes: 91 additions & 22 deletions OpenTaiko/src/Stages/07.Game/Taiko/CStage演奏ドラム画面.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Diagnostics;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
using DiscordRPC;
Expand Down Expand Up @@ -1474,8 +1475,9 @@ protected override void t進行描画_チップ_Taiko(CConfigIni configIni, ref

double _scrollSpeed = pChip.dbSCROLL_Y * (this.actScrollSpeed.dbConfigScrollSpeed[nPlayer] + 1.0) / 10.0;
float play_bpm_time = this.GetNowPBMTime(dTX, 0);
double th16DBeat = pChip.fBMSCROLLTime - play_bpm_time;

y += NotesManager.GetNoteY(pChip, time * pChip.dbBPM, _scrollSpeed, OpenTaiko.Skin.Game_Notes_Interval, play_bpm_time, pChip.eScrollMode, false);
y += NotesManager.GetNoteY(time, th16DBeat, pChip.dbBPM, _scrollSpeed, pChip.eScrollMode);
}

if (bSplitLane[nPlayer] || OpenTaiko.Tx.Puchichara[PuchiChara.tGetPuchiCharaIndexByName(OpenTaiko.GetActualPlayer(nPlayer))].effect.SplitLane) {
Expand Down Expand Up @@ -1659,6 +1661,8 @@ protected override void t進行描画_チップ_Taiko連打(CConfigIni configIni

#region[ 作り直したもの ]
if (pChip.bVisible) {
bool pHasBar = (NotesManager.IsRoll(pChip) || NotesManager.IsFuzeRoll(pChip));

if (NotesManager.IsGenericRoll(pChip)) {
if (pChip.nノーツ出現時刻ms != 0 && (nowTime < pChip.n発声時刻ms - pChip.nノーツ出現時刻ms))
pChip.bShow = false;
Expand Down Expand Up @@ -1691,7 +1695,18 @@ protected override void t進行描画_チップ_Taiko連打(CConfigIni configIni
long __dbt = nowTime;
long time = pChip.n発声時刻ms - __dbt;
float play_bpm_time = this.GetNowPBMTime(dTX, 0);
y += NotesManager.GetNoteY(pChip, time * pChip.dbBPM, _scrollSpeed, OpenTaiko.Skin.Game_Notes_Interval, play_bpm_time, pChip.eScrollMode, false);
double th16DBeat = pChip.fBMSCROLLTime - play_bpm_time;
y += NotesManager.GetNoteY(time, th16DBeat, pChip.dbBPM, _scrollSpeed, pChip.eScrollMode);
}

if (NotesManager.IsGenericBalloon(pChip)) {
if (nowTime >= pChip.n発声時刻ms && nowTime < pChip.nNoteEndTimems) {
x = NoteOriginX[nPlayer];
y = NoteOriginY[nPlayer];
} else if (nowTime >= pChip.nNoteEndTimems) {
x = x末端;
y = y末端;
}
}

if (bSplitLane[nPlayer] || OpenTaiko.Tx.Puchichara[PuchiChara.tGetPuchiCharaIndexByName(OpenTaiko.GetActualPlayer(nPlayer))].effect.SplitLane) {
Expand All @@ -1705,6 +1720,11 @@ protected override void t進行描画_チップ_Taiko連打(CConfigIni configIni
y末端 -= OpenTaiko.Skin.Game_Notes_Size[1] / 2;
}
}
}

bool isBodyXInScreen = (Math.Min(x, x末端) < OpenTaiko.Skin.Resolution[0] && Math.Max(x, x末端) > 0 - OpenTaiko.Skin.Game_Notes_Size[0]);
if (pHasBar) {
this.HideObscuringRoll(nPlayer, pChip, x, y, x末端, y末端, isBodyXInScreen, nowTime);
}

#region[ HIDSUD & STEALTH ]
Expand All @@ -1718,8 +1738,7 @@ protected override void t進行描画_チップ_Taiko連打(CConfigIni configIni
//if( CDTXMania.ConfigIni.eScrollMode != EScrollMode.Normal )
//x -= 10;

//if(x末端 > 0 - TJAPlayer3.Skin.Game_Notes_Size[0] && x < TJAPlayer3.Skin.Resolution[0])
if ((Math.Min(x, x末端) < OpenTaiko.Skin.Resolution[0] && Math.Max(x, x末端) > 0 - OpenTaiko.Skin.Game_Notes_Size[0])) {
if (isBodyXInScreen) {
if (OpenTaiko.Tx.Notes[(int)_gt] != null) {
//int num9 = this.actCombo.n現在のコンボ数.Drums >= 50 ? this.ctチップ模様アニメ.Drums.n現在の値 * 130 : 0;
//int num9 = this.actCombo.n現在のコンボ数.Drums >= 50 ? base.n現在の音符の顔番号 * 130 : 0;
Expand Down Expand Up @@ -1797,23 +1816,18 @@ protected override void t進行描画_チップ_Taiko連打(CConfigIni configIni
int _78_cut = 78 * _size[0] / 136;

if (NotesManager.IsRoll(pChip) || NotesManager.IsFuzeRoll(pChip)) {
if (NotesManager.IsFuzeRoll(pChip)
&& nowTime >= pChip.n発声時刻ms && nowTime < pChip.nNoteEndTimems) {
x = NoteOriginX[nPlayer];
y = NoteOriginY[nPlayer];
}


NotesManager.DisplayRoll(nPlayer, x, y, pChip, num9, normalColor, effectedColor, x末端, y末端);

if (OpenTaiko.Tx.SENotes[(int)_gt] != null) {
int _shift = NotesManager.IsBigRoll(pChip) ? 26 : 0;

if (!NotesManager.IsFuzeRoll(pChip)) {
OpenTaiko.Tx.SENotes[(int)_gt].vcScaleRatio.X = x末端 - x - 44 - _shift;
OpenTaiko.Tx.SENotes[(int)_gt].t2D描画(x + 90 + _shift, y + nSenotesY, new Rectangle(_60_cut, 8 * _size[1], 1, _size[1]));
OpenTaiko.Tx.SENotes[(int)_gt].vcScaleRatio.X = 1.0f;
OpenTaiko.Tx.SENotes[(int)_gt].t2D描画(x + 30 + _shift, y + nSenotesY, new Rectangle(0, 8 * _size[1], _60_cut, _size[1]));
if (pChip.bShowRoll) {
OpenTaiko.Tx.SENotes[(int)_gt].vcScaleRatio.X = x末端 - x - 44 - _shift;
OpenTaiko.Tx.SENotes[(int)_gt].t2D描画(x + 90 + _shift, y + nSenotesY, new Rectangle(_60_cut, 8 * _size[1], 1, _size[1]));
OpenTaiko.Tx.SENotes[(int)_gt].vcScaleRatio.X = 1.0f;
OpenTaiko.Tx.SENotes[(int)_gt].t2D描画(x + 30 + _shift, y + nSenotesY, new Rectangle(0, 8 * _size[1], _60_cut, _size[1]));
}
OpenTaiko.Tx.SENotes[(int)_gt].t2D描画(x - (_shift / 13), y + nSenotesY, new Rectangle(0, _size[1] * pChip.nSenote, _size[0], _size[1]));
} else {
NotesManager.DisplaySENotes(nPlayer, x + nSenotesX, y + nSenotesY, pChip);
Expand All @@ -1825,11 +1839,6 @@ protected override void t進行描画_チップ_Taiko連打(CConfigIni configIni

if (NotesManager.IsBalloon(pChip) || NotesManager.IsKusudama(pChip)) {
if (pChip.bShow) {
if (nowTime >= pChip.n発声時刻ms && nowTime < pChip.nNoteEndTimems)
x = NoteOriginX[nPlayer];
else if (nowTime >= pChip.nNoteEndTimems)
x = (NoteOriginX[nPlayer] + pChip.nNoteTipDistance_X);

NotesManager.DisplayNote(nPlayer, x, y, pChip, num9, OpenTaiko.Skin.Game_Notes_Size[0] * 2);
NotesManager.DisplaySENotes(nPlayer, x + nSenotesX, y + nSenotesY, pChip);

Expand Down Expand Up @@ -1881,6 +1890,65 @@ protected override void t進行描画_チップ_Taiko連打(CConfigIni configIni
#endregion
}

/// Detect and hide screen-obscuring rolls when any tips are out of screen
private void HideObscuringRoll(int iPlayer, CChip pChip, int xHead, int yHead, int xEnd, int yEnd, bool isBodyXInScreen, long nowTime) {
// display judging rolls
if (nowTime >= pChip.n発声時刻ms && nowTime <= pChip.nNoteEndTimems) {
pChip.bShowRoll = true;
return;
}

// ignore already out-of-screen rolls
bool isBodyYInScreen = (Math.Min(yHead, yEnd) < OpenTaiko.Skin.Resolution[1] && Math.Max(yHead, yEnd) > 0 - OpenTaiko.Skin.Game_Notes_Size[1]);
if (!(isBodyXInScreen && isBodyYInScreen)) {
return;
}

// display completely in-screen rolls
bool headInScreen = (xHead > 0 - OpenTaiko.Skin.Game_Notes_Size[0] && xHead < OpenTaiko.Skin.Resolution[0])
&& (yHead > 0 - OpenTaiko.Skin.Game_Notes_Size[1] && yHead < OpenTaiko.Skin.Resolution[1]);
bool endInScreen = (xEnd > 0 - OpenTaiko.Skin.Game_Notes_Size[0] && xEnd < OpenTaiko.Skin.Resolution[0])
&& (yEnd > 0 - OpenTaiko.Skin.Game_Notes_Size[1] && yEnd < OpenTaiko.Skin.Resolution[1]);
if (headInScreen && endInScreen) {
pChip.bShowRoll = true;
return;
}

// displacement per sec
double th16DBeat = -4 * pChip.dbBPM / 60;
int dxHead = NotesManager.GetNoteX(-1000, th16DBeat, pChip.dbBPM, pChip.dbSCROLL, pChip.eScrollMode);
int dyHead = NotesManager.GetNoteY(-1000, th16DBeat, pChip.dbBPM, pChip.dbSCROLL_Y, pChip.eScrollMode);
int dxEnd = NotesManager.GetNoteX(-1000, th16DBeat, pChip.dbBPM_end, pChip.dbSCROLL_end, pChip.eScrollMode_end);
int dyEnd = NotesManager.GetNoteY(-1000, th16DBeat, pChip.dbBPM_end, pChip.dbSCROLL_Y_end, pChip.eScrollMode_end);

// get move speed near the judgement mark

var head = new Vector2(xHead, yHead);
var end = new Vector2(xEnd, yEnd);
var origin = new Vector2(this.NoteOriginX[iPlayer], this.NoteOriginY[iPlayer]);
float pos = NearestLineSegRelPos(head, end, origin);

Vector2 dr = Vector2.Lerp(new(dxHead, dyHead), new(dxEnd, dyEnd), pos);
Vector2 rollNorm = Vector2.Normalize(new(yEnd - yHead, -(xEnd - xHead)));

int drCanMoveAwayMin = (OpenTaiko.Skin.Game_Notes_Size.Max() + 1) / 2;
// If the nearest point is roll tip, all moves may prevent obscuring.
// If the nearest point is roll body, only orthogonal moves may prevent obscuring.
float drAway = (pos > 0 && pos < 1) ? Math.Abs(Vector2.Dot(dr, rollNorm)) : dr.Length();
bool canMoveAway = drAway >= drCanMoveAwayMin;
pChip.bShowRoll = canMoveAway;
}

private static float NearestLineSegRelPos(Vector2 head, Vector2 end, Vector2 target) {
Vector2 body = end - head;
float len = body.Length();
Vector2 bodyUnit = Vector2.Normalize(body);

Vector2 dHead = target - head;
float dHeadProj = Vector2.Dot(dHead, bodyUnit);
return Math.Clamp(dHeadProj, 0f, len) / len;
}

protected override void t進行描画_チップ_ドラムス(CConfigIni configIni, ref CTja dTX, ref CChip pChip) {
}
protected override void t進行描画_チップ本体_ドラムス(CConfigIni configIni, ref CTja dTX, ref CChip pChip) {
Expand All @@ -1900,9 +1968,10 @@ protected override void t進行描画_チップ_小節線(CConfigIni configIni,
if (pChip.dbSCROLL_Y != 0.0) {
double _scrollSpeed = pChip.dbSCROLL_Y * (this.actScrollSpeed.dbConfigScrollSpeed[nPlayer] + 1.0) / 10.0;
long __dbt = (long)(SoundManager.PlayTimer.NowTimeMs * OpenTaiko.ConfigIni.SongPlaybackSpeed);
long time = pChip.n発声時刻ms - __dbt;
long msDTime = pChip.n発声時刻ms - __dbt;
float play_bpm_time = this.GetNowPBMTime(dTX, 0);
y += NotesManager.GetNoteY(pChip, time * pChip.dbBPM, _scrollSpeed, OpenTaiko.Skin.Game_Notes_Interval, play_bpm_time, pChip.eScrollMode, false);
double th16DBeat = pChip.fBMSCROLLTime - play_bpm_time;
y += NotesManager.GetNoteY(msDTime, th16DBeat, pChip.dbBPM, _scrollSpeed, pChip.eScrollMode);

//y += (int)(((pChip.n発声時刻ms - (CSound管理.rc演奏用タイマ.n現在時刻 * (((double)TJAPlayer3.ConfigIni.n演奏速度) / 20.0))) * pChip.dbBPM * pChip.dbSCROLL_Y * (this.act譜面スクロール速度.db現在の譜面スクロール速度[nPlayer] + 1.5)) / 628.7);
}
Expand Down
Loading

0 comments on commit 1aa4f58

Please sign in to comment.