perf
This commit is contained in:
@@ -5,10 +5,11 @@ using Ichni.RhythmGame;
|
||||
using Ichni.RhythmGame.UI;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace Ichni
|
||||
{
|
||||
public class GameManager : SerializedMonoBehaviour
|
||||
public partial class GameManager : SerializedMonoBehaviour
|
||||
{
|
||||
public static GameManager instance;
|
||||
|
||||
@@ -33,6 +34,8 @@ namespace Ichni
|
||||
public ProjectInformation projectInformation;
|
||||
public SongInformation songInformation;
|
||||
|
||||
public NoteManager noteManager;
|
||||
|
||||
public BasePrefabsCollection basePrefabs;
|
||||
public Dictionary<string, CustomPrefabsCollection> customPrefabs;
|
||||
|
||||
@@ -42,7 +45,7 @@ namespace Ichni
|
||||
public GameLoadingCanvas gameLoadingCanvas;
|
||||
public SummaryPageCanvas summaryPageCanvas;
|
||||
|
||||
public float songTime => audioManager.songPlayer.songTimeSegment;
|
||||
public float songTime => audioManager.songPlayer.songTimeSegment - songInformation.offset;
|
||||
|
||||
public bool isDebugging;
|
||||
|
||||
@@ -57,4 +60,19 @@ namespace Ichni
|
||||
projectLoader.TestLoad();
|
||||
}
|
||||
}
|
||||
|
||||
public partial class GameManager
|
||||
{
|
||||
public static void RestartGame()
|
||||
{
|
||||
SceneManager.LoadScene("GameScene");
|
||||
Time.timeScale = 1f; // 确保重启时时间缩放恢复正常
|
||||
}
|
||||
|
||||
public static void ReturnToMenu()
|
||||
{
|
||||
SceneManager.LoadScene("MenuScene");
|
||||
Time.timeScale = 1f; // 确保返回时时间缩放恢复正常
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Ichni.RhythmGame;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEngine;
|
||||
@@ -18,17 +19,21 @@ namespace Ichni
|
||||
public List<Flick> checkingFlickList;
|
||||
|
||||
public List<InputUnitTap> inputUnitTapList;
|
||||
public List<InputUnitSlide> inputUnitSlideList;
|
||||
public List<InputUnitRelease> inputUnitReleaseList;
|
||||
public List<InputUnitTouch> inputUnitTouchList;
|
||||
public List<InputUnitSwipe> inputUnitSwipeList;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
for (int i = -2; i <= 12; i++)
|
||||
{
|
||||
inputUnitTapList.Add(new InputUnitTap(i, Vector2.zero));
|
||||
inputUnitSlideList.Add(new InputUnitSlide(i, Vector2.zero, Vector2.zero));
|
||||
inputUnitReleaseList.Add(new InputUnitRelease(i, Vector2.zero));
|
||||
}
|
||||
checkingTapList = new List<Tap>();
|
||||
checkingStayList = new List<Stay>();
|
||||
checkingHoldList = new List<Hold>();
|
||||
checkingFlickList = new List<Flick>();
|
||||
inputUnitTapList = new List<InputUnitTap>();
|
||||
inputUnitTouchList = new List<InputUnitTouch>();
|
||||
inputUnitSwipeList = new List<InputUnitSwipe>();
|
||||
RhythmInputManager.OnTap += SetNewInputUnitTap;
|
||||
RhythmInputManager.OnTouch += SetNewInputUnitTouch;
|
||||
RhythmInputManager.OnSwipe += SetNewInputUnitSwipe;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
@@ -37,58 +42,8 @@ namespace Ichni
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Application.platform == RuntimePlatform.WindowsPlayer ||
|
||||
Application.platform == RuntimePlatform.OSXPlayer ||
|
||||
Application.platform == RuntimePlatform.WindowsEditor ||
|
||||
Application.platform == RuntimePlatform.OSXEditor)
|
||||
{
|
||||
if (Mouse.current.leftButton.wasPressedThisFrame)
|
||||
{
|
||||
SetNewInputUnitTap(-1, Mouse.current.position.ReadValue());
|
||||
}
|
||||
|
||||
if (Mouse.current.leftButton.isPressed)
|
||||
{
|
||||
SetNewInputUnitSlide(-1, Mouse.current.position.ReadValue(), Mouse.current.delta.ReadValue());
|
||||
}
|
||||
|
||||
if (Mouse.current.rightButton.wasPressedThisFrame)
|
||||
{
|
||||
SetNewInputUnitTap(-2, Mouse.current.position.ReadValue());
|
||||
}
|
||||
|
||||
if (Mouse.current.rightButton.isPressed)
|
||||
{
|
||||
SetNewInputUnitSlide(-2, Mouse.current.position.ReadValue(), Mouse.current.delta.ReadValue());
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var touch in Touch.activeTouches)
|
||||
{
|
||||
switch (touch.phase)
|
||||
{
|
||||
case TouchPhase.Began:
|
||||
SetNewInputUnitTap(touch.finger.index, touch.screenPosition);
|
||||
SetNewInputUnitSlide(touch.finger.index, touch.screenPosition, Vector2.zero);
|
||||
break;
|
||||
case TouchPhase.Stationary:
|
||||
SetNewInputUnitSlide(touch.finger.index, touch.screenPosition, Vector2.zero);
|
||||
break;
|
||||
case TouchPhase.Moved:
|
||||
SetNewInputUnitSlide(touch.finger.index, touch.screenPosition, touch.delta);
|
||||
break;
|
||||
case TouchPhase.Ended:
|
||||
SetNewInputUnitRelease(touch.finger.index, touch.screenPosition);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
List<InputUnitTap> enablingInputUnitTapList = inputUnitTapList.FindAll(x => x.isEnabling);
|
||||
List<InputUnitSlide> enablingInputUnitSlideList = inputUnitSlideList.FindAll(x => x.isEnabling);
|
||||
List<InputUnitRelease> enablingInputUnitReleaseList = inputUnitReleaseList.FindAll(x => x.isEnabling);
|
||||
|
||||
foreach (InputUnitTap inputUnitTap in enablingInputUnitTapList)
|
||||
foreach (InputUnitTap inputUnitTap in inputUnitTapList)
|
||||
{
|
||||
List<Tap> availableTaps = new List<Tap>();
|
||||
foreach (Tap tap in checkingTapList)
|
||||
@@ -98,101 +53,133 @@ namespace Ichni
|
||||
availableTaps.Add(tap);
|
||||
}
|
||||
}
|
||||
|
||||
if (availableTaps.Count > 0)
|
||||
|
||||
List<Hold> availableHolds = new List<Hold>();
|
||||
foreach (Hold hold in checkingHoldList)
|
||||
{
|
||||
if (hold.CheckJudgeAvailability(inputUnitTap))
|
||||
{
|
||||
availableHolds.Add(hold);
|
||||
}
|
||||
}
|
||||
bool haveHold = availableHolds.Count > 0;
|
||||
bool haveTap = availableTaps.Count > 0;
|
||||
|
||||
Hold closestHold = availableHolds.Min();
|
||||
Tap closestTap = availableTaps.Min();
|
||||
|
||||
if (haveHold && haveTap)
|
||||
{
|
||||
if (closestHold.exactJudgeTime < closestTap.exactJudgeTime)
|
||||
{
|
||||
closestHold.ExecuteStartJudge();
|
||||
}
|
||||
else
|
||||
{
|
||||
closestTap.ExecuteStartJudge();
|
||||
}
|
||||
}
|
||||
else if (haveHold)
|
||||
{
|
||||
closestHold.ExecuteStartJudge();
|
||||
}
|
||||
else if (haveTap)
|
||||
{
|
||||
availableTaps.Sort();
|
||||
Tap closestTap = availableTaps[0];
|
||||
Debug.Log(closestTap.exactJudgeTime);
|
||||
closestTap.ExecuteStartJudge();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (InputUnitSlide inputUnitSlide in enablingInputUnitSlideList)
|
||||
|
||||
foreach (InputUnitSwipe inputUnitSwipe in inputUnitSwipeList)
|
||||
{
|
||||
/*List<Flick> availableFlicks = new List<Flick>();
|
||||
|
||||
List<Flick> availableFlicks = new List<Flick>();
|
||||
|
||||
foreach (Flick flick in checkingFlickList)
|
||||
{
|
||||
if (flick.CheckJudgeAvailability(inputUnitSlide))
|
||||
if (flick.CheckJudgeAvailability(inputUnitSwipe))
|
||||
{
|
||||
availableFlicks.Add(flick);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (availableFlicks.Count > 0)
|
||||
{
|
||||
availableFlicks.Sort();
|
||||
Flick closestFlick = availableFlicks[0];
|
||||
closestFlick.SetFirstJudge(inputUnitSlide.inputDeltaPosition);
|
||||
}*/
|
||||
|
||||
closestFlick.ExecuteStartJudge();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (InputUnitTouch inputUnitTouch in inputUnitTouchList)
|
||||
{
|
||||
List<Stay> availableStays = new List<Stay>();
|
||||
foreach (Stay stay in checkingStayList)
|
||||
{
|
||||
if (stay.CheckJudgeAvailability(inputUnitSlide))
|
||||
if (stay.CheckJudgeAvailability(inputUnitTouch))
|
||||
{
|
||||
availableStays.Add(stay);
|
||||
}
|
||||
}
|
||||
|
||||
List<Hold> availableHolds = new List<Hold>();
|
||||
foreach (Hold hold in checkingHoldList)
|
||||
{
|
||||
if (hold.CheckJudgeAvailability(inputUnitTouch))
|
||||
{
|
||||
availableHolds.Add(hold);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Stay stay in availableStays)
|
||||
{
|
||||
stay.ExecuteStartJudge();
|
||||
}
|
||||
|
||||
foreach (Hold hold in availableHolds)
|
||||
{
|
||||
hold.ExecuteProcessJudge();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (!GameManager.instance.audioManager.isPlaying)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < inputUnitTapList.Count; i++)
|
||||
{
|
||||
inputUnitTapList[i].isEnabling = false;
|
||||
inputUnitSlideList[i].isEnabling = false;
|
||||
inputUnitSlideList[i].inputDeltaPosition = Vector2.zero;
|
||||
inputUnitSlideList[i].isEnabling = false;
|
||||
}
|
||||
inputUnitTapList.Clear();
|
||||
inputUnitTouchList.Clear();
|
||||
inputUnitSwipeList.Clear();
|
||||
}
|
||||
|
||||
public void SetNewInputUnitTap(int fingerId, Vector2 inputPosition)
|
||||
{
|
||||
InputUnitTap inputUnitTap = inputUnitTapList.Find(x => x.fingerId == fingerId);
|
||||
inputUnitTap.isEnabling = true;
|
||||
inputUnitTap.inputPosition = inputPosition;
|
||||
//Debug.Log("Tap: " + fingerId + " " + inputPosition);
|
||||
InputUnitTap inputUnitTap = new InputUnitTap(fingerId, inputPosition);
|
||||
if(!inputUnitTapList.Exists(x => x.fingerId == fingerId))
|
||||
{
|
||||
inputUnitTapList.Add(inputUnitTap);
|
||||
//Debug.Log("Tap: " + fingerId + " " + inputPosition);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetNewInputUnitSlide(int fingerId, Vector2 inputPosition, Vector2 inputDeltaPosition)
|
||||
public void SetNewInputUnitTouch(int fingerId, Vector2 inputPosition)
|
||||
{
|
||||
InputUnitSlide inputUnitSlide = inputUnitSlideList.Find(x => x.fingerId == fingerId);
|
||||
inputUnitSlide.isEnabling = true;
|
||||
inputUnitSlide.inputPosition = inputPosition;
|
||||
inputUnitSlide.inputDeltaPosition = inputDeltaPosition;
|
||||
//Debug.Log("Slide: " + fingerId + " " + inputPosition + " " + inputDeltaPosition);
|
||||
InputUnitTouch inputUnitTouch = new InputUnitTouch(fingerId, inputPosition);
|
||||
if(!inputUnitTouchList.Exists(x => x.fingerId == fingerId))
|
||||
{
|
||||
inputUnitTouchList.Add(inputUnitTouch);
|
||||
}
|
||||
//Debug.Log("Touch: " + fingerId + " " + inputPosition);
|
||||
}
|
||||
|
||||
public void SetNewInputUnitRelease(int fingerId, Vector2 inputPosition)
|
||||
|
||||
public void SetNewInputUnitSwipe(int fingerId, Vector2 inputPosition, Vector2 delta)
|
||||
{
|
||||
InputUnitRelease inputUnitRelease = inputUnitReleaseList.Find(x => x.fingerId == fingerId);
|
||||
inputUnitRelease.isEnabling = true;
|
||||
inputUnitRelease.inputPosition = inputPosition;
|
||||
//Debug.Log("Release: " + fingerId + " " + inputPosition);
|
||||
InputUnitSwipe inputUnitSwipe = new InputUnitSwipe(fingerId, inputPosition, delta);
|
||||
if(!inputUnitSwipeList.Exists(x => x.fingerId == fingerId))
|
||||
{
|
||||
inputUnitSwipeList.Add(inputUnitSwipe);
|
||||
}
|
||||
//Debug.Log("Swipe: " + fingerId + " " + inputPosition + " " + delta);
|
||||
}
|
||||
}
|
||||
|
||||
public class InputUnit
|
||||
{
|
||||
public int fingerId;
|
||||
public bool isEnabling;
|
||||
|
||||
public Vector2 inputPosition;
|
||||
public InputManager inputManager => GameManager.instance.inputManager;
|
||||
}
|
||||
|
||||
public class InputUnitTap : InputUnit
|
||||
@@ -204,24 +191,24 @@ namespace Ichni
|
||||
}
|
||||
}
|
||||
|
||||
public class InputUnitSlide : InputUnit
|
||||
public class InputUnitTouch : InputUnit
|
||||
{
|
||||
public Vector2 inputDeltaPosition;
|
||||
|
||||
public InputUnitSlide(int fingerId, Vector2 inputPosition, Vector2 inputDeltaPosition)
|
||||
public InputUnitTouch(int fingerId, Vector2 inputPosition)
|
||||
{
|
||||
this.fingerId = fingerId;
|
||||
this.inputPosition = inputPosition;
|
||||
this.inputDeltaPosition = inputDeltaPosition;
|
||||
}
|
||||
}
|
||||
|
||||
public class InputUnitRelease : InputUnit
|
||||
public class InputUnitSwipe : InputUnit
|
||||
{
|
||||
public InputUnitRelease(int fingerId, Vector2 inputPosition)
|
||||
public Vector2 swipeDirection;
|
||||
|
||||
public InputUnitSwipe(int fingerId, Vector2 inputPosition, Vector2 swipeDirection)
|
||||
{
|
||||
this.fingerId = fingerId;
|
||||
this.inputPosition = inputPosition;
|
||||
this.swipeDirection = swipeDirection.normalized;
|
||||
}
|
||||
}
|
||||
}
|
||||
40
Assets/Scripts/Manager/NoteManager.cs
Normal file
40
Assets/Scripts/Manager/NoteManager.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ichni.RhythmGame
|
||||
{
|
||||
public class NoteManager : MonoBehaviour
|
||||
{
|
||||
private List<(float activationTime, NoteBase note)> pendingNotes = new List<(float, NoteBase)>();
|
||||
private int nextNoteIndex = 0;
|
||||
|
||||
public void RegisterNote(NoteBase note, float activationTime)
|
||||
{
|
||||
pendingNotes.Add((activationTime, note));
|
||||
}
|
||||
|
||||
// 在所有物体注册完毕后,对列表进行一次排序
|
||||
public void AllNotesRegistered()
|
||||
{
|
||||
pendingNotes.Sort((a, b) => a.activationTime.CompareTo(b.activationTime));
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// 如果所有音符都已激活,则不执行任何操作
|
||||
if (nextNoteIndex >= pendingNotes.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查下一个待激活的音符
|
||||
while (nextNoteIndex < pendingNotes.Count &&
|
||||
GameManager.instance.songTime >= pendingNotes[nextNoteIndex].activationTime)
|
||||
{
|
||||
pendingNotes[nextNoteIndex].note.gameObject.SetActive(true);
|
||||
nextNoteIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Manager/NoteManager.cs.meta
Normal file
11
Assets/Scripts/Manager/NoteManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e50ec54a2c71f744bfced70191dc2d0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using DG.Tweening;
|
||||
using Ichni.RhythmGame.Beatmap;
|
||||
using Sirenix.OdinInspector;
|
||||
using UniRx;
|
||||
@@ -28,13 +29,12 @@ namespace Ichni
|
||||
format = ES3.Format.JSON,
|
||||
location = ES3.Location.Resources
|
||||
};
|
||||
|
||||
[Button("TestLoad")]
|
||||
|
||||
public void TestLoad()
|
||||
{
|
||||
string beatMapFolderPath = "Beatmaps/" + InformationTransistor.instance.chapterName +
|
||||
"/" + InformationTransistor.instance.songName +
|
||||
"/" + InformationTransistor.instance.difficultyName;
|
||||
string beatMapFolderPath = "Beatmaps/" + InformationTransistor.instance.chapter.chapterIndex +
|
||||
"/" + InformationTransistor.instance.song.songName +
|
||||
"/" + InformationTransistor.instance.difficulty.difficultyName;
|
||||
|
||||
LoadProjectInfo(beatMapFolderPath);
|
||||
LoadSongInfo(beatMapFolderPath);
|
||||
@@ -49,27 +49,30 @@ namespace Ichni
|
||||
.Subscribe(_ =>
|
||||
{
|
||||
LoadBeatMap(beatMapFolderPath);
|
||||
|
||||
Observable.EveryUpdate()
|
||||
.Where(_ => ((BeatmapContainer_BM)GameManager.instance.beatmapContainer.matchedBM).remainingElementAmount.Value == 0)
|
||||
.First()
|
||||
.Subscribe(_ =>
|
||||
{
|
||||
GameManager.instance.gameUICanvas.readyText.DOFade(1, 0.5f)
|
||||
.SetLoops(4, LoopType.Yoyo).SetEase(Ease.InOutFlash).Play();
|
||||
|
||||
Observable.Timer(TimeSpan.FromSeconds(2)).First().Subscribe(_ =>
|
||||
{
|
||||
GameManager.instance.audioManager.isStarting = false;
|
||||
GameManager.instance.audioManager.songPlayer.PlaySong();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Observable.EveryUpdate()
|
||||
.Where(_ => ThemeBundleManager.instance.waitingBundleAmount.Value == 0 &&
|
||||
(GameManager.instance.beatmapContainer.matchedBM as BeatmapContainer_BM).remainingElementAmount.Value == 0)
|
||||
.First()
|
||||
.Subscribe(_ =>
|
||||
{
|
||||
Observable.Timer(TimeSpan.FromSeconds(2)).First().Subscribe(_ =>
|
||||
{
|
||||
GameManager.instance.audioManager.isStarting = false;
|
||||
});
|
||||
});
|
||||
|
||||
Observable.EveryUpdate()
|
||||
/*Observable.EveryUpdate()
|
||||
.Where(_ => !GameManager.instance.audioManager.isStarting)
|
||||
.First()
|
||||
.Subscribe(_ =>
|
||||
{
|
||||
GameManager.instance.audioManager.songPlayer.PlaySong();
|
||||
});
|
||||
|
||||
});*/
|
||||
}
|
||||
|
||||
public void Load(string chapterName, string musicName, string difficultyName)
|
||||
|
||||
209
Assets/Scripts/Manager/RhythmInputManager.cs
Normal file
209
Assets/Scripts/Manager/RhythmInputManager.cs
Normal file
@@ -0,0 +1,209 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Touch = UnityEngine.InputSystem.EnhancedTouch.Touch;
|
||||
using TouchPhase = UnityEngine.InputSystem.TouchPhase;
|
||||
|
||||
/// <summary>
|
||||
/// 为节奏游戏设计的输入管理器,处理多点触控并分发三种主要事件。
|
||||
/// 【重要】此版本内置了编辑器内的鼠标模拟功能,无需手机即可测试。
|
||||
/// </summary>
|
||||
public class RhythmInputManager : MonoBehaviour
|
||||
{
|
||||
// =====================================================================
|
||||
// 公共事件 (Public Events)
|
||||
// =====================================================================
|
||||
public static event Action<int, Vector2> OnTap;
|
||||
public static event Action<int, Vector2> OnTouch;
|
||||
public static event Action<int, Vector2, Vector2> OnSwipe;
|
||||
|
||||
// =====================================================================
|
||||
// 可配置参数 (Configurable Parameters)
|
||||
// =====================================================================
|
||||
|
||||
[Header("划动设置 (Swipe Settings)")]
|
||||
[Tooltip("识别为划动的最小移动距离(像素)")]
|
||||
[SerializeField] private float minSwipeDistance = 50.0f;
|
||||
|
||||
// =====================================================================
|
||||
// 内部状态 (Internal State)
|
||||
// =====================================================================
|
||||
private class TouchState
|
||||
{
|
||||
public int TouchId;
|
||||
public Vector2 StartPosition;
|
||||
public float StartTime;
|
||||
public Vector2 LastSwipeDirection = Vector2.zero;
|
||||
public bool IsTapCandidate = true;
|
||||
}
|
||||
|
||||
private readonly Dictionary<int, TouchState> _activeTouches = new Dictionary<int, TouchState>();
|
||||
|
||||
// 为鼠标模拟专门设置一个固定的Touch ID
|
||||
private const int MOUSE_TOUCH_ID = 999;
|
||||
|
||||
// =====================================================================
|
||||
// MonoBehaviour 生命周期方法 (Lifecycle Methods)
|
||||
// =====================================================================
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
//OnTap += (id, pos)=> Debug.Log($"Tap Detected: Touch ID {id}, Position {pos}");
|
||||
//OnTouch += (id, pos) => Debug.Log($"Touch Detected: Touch ID {id}, Position {pos}");
|
||||
//OnSwipe += (id, pos, dir) => Debug.Log($"Swipe Detected: Touch ID {id}, Position {pos}, Direction {dir}");
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// 使用预处理指令区分平台
|
||||
#if UNITY_EDITOR
|
||||
// --- 在Unity编辑器中,使用鼠标模拟触摸 ---
|
||||
ProcessMouseInput();
|
||||
#else
|
||||
// --- 在真机设备上,使用真实的触摸输入 ---
|
||||
ProcessRealTouchInput();
|
||||
#endif
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
// 核心处理逻辑 (Core Processing Logic)
|
||||
// =====================================================================
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// 【仅在编辑器中运行】处理鼠标输入并模拟触摸事件。
|
||||
/// </summary>
|
||||
private void ProcessMouseInput()
|
||||
{
|
||||
if (Mouse.current == null) return;
|
||||
|
||||
Vector2 position = Mouse.current.position.ReadValue();
|
||||
|
||||
if (Mouse.current.leftButton.wasPressedThisFrame)
|
||||
{
|
||||
ProcessInputEvent(MOUSE_TOUCH_ID, TouchPhase.Began, position);
|
||||
}
|
||||
else if (Mouse.current.leftButton.isPressed)
|
||||
{
|
||||
// 如果鼠标位置有变化,则为Moved,否则为Stationary
|
||||
if (Mouse.current.delta.ReadValue().sqrMagnitude > 0.1f)
|
||||
{
|
||||
ProcessInputEvent(MOUSE_TOUCH_ID, TouchPhase.Moved, position);
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessInputEvent(MOUSE_TOUCH_ID, TouchPhase.Stationary, position);
|
||||
}
|
||||
}
|
||||
else if (Mouse.current.leftButton.wasReleasedThisFrame)
|
||||
{
|
||||
ProcessInputEvent(MOUSE_TOUCH_ID, TouchPhase.Ended, position);
|
||||
}
|
||||
|
||||
if (Mouse.current.rightButton.wasPressedThisFrame)
|
||||
{
|
||||
ProcessInputEvent(MOUSE_TOUCH_ID + 1, TouchPhase.Began, position);
|
||||
}
|
||||
else if (Mouse.current.rightButton.isPressed)
|
||||
{
|
||||
// 如果鼠标位置有变化,则为Moved,否则为Stationary
|
||||
if (Mouse.current.delta.ReadValue().sqrMagnitude > 0.1f)
|
||||
{
|
||||
ProcessInputEvent(MOUSE_TOUCH_ID + 1, TouchPhase.Moved, position);
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessInputEvent(MOUSE_TOUCH_ID + 1, TouchPhase.Stationary, position);
|
||||
}
|
||||
}
|
||||
else if (Mouse.current.rightButton.wasReleasedThisFrame)
|
||||
{
|
||||
ProcessInputEvent(MOUSE_TOUCH_ID + 1, TouchPhase.Ended, position);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// 【仅在真机上运行】处理真实的触摸屏输入。
|
||||
/// </summary>
|
||||
private void ProcessRealTouchInput()
|
||||
{
|
||||
if (Touchscreen.current == null) return;
|
||||
|
||||
foreach (Touch touch in Touch.activeTouches)
|
||||
{
|
||||
ProcessInputEvent(
|
||||
touch.touchId,
|
||||
touch.phase,
|
||||
touch.screenPosition
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 所有输入事件的核心处理函数,无论是真实触摸还是鼠标模拟都会调用它。
|
||||
/// </summary>
|
||||
private void ProcessInputEvent(int touchId, TouchPhase phase, Vector2 position)
|
||||
{
|
||||
switch (phase)
|
||||
{
|
||||
case TouchPhase.Began:
|
||||
var newState = new TouchState
|
||||
{
|
||||
TouchId = touchId,
|
||||
StartPosition = position,
|
||||
StartTime = Time.time,
|
||||
};
|
||||
_activeTouches[touchId] = newState;
|
||||
OnTap?.Invoke(touchId, position);
|
||||
OnTouch?.Invoke(touchId, position);
|
||||
break;
|
||||
|
||||
case TouchPhase.Moved:
|
||||
if (_activeTouches.TryGetValue(touchId, out TouchState movedState))
|
||||
{
|
||||
OnTouch?.Invoke(touchId, position);
|
||||
DetectSwipe(movedState, position);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case TouchPhase.Stationary:
|
||||
if (_activeTouches.TryGetValue(touchId, out TouchState stationaryState))
|
||||
{
|
||||
OnTouch?.Invoke(touchId, position);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case TouchPhase.Canceled:
|
||||
if (_activeTouches.ContainsKey(touchId))
|
||||
{
|
||||
_activeTouches.Remove(touchId);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检测划动逻辑 (无需修改)
|
||||
/// </summary>
|
||||
private void DetectSwipe(TouchState state, Vector2 currentPosition)
|
||||
{
|
||||
Vector2 swipeVector = currentPosition - state.StartPosition;
|
||||
if (swipeVector.magnitude < minSwipeDistance) return;
|
||||
|
||||
Vector2 direction = swipeVector.normalized;
|
||||
|
||||
// 检查是否是新的划动方向
|
||||
if (Vector2.Dot(direction, state.LastSwipeDirection) < 0.5f)
|
||||
{
|
||||
OnSwipe?.Invoke(state.TouchId, state.StartPosition, direction);
|
||||
state.LastSwipeDirection = direction;
|
||||
state.StartPosition = currentPosition;
|
||||
state.StartTime = Time.time;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Manager/RhythmInputManager.cs.meta
Normal file
11
Assets/Scripts/Manager/RhythmInputManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99971dd6462223c4596d435e8acdcfb8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -21,15 +21,7 @@ namespace Ichni
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = this;
|
||||
//DontDestroyOnLoad(gameObject); TODO: 后续处理
|
||||
}
|
||||
else if (instance != this)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
instance = this;
|
||||
|
||||
loadedThemeBundleList = new List<ThemeBundle>();
|
||||
AssetBundle.UnloadAllAssetBundles(true);
|
||||
@@ -101,7 +93,6 @@ namespace Ichni
|
||||
else if (Application.platform == RuntimePlatform.OSXEditor ||
|
||||
Application.platform == RuntimePlatform.OSXPlayer)
|
||||
{
|
||||
|
||||
uri = Application.streamingAssetsPath + "/ThemeBundles/OSX/" + themeBundleName;
|
||||
}
|
||||
else if (Application.platform == RuntimePlatform.Android)
|
||||
@@ -118,11 +109,12 @@ namespace Ichni
|
||||
yield break;
|
||||
}
|
||||
|
||||
UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(uri, 0);
|
||||
yield return request.SendWebRequest();
|
||||
AssetBundle bundle = AssetBundle.LoadFromFile(uri);
|
||||
AssetBundleCreateRequest createRequest = AssetBundle.LoadFromFileAsync(uri);
|
||||
yield return createRequest;
|
||||
AssetBundle bundle = createRequest.assetBundle;
|
||||
Object[] ob = bundle.LoadAllAssets<Object>();
|
||||
loadedThemeBundleList.Add(new ThemeBundle(themeBundleName));
|
||||
|
||||
for (int i = 0; i < ob.Length; i++)
|
||||
{
|
||||
if (ob[i].GetType() == typeof(GameObject))
|
||||
|
||||
Reference in New Issue
Block a user