
我对于常见的音游的认知就几处,跟着节奏,在到达节奏的那个点附近的时候按下Tap键触发。想起来很简单,好,于是上手做。
1. 需求public class Note : MonoBehaviour
{
private float remainTime;
private float duration = 2;
private float perfectTime = 1;
private float perfectTimeOffset = 0.05f;
private float greatTimeOffset = 0.15f;
private float moveSpeed = 1f;
//这两处有些不合理,应该用同一管理器传值,而不是每个单独脚本重新拖入位置
private RectTransform startLine;
private RectTransform endLine;
//
private RectTransform rectTrans;
public bool isActivated;
public bool isShow;
public bool hasStartedNextNote;
public bool hasTapped;
private void Update()
{
if (isActivated)
{
remainTime -= Time.deltaTime;
if (remainTime < perfectTime - greatTimeOffset && isShow && !hasTapped)
{
HideNote();
RhythmManager.Instance.NoteDeQueue();
//TODO: combo断连
RhythmManager.Instance.BreakCombo();
}
if(remainTime <= 0.001f )
{
Reset();
}
if (remainTime <= perfectTime + 0.01f && remainTime >= perfectTime - 0.01f && !hasStartedNextNote)
{
hasStartedNextNote = true;
RhythmManager.Instance.StartNextNote();
}
}
}
private void FixedUpdate()
{
if (isActivated)
{
rectTrans.anchoredPosition += new Vector2((endLine.anchoredPosition.x - startLine.anchoredPosition.x) * Time.deltaTime / 2, 0);
}
}
#region public API
public void Reset()
{
transform.position = startLine.transform.position;
remainTime = duration;
isActivated = false;
hasStartedNextNote = false;
hasTapped = false;
HideNote();
}
public void SetActive()
{
isActivated = true;
ShowNote();
}
public TapLevel BeTapped()
{
hasTapped = true;
HideNote();
RhythmManager.Instance.NoteDeQueue();
TapLevel tapLevel = TapLevel.Miss;
if (remainTime > perfectTime + greatTimeOffset || remainTime < perfectTime - greatTimeOffset)
tapLevel = TapLevel.Miss;
else if (remainTime <= perfectTime + perfectTimeOffset && remainTime >= perfectTime - perfectTimeOffset)
tapLevel = TapLevel.Perfect;
else
tapLevel = TapLevel.Good;
//TODO:隐藏节点 isShow = false;
return tapLevel;
}
#endregion
#region Helper
private void ShowNote()
{
isShow = true;
GetComponent().alpha = 1;
}
private void HideNote()
{
isShow = false;
GetComponent().alpha = 0;
}
#endregion
}
public class RhythmManager : UnitySingleton{ public Note[] notes; public Queue noteQueue; public int noteIdx = 0; //拍击顺序(临时) public string keyCodes; public bool inMusicMode; private void Awake() { initialization(); } void initialization() { notes = GameObject.Find("Notes_U").GetComponentsInChildren (); noteQueue = new Queue (); keyCodes = ""; } #region Public API public bool InAndOutMusicMode() { if (inMusicMode) { inMusicMode = false; AudioManager.Instance.OutMusicMode(); for (int idx = 0; idx < notes.Length; idx++) { notes[idx].Reset(); } noteQueue.Clear(); } else { inMusicMode = true; AudioManager.Instance.InMusicMode(); noteQueue.Enqueue(notes[noteIdx]); notes[noteIdx].SetActive(); return false; } } public void StartNextNote() { noteIdx = (noteIdx + 1) % notes.Length; noteQueue.Enqueue(notes[noteIdx]); notes[noteIdx].SetActive(); } public void NoteDeQueue() { noteQueue.Dequeue(); } public void BreakCombo() { keyCodes = ""; UIManager.Instance.GetPanelBase("ComboPanel").GetComponent ().BreakCombo(); } public void Tap(KeyCode keyCode) { if (noteQueue.Count == 0) return; TapLevel tapLevel = noteQueue.Peek().BeTapped(); UIManager.Instance.GetPanelBase("TapLevelPanel").GetComponent ().ShowTapLevelText(tapLevel); switch (tapLevel) { case TapLevel.Miss: keyCodes = ""; UIManager.Instance.GetPanelBase("ComboPanel").GetComponent ().BreakCombo(); break; case TapLevel.Good: keyCodes += keyCode.ToString(); UIManager.Instance.GetPanelBase("ComboPanel").GetComponent ().RefreshCombo(); break; case TapLevel.Perfect: keyCodes += keyCode.ToString(); UIManager.Instance.GetPanelBase("ComboPanel").GetComponent ().RefreshCombo(); break; default: Debug.LogError("传入的TapLevel有问题"); break; } } #endregion }
对旧方案的改进
新需求
缺点
通过设置Time.deltaTime的方式来实现减速提速效果虽然很方便,但用这种方法在减速的时候会出现降低帧数的情况,因为fixedUpdate是指定的帧数,在默认50帧的情况下,如果我们将Time.deltaTime/=2,那么除2后游戏的1秒等于正常下游戏中的0.5秒,但fixedUpdate仍然不变,就是说此时的帧数按照现实是2秒50帧,而正常情况下是1秒50帧,帧数是和除的系数成反比的。为了更好理解,在极端情况下,我们把系数设为50,那么现实中每秒就是1帧,这显然不是我们想要的。所以我考虑用复杂的方式,为所以和减速增速相关的地方乘除这个增量。