修正了Tap的名称,编写了渲染Note的逻辑

This commit is contained in:
OrdinaryMan647 2025-11-19 01:26:30 +08:00
parent 62853fa9be
commit 1fcb6dedf0
20 changed files with 1056 additions and 273 deletions

File diff suppressed because one or more lines are too long

View File

@ -148,6 +148,7 @@ GameObject:
- component: {fileID: 5207352570132040939} - component: {fileID: 5207352570132040939}
- component: {fileID: 8104531933206489017} - component: {fileID: 8104531933206489017}
- component: {fileID: 7810372270032017921} - component: {fileID: 7810372270032017921}
- component: {fileID: 7093576537923845205}
m_Layer: 0 m_Layer: 0
m_Name: HeadAnchorPoint m_Name: HeadAnchorPoint
m_TagString: Untagged m_TagString: Untagged
@ -242,3 +243,15 @@ MeshCollider:
m_Convex: 0 m_Convex: 0
m_CookingOptions: 30 m_CookingOptions: 30
m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0} m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
--- !u!114 &7093576537923845205
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8900154505411094545}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a3d1b0613bc35c14a915a806b27b6cf5, type: 3}
m_Name:
m_EditorClassIdentifier:

View File

@ -11,7 +11,7 @@ GameObject:
- component: {fileID: 3133920083175420714} - component: {fileID: 3133920083175420714}
- component: {fileID: 6279844256921695762} - component: {fileID: 6279844256921695762}
m_Layer: 0 m_Layer: 0
m_Name: NoteAnchorPoint m_Name: TapAnchorPoint
m_TagString: Untagged m_TagString: Untagged
m_Icon: {fileID: 0} m_Icon: {fileID: 0}
m_NavMeshLayer: 0 m_NavMeshLayer: 0
@ -93,10 +93,10 @@ GameObject:
serializedVersion: 6 serializedVersion: 6
m_Component: m_Component:
- component: {fileID: 7443082168914965180} - component: {fileID: 7443082168914965180}
- component: {fileID: 4869839956365182491}
- component: {fileID: 715087861950065430} - component: {fileID: 715087861950065430}
- component: {fileID: 673455592900407993}
m_Layer: 0 m_Layer: 0
m_Name: Note m_Name: Tap
m_TagString: Untagged m_TagString: Untagged
m_Icon: {fileID: 0} m_Icon: {fileID: 0}
m_NavMeshLayer: 0 m_NavMeshLayer: 0
@ -119,18 +119,6 @@ Transform:
- {fileID: 3133920083175420714} - {fileID: 3133920083175420714}
m_Father: {fileID: 0} m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &4869839956365182491
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2366632135410690476}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a2100bdbe3afed446ab147d3cf7c0508, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!65 &715087861950065430 --- !u!65 &715087861950065430
BoxCollider: BoxCollider:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -152,6 +140,18 @@ BoxCollider:
serializedVersion: 3 serializedVersion: 3
m_Size: {x: 1, y: 1, z: 0} m_Size: {x: 1, y: 1, z: 0}
m_Center: {x: 0, y: 0, z: 0} m_Center: {x: 0, y: 0, z: 0}
--- !u!114 &673455592900407993
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2366632135410690476}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f055fb95e30ebde45b74584656d8d3d8, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &8241740096970702598 --- !u!1 &8241740096970702598
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -163,7 +163,7 @@ GameObject:
- component: {fileID: 8905090958658591294} - component: {fileID: 8905090958658591294}
- component: {fileID: 5017689155040747022} - component: {fileID: 5017689155040747022}
m_Layer: 0 m_Layer: 0
m_Name: NoteRenderer m_Name: TapRenderer
m_TagString: Untagged m_TagString: Untagged
m_Icon: {fileID: 0} m_Icon: {fileID: 0}
m_NavMeshLayer: 0 m_NavMeshLayer: 0

View File

@ -417,9 +417,9 @@ RectTransform:
m_Father: {fileID: 1791412692} m_Father: {fileID: 1791412692}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 1, y: 0} m_AnchorMin: {x: 1, y: 0}
m_AnchorMax: {x: 1, y: 0} m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: -155, y: 457} m_AnchoredPosition: {x: -140, y: -1.6697998}
m_SizeDelta: {x: 280, y: 500} m_SizeDelta: {x: 280, y: -11.34039}
m_Pivot: {x: 0.5, y: 0.5} m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &35238248 --- !u!114 &35238248
MonoBehaviour: MonoBehaviour:
@ -3599,7 +3599,7 @@ GameObject:
- component: {fileID: 450412148} - component: {fileID: 450412148}
- component: {fileID: 450412147} - component: {fileID: 450412147}
m_Layer: 5 m_Layer: 5
m_Name: ChartStting m_Name: ChartSetting
m_TagString: Untagged m_TagString: Untagged
m_Icon: {fileID: 0} m_Icon: {fileID: 0}
m_NavMeshLayer: 0 m_NavMeshLayer: 0
@ -8194,6 +8194,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 071aa469eea9e9d4d9d022c8a98fa777, type: 3} m_Script: {fileID: 11500000, guid: 071aa469eea9e9d4d9d022c8a98fa777, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
_Transform: {fileID: 0}
--- !u!1 &1166455538 --- !u!1 &1166455538
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@ -22,7 +22,7 @@ public abstract class BasePool<BaseClass> : MonoBehaviour where BaseClass : Mono
/// <summary> /// <summary>
/// 依据一个原型,返回一个空的可用对象 /// 依据一个原型,返回一个空的可用对象
/// </summary> /// </summary>
public DerivedClass Get<DerivedClass>(DerivedClass prefab) where DerivedClass : BaseClass public virtual DerivedClass Get<DerivedClass>(DerivedClass prefab) where DerivedClass : BaseClass
{ {
var type = typeof(DerivedClass); var type = typeof(DerivedClass);
if (!Pools.ContainsKey(type)) if (!Pools.ContainsKey(type))
@ -42,8 +42,10 @@ public abstract class BasePool<BaseClass> : MonoBehaviour where BaseClass : Mono
//如果对象池没有对象,则创建一个对象 //如果对象池没有对象,则创建一个对象
obj = Instantiate(prefab); obj = Instantiate(prefab);
ActiveObjectList[type].Add(obj); ActiveObjectList[type].Add(obj);
//运行调用方法
OnCreate(obj); OnCreate(obj);
} }
//激活时调用Get钩子
OnGet(obj); OnGet(obj);
obj.gameObject.SetActive(true); obj.gameObject.SetActive(true);
obj.enabled = true; obj.enabled = true;
@ -53,12 +55,16 @@ public abstract class BasePool<BaseClass> : MonoBehaviour where BaseClass : Mono
/// <summary> /// <summary>
/// 回收当前对象 /// 回收当前对象
/// </summary> /// </summary>
public void Release(BaseClass Object) public virtual void Release(BaseClass Object)
{ {
if(Object != null)
{
UnityEngine.Debug.LogError("BasePool" + ":输入为Null,请检查逻辑");
}
var type = Object.GetType(); var type = Object.GetType();
//如果字典中没有该类的对象池,则创建一个该类型的对象池 //如果字典中没有该类的对象池,则创建一个该类型的对象池
if (!Pools.ContainsKey(type)) Pools[type] = new Stack<BaseClass>(); if (!Pools.ContainsKey(type)) Pools[type] = new Stack<BaseClass>();
//回收时调用释放钩子
OnRelease(Object); OnRelease(Object);
Object.gameObject.SetActive(false); Object.gameObject.SetActive(false);
@ -70,7 +76,7 @@ public abstract class BasePool<BaseClass> : MonoBehaviour where BaseClass : Mono
/// </summary> /// </summary>
/// <param name="Object"></param> /// <param name="Object"></param>
/// <returns></returns> /// <returns></returns>
public bool ContainsObject(BaseClass Object) public virtual bool ContainsObject(BaseClass Object)
{ {
var type = Object.GetType(); var type = Object.GetType();
//如果没有该类型的对象池,则返回假 //如果没有该类型的对象池,则返回假
@ -83,7 +89,7 @@ public abstract class BasePool<BaseClass> : MonoBehaviour where BaseClass : Mono
/// <remarks> /// <remarks>
/// <paramref name="该操作会清空所有的对象"/> /// <paramref name="该操作会清空所有的对象"/>
/// </remarks> /// </remarks>
public void ClearPool() public virtual void ClearPool()
{ {
foreach (var stack in Pools.Values) foreach (var stack in Pools.Values)
{ {
@ -95,7 +101,7 @@ public abstract class BasePool<BaseClass> : MonoBehaviour where BaseClass : Mono
Pools.Clear(); Pools.Clear();
} }
/// <summary> /// <summary>
/// 返回一个当前类型的只读列表 /// 返回一个当前类型的只读列表(其实有更好的写法,之后会尝试优化,不使用ReadOnlyCollection)
/// </summary> /// </summary>
public ReadOnlyCollection<DerivedClass> GetActiveObjectList<DerivedClass>() where DerivedClass : BaseClass public ReadOnlyCollection<DerivedClass> GetActiveObjectList<DerivedClass>() where DerivedClass : BaseClass
{ {

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
/// <summary> /// <summary>
/// 谱面运行数据类,负责将谱面数据解析之后生成运行时数据项,与控制层通讯,这些数据项是查询现有数据项的唯一依据 /// 谱面运行数据类,负责将谱面数据解析之后生成运行时数据项,与控制层通讯,这些数据项是查询现有数据项的唯一依据
@ -12,14 +13,24 @@ public class ChartRuntimeModel
/// </summary> /// </summary>
public SortedSet<RuntimeBaseNoteData> ChartRuntimeSet = new SortedSet<RuntimeBaseNoteData>(new UniversalBaseNoteComparer()); public SortedSet<RuntimeBaseNoteData> ChartRuntimeSet = new SortedSet<RuntimeBaseNoteData>(new UniversalBaseNoteComparer());
/// <summary> /// <summary>
/// 输入搜索的开始与结束时间,返回符合条件的对象视图 /// 输入搜索的开始与结束时间,返回符合条件的对象视图,当输入小于0时,返回Null
/// </summary> /// </summary>
public SortedSet<RuntimeBaseNoteData> SearchRange(float startTime, float endTime) public SortedSet<RuntimeBaseNoteData> SearchRange(float startTime, float endTime)
{ {
var view = ChartRuntimeSet.GetViewBetween(new TempBaseNoteComparer(startTime), new TempBaseNoteComparer(endTime)); if(startTime<=0||endTime <= 0) { return null; }
//深拷贝
var view = new SortedSet<RuntimeBaseNoteData>(ChartRuntimeSet.GetViewBetween(
new TempBaseNoteComparer(startTime),
new TempBaseNoteComparer(endTime)
)
);
return view; return view;
} }
/// <summary> /// <summary>
/// 清除所有的运行时数据
/// </summary>
public void Clear() { ChartRuntimeSet.Clear(); UnityEngine.Debug.Log(ChartRuntimeSet.Count); }
/// <summary>
/// 删除指定的数据项 /// 删除指定的数据项
/// </summary> /// </summary>
public void DeleteDataItem(RuntimeBaseNoteData obj) public void DeleteDataItem(RuntimeBaseNoteData obj)
@ -27,7 +38,7 @@ public class ChartRuntimeModel
ChartRuntimeSet.Remove(obj); ChartRuntimeSet.Remove(obj);
} }
/// <summary> /// <summary>
/// 获得指定的数据项引用,如果不存在对应的数据项则会返回null /// 获得指定的数据项引用,如果不存在对应的数据项则会返回Null
/// </summary> /// </summary>
public RuntimeBaseNoteData GetDataItem(RuntimeBaseNoteData obj) public RuntimeBaseNoteData GetDataItem(RuntimeBaseNoteData obj)
{ {
@ -56,7 +67,7 @@ public class ChartRuntimeModel
{ {
switch (item) switch (item)
{ {
case RuntimeNoteData: case RuntimeTapData:
{ {
chart.noteList.Add(new NoteListItem( chart.noteList.Add(new NoteListItem(
item.xPos, item.xPos,
@ -109,6 +120,9 @@ public class ChartRuntimeModel
} }
} }
/// <summary>
/// 比较器,逻辑为同一个位置,同一个时间,不能出现同一种类型的Note
/// </summary>
public class UniversalBaseNoteComparer : IComparer<RuntimeBaseNoteData> public class UniversalBaseNoteComparer : IComparer<RuntimeBaseNoteData>
{ {
public int Compare(RuntimeBaseNoteData x, RuntimeBaseNoteData y) public int Compare(RuntimeBaseNoteData x, RuntimeBaseNoteData y)
@ -169,9 +183,9 @@ public class TempBaseNoteComparer : RuntimeBaseNoteData
targetTime = time; targetTime = time;
} }
} }
public class RuntimeNoteData : RuntimeBaseNoteData public class RuntimeTapData : RuntimeBaseNoteData
{ {
public RuntimeNoteData(float targetTime, float xPos, float yPos, BPMGroup bpmGroup) public RuntimeTapData(float targetTime, float xPos, float yPos, BPMGroup bpmGroup)
{ {
this.targetTime = targetTime; this.targetTime = targetTime;
this.xPos = xPos; this.xPos = xPos;

View File

@ -1,22 +1,48 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
public class NotePoolManager : BasePool<BaseNote> public class NotePoolManager : BasePool<BaseNote>
{ {
/// <summary>
/// 基于运行时数据用于存储生成出来活跃对象列表
/// </summary>
private Dictionary<RuntimeBaseNoteData, BaseNote> _dataToNoteCache = new Dictionary<RuntimeBaseNoteData, BaseNote>();
/// <summary>
/// 在每一个对象被创建出来的时候都会自动为其注册返回事件
/// </summary>
protected override void OnCreate(BaseNote obj) protected override void OnCreate(BaseNote obj)
{ {
obj.OnNoteUesd += ReturnBaseNoteToPool; obj.OnNoteUesd += ReturnBaseNoteToPool;
} }
/// <summary>
/// 在激活新的对象的时候,将会在当前对象池中存储该对象的数据,用于快速查找
/// </summary>
protected override void OnGet(BaseNote obj) protected override void OnGet(BaseNote obj)
{ {
base.OnGet(obj); base.OnGet(obj);
} // 缓存映射关系
protected override void OnRelease(BaseNote obj) if (obj.SelfRef != null)
{ {
_dataToNoteCache.Add(obj.SelfRef, obj);
}
} }
/// <summary> /// <summary>
/// 泛型note回收方法 /// 在对象被回收的时候,从活跃列表中移除该对象
/// </summary>
protected override void OnRelease(BaseNote obj)
{
base.OnRelease(obj);
// 清理缓存
if (obj.SelfRef != null && _dataToNoteCache.ContainsKey(obj.SelfRef))
{
_dataToNoteCache.Remove(obj.SelfRef);
}
}
/// <summary>
/// 泛型Note回收方法
/// </summary> /// </summary>
/// <param name="note"></param>
public void ReturnBaseNoteToPool(BaseNote note) public void ReturnBaseNoteToPool(BaseNote note)
{ {
//如果字典中没有该类的对象池,则创建一个 //如果字典中没有该类的对象池,则创建一个
@ -25,5 +51,81 @@ public class NotePoolManager : BasePool<BaseNote>
Pools[type].Push(note); Pools[type].Push(note);
note.gameObject.SetActive(false); note.gameObject.SetActive(false);
} }
public override void ClearPool()
{
foreach (var list in ActiveObjectList)
{
foreach (var note in list.Value)
{
ReturnBaseNoteToPool(note);
}
}
}
/// <summary>
/// 使用运行时数据以近似遍历的方式在父对象池进行变量查找
/// </summary>
public BaseNote GetNoteByRuntimeData(RuntimeBaseNoteData data)
{
if (data == null)
{
UnityEngine.Debug.LogError("NotePoolManager" + "传入的数据是Null");
return null;
}
BaseNote note = null;
switch (data)
{
case RuntimeTapData:
{
ForEach((TapController n) =>
{
if (n.SelfRef == data) note = n;
});
break;
}
case RuntimeDragData:
{
ForEach((DragController n) =>
{
if (n.SelfRef == data) note = n;
});
break;
}
case RuntimeFlickData:
{
ForEach((FlickController n) =>
{
if (n.SelfRef == data) note = n;
});
break;
}
case RuntimeSnakeData:
{
ForEach((DataFlowController n) =>
{
if (n.SelfRef == data) note = n;
});
break;
}
}
UnityEngine.Debug.LogError("NotePoolManager" + ":这个运行时数据不在对象池的键中,没有找到对应的视图对象");
return note;
}
/// <summary>
/// 在Note自己的字典集合中查询对象,查找失败将会返回Null,该方法仍在测试中
/// </summary>
public BaseNote GetNoteByRuntimeDataInPool(RuntimeBaseNoteData data)
{
if (data == null)
{
UnityEngine.Debug.LogError("NotePoolManager" + ":传入的数据是Null");
return null;
}
if (_dataToNoteCache.TryGetValue(data, out BaseNote result))
{
return result;
}
return null;
}
} }

View File

@ -1,6 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine; using UnityEngine;
using static TMPro.Examples.TMP_ExampleScript_01;
/// <summary> /// <summary>
/// 用于描述Note判定情况的委托 /// 用于描述Note判定情况的委托
@ -173,14 +175,20 @@ public abstract class BaseNote : MonoBehaviour,IRaycastHittable
//像判定区间,还有游戏难度,关卡属性,可以放在这里初始化 //像判定区间,还有游戏难度,关卡属性,可以放在这里初始化
} }
/// <summary> /// <summary>
/// 返回一个自己的引用 /// 返回一个自己的引用
/// </summary> /// </summary>
public RuntimeBaseNoteData OnHitByRay(RaycastHit hit) virtual public RuntimeBaseNoteData OnHitByRay(RaycastHit hit)
{ {
// 打印自己的信息 // 打印自己的信息
Debug.Log($"物体 {gameObject.name} 被击中了!"); Debug.Log($"物体 {gameObject.name} 被击中了!\n" +
Debug.Log($"碰撞点: {hit.point}, 法线: {hit.normal}"); $"碰撞点: {hit.point}, 法线: {hit.normal}\n" +
$"自身引用为{SelfRef}\n" +
$"父对象: {transform.parent?.name}"
);
// 可以添加更多自定义信息 // 可以添加更多自定义信息
return SelfRef; return SelfRef;
} }

View File

@ -48,10 +48,11 @@ public class DataFlowController : BaseNote
} }
else else
{ {
retObj = Instantiate<DataFlowUnit>(dataFlowUnitPrefab,_transform); retObj = Instantiate<DataFlowUnit>(dataFlowUnitPrefab, _transform);
} }
retObj.gameObject.SetActive(true); retObj.gameObject.SetActive(true);
retObj.enabled = true; retObj.enabled = true;
retObj.SelfRef = (RuntimeSnakeData)SelfRef;
return retObj; return retObj;
} }
@ -64,13 +65,16 @@ public class DataFlowController : BaseNote
{ {
obj.gameObject.SetActive(false); obj.gameObject.SetActive(false);
obj.enabled = false; obj.enabled = false;
dataFlowUnitPool.Push(obj); dataFlowUnitPool.Push(obj);
} }
} }
private void CreateDataFlow( float valueInterval,ReferencePointLocation referencePoint,float currentTime) private void CreateDataFlow(float valueInterval, ReferencePointLocation referencePoint, float currentTime)
{ {
if (SelfRef == null)
{
Debug.LogError($"当前对象没有数据,请检查主控赋值");
}
//指定起始坐标 //指定起始坐标
Vector2 startPoint = new Vector2(_startPointXPos, _startPointYPos); Vector2 startPoint = new Vector2(_startPointXPos, _startPointYPos);
Vector2 endPoint = new Vector2(_endPointXPos, _endPointYPos); Vector2 endPoint = new Vector2(_endPointXPos, _endPointYPos);
@ -83,38 +87,41 @@ public class DataFlowController : BaseNote
//计算出点的位置 //计算出点的位置
var tempEndPoint = BezierFunctions.GetBezierPoint( var tempEndPoint = BezierFunctions.GetBezierPoint(
startPoint, startPoint,
endPoint, endPoint,
referencePoint, referencePoint,
(currentTime + valueInterval) / _endTime (currentTime + valueInterval) / _endTime
); );
GetView().Init( var temp = GetView();
tempStartPoint, temp.Init(
tempEndPoint, tempStartPoint,
currentTime, tempEndPoint,
currentTime + valueInterval, currentTime,
0.4f, currentTime + valueInterval,
_songInformation, 0.4f,
_songInformation,
_BPMGroup _BPMGroup
); );
temp.SelfRef = (RuntimeSnakeData)SelfRef;
//自增时间 //自增时间
currentTime += valueInterval; currentTime += valueInterval;
//移动尾部 //移动尾部
tempStartPoint = tempEndPoint; tempStartPoint = tempEndPoint;
} }
//这里生成最后一段蛇 //这里生成最后一段蛇
GetView().Init( var go = GetView();
tempStartPoint, go.Init(
endPoint, tempStartPoint,
currentTime, endPoint,
_endTime, currentTime,
0.4f, _endTime,
_songInformation, 0.4f,
_songInformation,
_BPMGroup _BPMGroup
); );
go.SelfRef = (RuntimeSnakeData)SelfRef;
} }
public void Init(Vector2 startPoint, Vector2 endPoint, float startTime, float endTime, float width, SongInformationContainer container, BPMGroup timing, ReferencePointLocation referencePoint) public void Init(Vector2 startPoint, Vector2 endPoint, float startTime, float endTime, float width, SongInformationContainer container, BPMGroup timing, ReferencePointLocation referencePoint)
{ {
@ -134,7 +141,8 @@ public class DataFlowController : BaseNote
_BPMGroup = timing; _BPMGroup = timing;
CreateDataFlow(_BPMGroup.Beat / 4, referencePoint, startTime); Debug.Log(SelfRef);
CreateDataFlow(_BPMGroup.Beat / 2, referencePoint, startTime);
} }
} }

View File

@ -1,12 +1,13 @@
using UnityEngine; using UnityEngine;
using UnityEngine.UIElements;
public class DataFlowUnit : DataFlowController
public class DataFlowUnit : MonoBehaviour
{ {
//protected Transform _transform; protected Transform _transform;
//protected Transform _rendererTransform; protected Transform _rendererTransform;
//protected Transform _anchorPointTransform; protected Transform _anchorPointTransform;
public RuntimeSnakeData SelfRef;
//首尾位置 //首尾位置
private float _UnitStartPointXPos; private float _UnitStartPointXPos;
private float _UnitStartPointYPos; private float _UnitStartPointYPos;
@ -15,8 +16,8 @@ public class DataFlowUnit : DataFlowController
//起始时间 //起始时间
private float _UnitStartTime; private float _UnitStartTime;
private float _UnitEndTime; private float _UnitEndTime;
//SongInformationContainer _songInformation; SongInformationContainer _songInformation;
//BPMGroup _BPMGroup; BPMGroup _BPMGroup;
/// <summary> /// <summary>
/// 现在时间与结束点时间的差值 /// 现在时间与结束点时间的差值
@ -141,12 +142,19 @@ public class DataFlowUnit : DataFlowController
private Vector3[] _vertex = new Vector3[24]; private Vector3[] _vertex = new Vector3[24];
private float _unitWidth = 0.4f; private float _unitWidth = 0.4f;
#endregion #endregion
public DataFlowUnitAnchorController _anchorController;
void Awake() void Awake()
{ {
_transform = gameObject.GetComponent<Transform>(); _transform = gameObject.GetComponent<Transform>();
_rendererMeshFilter = _transform.Find("Renderer").GetComponent<MeshFilter>(); _rendererMeshFilter = _transform.Find("Renderer").GetComponent<MeshFilter>();
_rendererTransform = _transform.Find("Renderer").GetComponent<Transform>(); _rendererTransform = _transform.Find("Renderer").GetComponent<Transform>();
_anchorPointTransform = _transform.Find("HeadAnchorPoint").GetComponent<Transform>(); _anchorPointTransform = _transform.Find("HeadAnchorPoint").GetComponent<Transform>();
//由于锚点是独立于物件存在的,所以需要额外设置脚本
_anchorController = _anchorPointTransform.gameObject.GetComponent<DataFlowUnitAnchorController>();
//将mesh标记为动态 //将mesh标记为动态
_rendererMeshFilter.mesh.MarkDynamic(); _rendererMeshFilter.mesh.MarkDynamic();
} }
@ -227,6 +235,9 @@ public class DataFlowUnit : DataFlowController
_anchorPointTransform.gameObject.SetActive(false); _anchorPointTransform.gameObject.SetActive(false);
_BPMGroup = timing; _BPMGroup = timing;
Debug.Log(SelfRef);
_anchorController.SetSelfRef(SelfRef);
} }
} }

View File

@ -0,0 +1,30 @@
using UnityEngine;
/// <summary>
/// 仅仅是给射线一个开盒蛇引用的机会,将会直接持有父类的数据,击中任意锚点都会获取到父类的数据
/// </summary>
public class DataFlowUnitAnchorController :MonoBehaviour, IRaycastHittable
{
RuntimeBaseNoteData SelfRef=null;
/// <summary>
/// 重写射线命中方法,确保能正确返回引用
/// </summary>
public RuntimeBaseNoteData OnHitByRay(RaycastHit hit)
{
// 如果自身没有 SelfRef尝试从父对象获取
if (SelfRef == null)
{
Debug.LogError($"当前对象没有数据");
}
Debug.Log($"DataFlow锚点被击中了\n自身引用为{SelfRef}\n碰撞点: {hit.point}, 法线: {hit.normal}\n");
return SelfRef;
}
/// <summary>
/// 用于设置数据项目
/// </summary>
public void SetSelfRef(RuntimeBaseNoteData data)
{
SelfRef = data;
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: a2100bdbe3afed446ab147d3cf7c0508 guid: a3d1b0613bc35c14a915a806b27b6cf5
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@ -1,13 +1,13 @@
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
public class NoteController : BaseNote public class TapController : BaseNote
{ {
private SpriteRenderer m_SpriteRenderer; private SpriteRenderer m_SpriteRenderer;
void Awake() void Awake()
{ {
_transform = gameObject.GetComponent<Transform>(); _transform = gameObject.GetComponent<Transform>();
_anchorPointTransform = _transform.Find("NoteAnchorPoint").GetComponent<Transform>(); _anchorPointTransform = _transform.Find("TapAnchorPoint").GetComponent<Transform>();
_rendererTransform = _transform.Find("NoteRenderer").GetComponent<Transform>(); _rendererTransform = _transform.Find("TapRenderer").GetComponent<Transform>();
//获取自身渲染器组件 //获取自身渲染器组件
m_SpriteRenderer = _anchorPointTransform.GetComponent<SpriteRenderer>(); m_SpriteRenderer = _anchorPointTransform.GetComponent<SpriteRenderer>();
} }
@ -36,3 +36,4 @@ public class NoteController : BaseNote
_BPMGroup = timing; _BPMGroup = timing;
} }
} }

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f055fb95e30ebde45b74584656d8d3d8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,18 +1,28 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using UnityEngine.UI;
public class LeftPanelView : MonoBehaviour public class LeftPanelView : MonoBehaviour
{ {
// Start is called before the first frame update public Transform _Transform;
void Start()
{
}
// Update is called once per frame public Button BPMList { get; private set; }
void Update() public Button DesignCheck { get; private set; }
public Button Mesh { get; private set; }
public Button Crosshair { get; private set; }
public Button Folder { get; private set; }
public Button Setting { get; private set; }
public Button Audio { get; private set; }
public Button ChartSetting { get; private set; }
private void Awake()
{ {
_Transform = gameObject.GetComponent<Transform>();
BPMList = _Transform.Find("BPMList").GetComponent<Button>();
DesignCheck = _Transform.Find("DesignCheck").GetComponent<Button>();
Mesh = _Transform.Find("Mesh").GetComponent<Button>();
Crosshair = _Transform.Find("Crosshair").GetComponent<Button>();
Folder = _Transform.Find("Folder").GetComponent<Button>();
Setting = _Transform.Find("Setting").GetComponent<Button>();
Audio = _Transform.Find("Audio").GetComponent<Button>();
ChartSetting = _Transform.Find("ChartSetting").GetComponent<Button>();
} }
} }

View File

@ -3,17 +3,28 @@ using System.IO;
using System; using System;
using SFB; using SFB;
using System.Collections; using System.Collections;
using Ookii.Dialogs;
public enum GeneralOptionPanelEvent using UnityEditor.Experimental.GraphView;
{ using System.Collections.Generic;
MouseGudies, BuildingModel, EditModel using System.Linq;
} using static System.Windows.Forms.VisualStyles.VisualStyleElement;
/// <summary> /// <summary>
/// 用于持续检测用户的鼠标输入并且做出对应UI的响应,这是一个测试中的脚本,之后需要重构 /// 用于持续检测用户的鼠标输入并且做出对应UI的响应,这是一个测试中的脚本,之后需要重构
/// </summary> /// </summary>
public class MainMenuController : MonoBehaviour public class MainMenuController : MonoBehaviour
{ {
enum GeneralOptionPanelEvent
{
MouseGuides, BuildingModel, EditModel
}
enum EditOperation
{
}
Coroutine _runningCoroutine;
private Transform _Transform; private Transform _Transform;
private MainMenuView _MainMenuView; private MainMenuView _MainMenuView;
private MainMenuModel _MainMenuModel; private MainMenuModel _MainMenuModel;
@ -44,7 +55,14 @@ public class MainMenuController : MonoBehaviour
/// 当歌曲时间发生变化事触发该事件,传入的时间为改变后的时间,更新之后的UI /// 当歌曲时间发生变化事触发该事件,传入的时间为改变后的时间,更新之后的UI
/// </summary> /// </summary>
private event Action<float> OnTimeChange; private event Action<float> OnTimeChange;
/// <summary>
/// 当用户有编辑操作的时候触发这个事件
/// </summary>
private event EventHandler EditCommand;
/// <summary>
/// 需要修改提示栏可以触发这个事件
/// </summary>
private event EventHandler ChangePromptBar;
#region Unity生命周期函数 #region Unity生命周期函数
void Start() void Start()
@ -60,16 +78,20 @@ public class MainMenuController : MonoBehaviour
//初始化各个界面 //初始化各个界面
InitTopPenal(); InitTopPenal();
InitLeftPenal();
InitProgressBar(); InitProgressBar();
InitAllOptionPanel(); InitAllOptionPanel();
//这里初始化选择器的视图
_SelectView = _MainMenuView.NotePool.Get(_MainMenuView.MainMenuSelectView); _SelectView = _MainMenuView.NotePool.Get(_MainMenuView.MainMenuSelectView);
_SelectView.Init(0, _SongTimeContainer, _MainMenuModel.MainBPMGroup); _SelectView.Init(0, _SongTimeContainer, _MainMenuModel.MainBPMGroup);
//注册事件 //注册时间变化事件
OnTimeChange += _MainMenuView.TopPanel.ChangeTimeText; OnTimeChange += _MainMenuView.TopPanel.ChangeTimeText;
OnTimeChange += ChangeProgressBar; OnTimeChange += ChangeProgressBar;
//注册命令事件
EditCommand += DeleteNote;
//注册物件更新事件
OnCurrentDataUpdate += UpdateNoteDataWindow; OnCurrentDataUpdate += UpdateNoteDataWindow;
} }
void Update() void Update()
@ -79,6 +101,7 @@ public class MainMenuController : MonoBehaviour
//在数据层更新当前的歌曲时间 //在数据层更新当前的歌曲时间
_SongTimeContainer.UpdateSongInformation(_MainMenuModel.SongCurrentTime); _SongTimeContainer.UpdateSongInformation(_MainMenuModel.SongCurrentTime);
UpdateNoteView(_MainMenuModel.SongCurrentTime, _MainMenuModel.SongCurrentTime+ _MainMenuModel.EndOffset);
//检查当前输入 //检查当前输入
CheckUserInput(); CheckUserInput();
} }
@ -89,7 +112,14 @@ public class MainMenuController : MonoBehaviour
/// </summary> /// </summary>
private void ChangeTimeWhitMouseScroll(float value) private void ChangeTimeWhitMouseScroll(float value)
{ {
_MainMenuModel.SongCurrentTime += value * _MainMenuModel.MainBPMGroup.Beat / 4; //改变歌曲的进度,改变的量为一拍的4分之一,只在歌曲时间内才能改变
if (_MainMenuModel.SongCurrentTime + value * _MainMenuModel.MainBPMGroup.Beat / 4>=0 &&
_MainMenuModel.SongCurrentTime + value * _MainMenuModel.MainBPMGroup.Beat / 4 <= _MainMenuModel.SongDuration)
{
_MainMenuModel.SongCurrentTime += value * _MainMenuModel.MainBPMGroup.Beat / 4;
}
if (value == 0) return; if (value == 0) return;
OnTimeChange?.Invoke(_MainMenuModel.SongCurrentTime); OnTimeChange?.Invoke(_MainMenuModel.SongCurrentTime);
} }
@ -118,7 +148,21 @@ public class MainMenuController : MonoBehaviour
_MainMenuView.TopPanel.PlaySongButton.onClick.AddListener(OnPlaySongButtonClick); _MainMenuView.TopPanel.PlaySongButton.onClick.AddListener(OnPlaySongButtonClick);
_MainMenuView.TopPanel.StopSongButton.onClick.AddListener(OnStopSongButtonClick); _MainMenuView.TopPanel.StopSongButton.onClick.AddListener(OnStopSongButtonClick);
} }
Coroutine _runningCoroutine; private void InitLeftPenal()
{
_MainMenuView.LeftPanel.BPMList.onClick.AddListener(() => { });
_MainMenuView.LeftPanel.DesignCheck.onClick.AddListener(() => { });
_MainMenuView.LeftPanel.Mesh.onClick.AddListener(() => { });
_MainMenuView.LeftPanel.Crosshair.onClick.AddListener(() => { });
_MainMenuView.LeftPanel.Folder.onClick.AddListener(() =>
{
//文件夹处理,Json导入,Json导出
ReadFile();
});
_MainMenuView.LeftPanel.Setting.onClick.AddListener(() => { });
_MainMenuView.LeftPanel.Audio.onClick.AddListener(() => { });
_MainMenuView.LeftPanel.ChartSetting.onClick.AddListener(() => { });
}
/// <summary> /// <summary>
/// 开始播放按钮绑定的方法 /// 开始播放按钮绑定的方法
/// </summary> /// </summary>
@ -214,6 +258,7 @@ public class MainMenuController : MonoBehaviour
OnTimeChange?.Invoke(_MainMenuModel.SongCurrentTime); OnTimeChange?.Invoke(_MainMenuModel.SongCurrentTime);
} }
#endregion #endregion
#region
/// <summary> /// <summary>
/// 监听用户的输入 /// 监听用户的输入
/// </summary> /// </summary>
@ -254,11 +299,21 @@ public class MainMenuController : MonoBehaviour
CloseBuildingOptionPanel(); CloseBuildingOptionPanel();
}//使用ESC退出建造模式 }//使用ESC退出建造模式
} }
if (Input.GetKeyDown(KeyCode.Delete))
{
EditCommand?.Invoke(this, null);
}
if (Input.GetKeyDown(KeyCode.I))
{
InitProjectOnChart();
}
if (Input.GetKeyDown(KeyCode.F)) if (Input.GetKeyDown(KeyCode.F))
{ {
ReadFile(); ReadFile();
} }
} }
#endregion
#region #region
/// <summary> /// <summary>
/// 文件写入操作 /// 文件写入操作
@ -283,14 +338,26 @@ public class MainMenuController : MonoBehaviour
CloseGeneralOptionPanel(); CloseGeneralOptionPanel();
} }
/// <summary> /// <summary>
/// 选择谱面文件,读取 /// 选择谱面文件,读取,该操作在成功读取文件之后将会覆盖当前的数据
/// </summary> /// </summary>
private void ReadFile() private void ReadFile()
{ {
string[] filePath = StandaloneFileBrowser.OpenFolderPanel("选择文件夹", Application.persistentDataPath, false); //StandaloneFileBrowser.OpenFolderPanel("选择文件夹", Application.persistentDataPath, false);
string[] filePath = StandaloneFileBrowser.OpenFilePanel("选择文件夹", Application.persistentDataPath, "json", false);
if (filePath == null) return;
_MainMenuView.TopPanel.StatusBar.text = filePath[0];
();
/*
* ,,
*
*/
try try
{ {
_MainMenuModel.ReadChartByPath(filePath[0] + "\\Chart.json"); _MainMenuModel.ReadChartByPath(filePath[0]);
} }
catch (System.NullReferenceException e) catch (System.NullReferenceException e)
{ {
@ -303,18 +370,112 @@ public class MainMenuController : MonoBehaviour
return; return;
} }
} }
/// <summary>
/// 清除当前的所有数据,核爆运行时数据,所有的东西都需要写一个自毁按钮,这是创造者的浪漫
/// </summary>
private void ()
{
//核爆视图数据
_MainMenuView.NotePool.ClearPool();
//核爆运行时数据库
_MainMenuModel.ClearRunTimeData();
}
/// <summary>
/// 从当前的持久化数据中重新读取数据,目前拿的还是默认的时间组,需要修改迭代
/// </summary>
private void InitProjectOnChart()
{
foreach (var item in _MainMenuModel.PersistentChartData.noteList)
{
//运行时数据
var selfRef = _MainMenuModel.CreateNewTapDataItem(
item.targetTime,
item.x,
item.y,
item.timingGroup
);
//视觉对象初始化
var Go = _MainMenuView.NotePool.Get(_MainMenuView.TapPrefab);
Go.Init(
new Vector2(
item.x,
item.y),
item.targetTime,
_SongTimeContainer,
_MainMenuModel.MainBPMGroup);
//设置视觉对象指针
Go.SelfRef = selfRef;
}
foreach (var item in _MainMenuModel.PersistentChartData.dragList)
{
//运行时数据
var selfRef = _MainMenuModel.CreateNewDragDataItem(
item.targetTime,
item.x,
item.y,
item.timingGroup
);
//视觉对象初始化
var Go = _MainMenuView.NotePool.Get(_MainMenuView.DragPrefab);
Go.Init(
new Vector2(
item.x,
item.y),
item.targetTime,
_SongTimeContainer,
_MainMenuModel.MainBPMGroup);
//设置视觉对象指针
Go.SelfRef = selfRef;
}
foreach (var item in _MainMenuModel.PersistentChartData.flickList)
{
//运行时数据
var selfRef = _MainMenuModel.CreateNewFlickDataItem(
item.targetTime,
item.x,
item.y,
item.timingGroup,
item.direction
);
//视觉对象初始化
var Go = _MainMenuView.NotePool.Get(_MainMenuView.FlickPrefab);
Go.Init(
new Vector2(
item.x,
item.y),
item.targetTime,
_SongTimeContainer,
item.direction,
_MainMenuView.FlickSpritePairs,
_MainMenuModel.MainBPMGroup
);
//设置视觉对象指针
Go.SelfRef = selfRef;
}
foreach (var item in _MainMenuModel.PersistentChartData.dataFlowList)
{
var data = _MainMenuModel.CreateNewSnakeDataItem(
item.startTime,
item.startX,
item.startY,
item.endX,
item.endY,
item.endTime,
item.timingGroup,
item.type
);
}
}
#endregion #endregion
#region #region
/// <summary> /// <summary>
/// 创建新的note实例的函数 /// 创建新的note实例的函数
/// </summary> /// </summary>
private void CreateNewNote(Vector3 mouseWorldPos, NoteController note, int timingGroup) private void CreateNewNote(Vector3 mouseWorldPos, TapController note, int timingGroup)
{ {
_MainMenuView.TopPanel.StatusBar.text = "已创建 " + note.gameObject.name; _MainMenuView.TopPanel.StatusBar.text = "已创建 " + note.gameObject.name;
var selfRef = _MainMenuModel.CreateNewNoteDataItem(_MainMenuModel.SongCurrentTime, mouseWorldPos.x, mouseWorldPos.y, timingGroup); var selfRef = _MainMenuModel.CreateNewTapDataItem(_MainMenuModel.SongCurrentTime, mouseWorldPos.x, mouseWorldPos.y, timingGroup);
var Go = _MainMenuView.NotePool.Get(note); var Go = _MainMenuView.NotePool.Get(note);
Go.Init( Go.Init(
@ -420,6 +581,9 @@ public class MainMenuController : MonoBehaviour
Go.SelfRef = selfRef; Go.SelfRef = selfRef;
} }
/// <summary>
/// 创建蛇实例的函数
/// </summary>
private IEnumerator CreateNewDataFlow(Vector3 mouseWorldPos, DataFlowController dataFlow, int timingGroup) private IEnumerator CreateNewDataFlow(Vector3 mouseWorldPos, DataFlowController dataFlow, int timingGroup)
{ {
ReferencePointLocation reference = ReferencePointLocation.Near; ReferencePointLocation reference = ReferencePointLocation.Near;
@ -515,8 +679,9 @@ public class MainMenuController : MonoBehaviour
endTime, endTime,
timingGroup, timingGroup,
reference); reference);
var Go = _MainMenuView.NotePool.Get(dataFlow); var Go = _MainMenuView.NotePool.Get(dataFlow);
//注意,一定要在设置自身数据之后再进行初始化,不然子类会全部找不到自己的数据
Go.SelfRef = selfRef;
Go.Init( Go.Init(
mouseWorldPos, mouseWorldPos,
currentMousePos, currentMousePos,
@ -528,7 +693,7 @@ public class MainMenuController : MonoBehaviour
reference reference
); );
Go.SelfRef = selfRef;
_MainMenuView.TopPanel.StatusBar.text = "开始位置:" + mouseWorldPos.ToString() + " 时间:" + startTime + " 结束位置:" + currentMousePos.ToString() + " 时间:" + endTime; _MainMenuView.TopPanel.StatusBar.text = "开始位置:" + mouseWorldPos.ToString() + " 时间:" + startTime + " 结束位置:" + currentMousePos.ToString() + " 时间:" + endTime;
} }
/// <summary> /// <summary>
@ -541,11 +706,11 @@ public class MainMenuController : MonoBehaviour
//处于创造模式下,单击左键将会创造预备创造的物件 //处于创造模式下,单击左键将会创造预备创造的物件
switch (preGeneratedObject) switch (preGeneratedObject)
{ {
case NoteController: case TapController:
{ {
CreateNewNote( CreateNewNote(
Camera.main.ScreenToWorldPoint(new Vector3(mousePos.x, mousePos.y, 8)), Camera.main.ScreenToWorldPoint(new Vector3(mousePos.x, mousePos.y, 8)),
_MainMenuView.NotePrefab, _MainMenuView.TapPrefab,
_MainMenuModel.MainBPMGroup.GroupNum); _MainMenuModel.MainBPMGroup.GroupNum);
break; break;
} }
@ -589,7 +754,7 @@ public class MainMenuController : MonoBehaviour
} }
} }
#endregion #endregion
#region #region
/// <summary> /// <summary>
/// 初始化所有右键会话窗口 /// 初始化所有右键会话窗口
/// </summary> /// </summary>
@ -621,7 +786,7 @@ public class MainMenuController : MonoBehaviour
/// </summary> /// </summary>
void InitBuildingOptionPanel() void InitBuildingOptionPanel()
{ {
BuildingOptionPanel.NoteButton.onClick.AddListener(() => OnBuildingModelButtonClick(BuildingOptionPanel.NoteButton.gameObject, _MainMenuView.NotePrefab)); BuildingOptionPanel.NoteButton.onClick.AddListener(() => OnBuildingModelButtonClick(BuildingOptionPanel.NoteButton.gameObject, _MainMenuView.TapPrefab));
BuildingOptionPanel.DragButton.onClick.AddListener(() => OnBuildingModelButtonClick(BuildingOptionPanel.DragButton.gameObject, _MainMenuView.DragPrefab)); BuildingOptionPanel.DragButton.onClick.AddListener(() => OnBuildingModelButtonClick(BuildingOptionPanel.DragButton.gameObject, _MainMenuView.DragPrefab));
BuildingOptionPanel.FlickButton.onClick.AddListener(() => OnBuildingModelButtonClick(BuildingOptionPanel.FlickButton.gameObject, _MainMenuView.FlickPrefab)); BuildingOptionPanel.FlickButton.onClick.AddListener(() => OnBuildingModelButtonClick(BuildingOptionPanel.FlickButton.gameObject, _MainMenuView.FlickPrefab));
BuildingOptionPanel.DataFlowButton.onClick.AddListener(() => OnBuildingModelButtonClick(BuildingOptionPanel.DataFlowButton.gameObject, _MainMenuView.DataFlowPrefab)); BuildingOptionPanel.DataFlowButton.onClick.AddListener(() => OnBuildingModelButtonClick(BuildingOptionPanel.DataFlowButton.gameObject, _MainMenuView.DataFlowPrefab));
@ -714,7 +879,7 @@ public class MainMenuController : MonoBehaviour
} }
} }
#endregion #endregion
#region #region
/* /*
* *
* 1.线 * 1.线
@ -743,7 +908,7 @@ public class MainMenuController : MonoBehaviour
Debug.DrawLine(ray.origin, hit.point, Color.green, 0.4f); Debug.DrawLine(ray.origin, hit.point, Color.green, 0.4f);
// 在碰撞点绘制一个小球 // 在碰撞点绘制一个小球
Debug.DrawRay(hit.point, hit.normal, Color.blue, 0.4f); Debug.DrawRay(hit.point, hit.normal, Color.blue, 0.4f);
Debug.Log("击中了:"+hit.collider.gameObject.name); Debug.Log("主控制器击中了:" + hit.collider.gameObject.name);
//这里触发一下更新事件 //这里触发一下更新事件
OnCurrentDataUpdate?.Invoke(GetNoteDataByRay(hit)); OnCurrentDataUpdate?.Invoke(GetNoteDataByRay(hit));
} }
@ -770,13 +935,37 @@ public class MainMenuController : MonoBehaviour
/// </summary> /// </summary>
public void UpdateNoteDataWindow(RuntimeBaseNoteData data) public void UpdateNoteDataWindow(RuntimeBaseNoteData data)
{ {
if(data!= currentData) if (data != currentData)
{ {
Debug.Log("已经替换了目前的数据"); Debug.Log("已经替换了目前的数据");
currentData = data; currentData = data;
_MainMenuView.NoteEditWindows.UpdateWindowData(currentData); _MainMenuView.NoteEditWindows.UpdateWindowData(currentData);
} }
} }
/// <summary>
/// 删除当前选择的物件
/// </summary>
public void DeleteNote(object sender, EventArgs e)
{
if (currentData == null) { _MainMenuView.TopPanel.StatusBar.text = "目前没有可以删除的Note (´;ω;`)"; }
var note = _MainMenuView.NotePool.GetNoteByRuntimeData(currentData);
if (note == null)
{
UnityEngine.Debug.LogError(this.name + ":查找结果为Null,请检查逻辑");
return;
}
_MainMenuView.NotePool.Release(note);
if (!_MainMenuModel.DeleteRuntimeDataItem(currentData))
{
UnityEngine.Debug.LogError(this.name + ":数据项目没有删除成功,请检查逻辑");
}
}
#endregion #endregion
#region #region
//储存当前查找到的数据引用,之后将作为查找的依据 //储存当前查找到的数据引用,之后将作为查找的依据
@ -784,4 +973,155 @@ public class MainMenuController : MonoBehaviour
//当属性面板里面的数据发生修改时,用预先存储的数据去查找 //当属性面板里面的数据发生修改时,用预先存储的数据去查找
//修改好数据之后,用新数据更新预先存储的数据,将成为新的查找依据 //修改好数据之后,用新数据更新预先存储的数据,将成为新的查找依据
#endregion #endregion
#region
/*
*
* :
* ,,
* :,
*
* ,,
*/
/// <summary>
/// 这是上一帧已经渲染出来的数据集
/// </summary>
SortedSet<RuntimeBaseNoteData> previousFrameSet= new SortedSet<RuntimeBaseNoteData>();
/// <summary>
/// 更新所有Note视图
/// </summary>
public void UpdateNoteView(float startTime, float endTime)
{
var currentFrameSet = _MainMenuModel.SearchRange(startTime, endTime);
if (currentFrameSet == null || previousFrameSet==null)
{
UnityEngine.Debug.Log(this.name+":查询出来的结果为空");
return;
}
//获得一个需要删除的视图对象的列表
var delete = previousFrameSet.Except(currentFrameSet);
//获得一个需要创建的视图对象的列表
var create = currentFrameSet.Except(previousFrameSet);
Debug.Log($"开始时间为:{startTime}\n,"
+$"结束时间为:{endTime}\n"
+$"删除列表有{delete.Count()}数据,待创建列表有{create.Count()}个数据"
);
if (delete != null)
{
foreach (var NeedDeleteData in delete)
{
var temp = _MainMenuView.NotePool.GetNoteByRuntimeData(NeedDeleteData);
_MainMenuView.NotePool.Release(temp);
}
}
if (create != null)
{
foreach (var NeedCreateData in create)
{
CreateNewViewWithRunTimeData(NeedCreateData);
}
}
previousFrameSet = currentFrameSet;
}
/// <summary>
/// 依据运行时数据创建新的视图对象
/// </summary>
private BaseNote CreateNewViewWithRunTimeData(RuntimeBaseNoteData baseNoteData)
{
if (baseNoteData == null)
{
return null;
}
BaseNote baseNote = null;
switch (baseNoteData)
{
case RuntimeTapData:
{
var tap = baseNoteData as RuntimeTapData;
var note = _MainMenuView.NotePool.Get(_MainMenuView.TapPrefab);
note.SelfRef = tap;
note.Init(
new Vector2(
tap.xPos,
tap.yPos),
tap.targetTime,
_SongTimeContainer,
_MainMenuModel.MainBPMGroup
);
break;
}
case RuntimeDragData:
{
var drag = baseNoteData as RuntimeDragData;
var note = _MainMenuView.NotePool.Get(_MainMenuView.DragPrefab);
note.SelfRef = drag;
note.Init(
new Vector2(
drag.xPos,
drag.yPos),
drag.targetTime,
_SongTimeContainer,
_MainMenuModel.MainBPMGroup
);
break;
}
case RuntimeFlickData:
{
var flick = baseNoteData as RuntimeFlickData;
var note = _MainMenuView.NotePool.Get( _MainMenuView.FlickPrefab);
note.SelfRef = flick;
note.Init(
new Vector2(flick.xPos, flick.yPos),
flick.targetTime,
_SongTimeContainer,
_MainMenuView.FlickSpritePairs,
_MainMenuModel.MainBPMGroup
);
break;
}
case RuntimeSnakeData:
{
var slider = baseNoteData as RuntimeSnakeData;
var note = _MainMenuView.NotePool.Get(_MainMenuView.DataFlowPrefab);
note.SelfRef = slider;
note.Init(
new Vector2(slider.xPos ,slider.yPos),
new Vector2 (slider.endXPos,slider.endYPos),
slider .targetTime,
slider.endTime,
0.4f,
_SongTimeContainer,
_MainMenuModel.MainBPMGroup,
slider.referencePoint
);
break;
}
}
return baseNote;
}
#endregion
}
public class StringEventArgs : EventArgs
{
public string Message { get; set; }
public StringEventArgs(string message)
{
Message = message;
}
} }

View File

@ -13,6 +13,26 @@ public class MainMenuModel : MonoBehaviour
readonly private float DefaultNoteStream = 5f; readonly private float DefaultNoteStream = 5f;
readonly private float DefaultBPM = 128; readonly private float DefaultBPM = 128;
readonly private float DefaultBaseBPM = 128; readonly private float DefaultBaseBPM = 128;
private float BaseSpeed = 25;
private float TrackLength = 125;
private float NoteStream = 5f;
private float BPM = 128;
private float BaseBPM = 128;
/// <summary>
/// 到达零平面需要的时间,通过轨道长度除以音符流速与基准速度的积获得
/// </summary>
public float EndOffset
{
get
{
return TrackLength / (NoteStream * BaseSpeed);
}
}
/// <summary> /// <summary>
/// 存储所有拍线的时间,在加载BPM组的时候就需要初始化完成 /// 存储所有拍线的时间,在加载BPM组的时候就需要初始化完成
/// </summary> /// </summary>
@ -31,10 +51,25 @@ public class MainMenuModel : MonoBehaviour
return BPMGroupManager.QueryBPMGroup(0); return BPMGroupManager.QueryBPMGroup(0);
} }
} }
/// <summary>
/// 用于持久化的数据的谱面对象
/// </summary>
public Chart PersistentChartData { set; get; } public Chart PersistentChartData { set; get; }
/// <summary>
/// 用于管理BPM对象的数据模块
/// </summary>
public BPMGroupModel BPMGroupManager { set; get; } public BPMGroupModel BPMGroupManager { set; get; }
/// <summary>
/// 用于管理所有谱面运行时数据的数据模块
/// </summary>
public ChartRuntimeModel ChartRuntimeDataManager { set; get; } public ChartRuntimeModel ChartRuntimeDataManager { set; get; }
/// <summary>
/// 歌
/// </summary>
public AudioSource Song { set; get; } public AudioSource Song { set; get; }
/// <summary>
/// 当前歌曲时间,单位是秒
/// </summary>
public float SongCurrentTime public float SongCurrentTime
{ {
get get
@ -47,9 +82,20 @@ public class MainMenuModel : MonoBehaviour
Song.time = value; Song.time = value;
} }
} }
/// <summary>
/// 歌曲长度,单位:秒
/// </summary>
public float SongDuration
{
get
{
return Song.clip.length;
}
}
#region
private void Awake() private void Awake()
{ {
//Awake是程序的入口
Song = gameObject.GetComponent<AudioSource>(); Song = gameObject.GetComponent<AudioSource>();
InitMainMenuModel(); InitMainMenuModel();
} }
@ -70,109 +116,6 @@ public class MainMenuModel : MonoBehaviour
//初始化新项目的结构 //初始化新项目的结构
NewProjectData(); NewProjectData();
} }
/// <summary>
/// 依据时间更新所有BPM组的状态,将这个方法注册在控制层的时间变化事件中
/// </summary>
public void UpdateBPMGroup(float currentTime)
{
BPMGroupManager.UpdateBPMGroup(currentTime);
}
/// <summary>
/// 向管理器申请创建新的数据项,返回创建结果
/// </summary>
public bool CreateBPMDataItem(int groupNum, float startTime, float currentBPM)
{
BPMGroupManager.CreateNewBPMGroup(groupNum, startTime, currentBPM);
return BPMGroupManager.QueryBPMGroupDataItem(groupNum, startTime, currentBPM);
}
/// <summary>
/// 向管理器申请删除指定的数据项,返回删除结果
/// </summary>
public bool DeleteBPMDataItem(int groupNum, float startTime, float currentBPM)
{
BPMGroupManager.DeleteBPMGroup(groupNum, startTime);
return !BPMGroupManager.QueryBPMGroupDataItem(groupNum, startTime, currentBPM);
}
/// <summary>
/// 这里会返回一个包含当前所有BPM数据项的集合用于让C层持有数据库的备份,之后只能通过开发的接口更改数据,C层本身并不能直接访问BPM管理器
/// </summary>
public List<(int GroupNum, float startTime, float currentBPM)> GetAllBPMDataItem()
{
return BPMGroupManager.GetAllBPMDataItem();
}
/// <summary>
/// 更新所有的玩家设置
/// </summary>
public void UpdatePlayerSetting(float noteStream, float baseSpeed, float baseBPM, float trackLength)
{
BPMGroupManager.UpdatePlayerSetting(noteStream, baseSpeed, baseBPM, trackLength);
PersistentChartData.globalConfig.baseBPM = baseBPM;
PersistentChartData.globalConfig.baseSpeed = baseSpeed;
PersistentChartData.globalConfig.trackLength = trackLength;
PersistentChartData.globalConfig.noteStream = noteStream;
}
/// <summary>
/// 删除指定的数据项,返回删除的情况
/// </summary>
public bool DeleteNoteDataItem(RuntimeBaseNoteData obj)
{
ChartRuntimeDataManager.DeleteDataItem(obj);
if (ChartRuntimeDataManager.GetDataItem(obj) == null)
{
return true;
}
return false;
}
public RuntimeNoteData CreateNewNoteDataItem(float targetTime, float xPos, float yPos, int num)
{
var go = BPMGroupManager.QueryBPMGroup(num);
if (go == null) return null;
var item = new RuntimeNoteData(targetTime, xPos, yPos, go);
ChartRuntimeDataManager.AddDataItem(item);
return item;
}
public RuntimeDragData CreateNewDragDataItem(float targetTime, float xPos, float yPos, int num)
{
var go = BPMGroupManager.QueryBPMGroup(num);
if (go == null) return null;
var item = new RuntimeDragData(targetTime, xPos, yPos, go);
ChartRuntimeDataManager.AddDataItem(item);
return item;
}
public RuntimeFlickData CreateNewFlickDataItem(float targetTime, float xPos, float yPos, int num, FlickDirection direction)
{
var go = BPMGroupManager.QueryBPMGroup(num);
if (go == null) return null;
var item = new RuntimeFlickData(targetTime, xPos, yPos, direction, go);
ChartRuntimeDataManager.AddDataItem(item);
return item;
}
public RuntimeSnakeData CreateNewSnakeDataItem(float targetTime, float xPos, float yPos, float endXPos, float endYPos, float endTime, int num, ReferencePointLocation referencePoint)
{
var go = BPMGroupManager.QueryBPMGroup(num);
if (go == null) return null;
var item = new RuntimeSnakeData(targetTime, xPos, yPos, endXPos, endYPos, endTime, referencePoint, go);
ChartRuntimeDataManager.AddDataItem(item);
return item;
}
/// <summary>
/// 导出运行时模型与BPM管理模型中的数据项至持久化数据结构中
/// </summary>
public void UpdateChartData()
{
ChartRuntimeDataManager.GetChartData(PersistentChartData);
//导出BPM数据
var bpmList = BPMGroupManager.GetDataObject();
PersistentChartData.BPMList = bpmList;
}
private void NewProjectData() private void NewProjectData()
{ {
//创建默认BPM组,编号为零 //创建默认BPM组,编号为零
@ -204,6 +147,126 @@ public class MainMenuModel : MonoBehaviour
PersistentChartData.META.chartDesigner = "Program Team"; PersistentChartData.META.chartDesigner = "Program Team";
PersistentChartData.META.illustrator = "天辞ちゃんBananApple"; PersistentChartData.META.illustrator = "天辞ちゃんBananApple";
} }
#endregion
#region BPM数据操作接口
/// <summary>
/// 依据时间更新所有BPM组的状态,将这个方法注册在控制层的时间变化事件中
/// </summary>
public void UpdateBPMGroup(float currentTime)
{
BPMGroupManager.UpdateBPMGroup(currentTime);
}
/// <summary>
/// 向管理器申请创建新的BPM数据项,返回创建结果
/// </summary>
public bool CreateBPMDataItem(int groupNum, float startTime, float currentBPM)
{
BPMGroupManager.CreateNewBPMGroup(groupNum, startTime, currentBPM);
return BPMGroupManager.QueryBPMGroupDataItem(groupNum, startTime, currentBPM);
}
/// <summary>
/// 向管理器申请删除指定的BPM数据项,返回删除结果
/// </summary>
public bool DeleteBPMDataItem(int groupNum, float startTime, float currentBPM)
{
BPMGroupManager.DeleteBPMGroup(groupNum, startTime);
return !BPMGroupManager.QueryBPMGroupDataItem(groupNum, startTime, currentBPM);
}
/// <summary>
/// 这里会返回一个包含当前所有BPM数据项的集合用于让C层持有数据库的备份,之后只能通过开发的接口更改数据,C层本身并不能直接访问BPM管理器
/// </summary>
public List<(int GroupNum, float startTime, float currentBPM)> GetAllBPMDataItem()
{
return BPMGroupManager.GetAllBPMDataItem();
}
/// <summary>
/// 更新所有BPM对象的玩家设置,
/// </summary>
public void UpdatePlayerSetting(float noteStream, float baseSpeed, float baseBPM, float trackLength)
{
BPMGroupManager.UpdatePlayerSetting(noteStream, baseSpeed, baseBPM, trackLength);
PersistentChartData.globalConfig.baseBPM = baseBPM;
PersistentChartData.globalConfig.baseSpeed = baseSpeed;
PersistentChartData.globalConfig.trackLength = trackLength;
PersistentChartData.globalConfig.noteStream = noteStream;
}
#endregion
#region
/// <summary>
/// 删除指定的数据项,返回删除的情况
/// </summary>
public bool DeleteRuntimeDataItem(RuntimeBaseNoteData obj)
{
ChartRuntimeDataManager.DeleteDataItem(obj);
if (ChartRuntimeDataManager.GetDataItem(obj) == null)
{
return true;
}
return false;
}
public RuntimeTapData CreateNewTapDataItem(float targetTime, float xPos, float yPos, int num)
{
var go = BPMGroupManager.QueryBPMGroup(num);
if (go == null) return null;
var item = new RuntimeTapData(targetTime, xPos, yPos, go);
ChartRuntimeDataManager.AddDataItem(item);
return item;
}
public RuntimeDragData CreateNewDragDataItem(float targetTime, float xPos, float yPos, int num)
{
var go = BPMGroupManager.QueryBPMGroup(num);
if (go == null) return null;
var item = new RuntimeDragData(targetTime, xPos, yPos, go);
ChartRuntimeDataManager.AddDataItem(item);
return item;
}
public RuntimeFlickData CreateNewFlickDataItem(float targetTime, float xPos, float yPos, int num, FlickDirection direction)
{
var go = BPMGroupManager.QueryBPMGroup(num);
if (go == null) return null;
var item = new RuntimeFlickData(targetTime, xPos, yPos, direction, go);
ChartRuntimeDataManager.AddDataItem(item);
return item;
}
public RuntimeSnakeData CreateNewSnakeDataItem(float targetTime, float xPos, float yPos, float endXPos, float endYPos, float endTime, int num, ReferencePointLocation referencePoint)
{
var go = BPMGroupManager.QueryBPMGroup(num);
if (go == null) return null;
var item = new RuntimeSnakeData(targetTime, xPos, yPos, endXPos, endYPos, endTime, referencePoint, go);
ChartRuntimeDataManager.AddDataItem(item);
return item;
}
/// <summary>
/// 输入搜索的开始与结束时间,返回符合条件的集合
/// </summary>
public SortedSet<RuntimeBaseNoteData> SearchRange(float startTime, float endTime)
{
var set =ChartRuntimeDataManager.SearchRange(startTime, endTime);
return set;
}
public void ClearRunTimeData()
{
ChartRuntimeDataManager.Clear();
}
#endregion
#region
/// <summary>
/// 导出运行时模型与BPM管理模型中的数据项至持久化数据结构中
/// </summary>
public void UpdateChartData()
{
ChartRuntimeDataManager.GetChartData(PersistentChartData);
//导出BPM数据
var bpmList = BPMGroupManager.GetDataObject();
PersistentChartData.BPMList = bpmList;
}
/// <summary> /// <summary>
/// 依据路径读取Chart文件,注意,读取新的文件将会覆盖当前工程 /// 依据路径读取Chart文件,注意,读取新的文件将会覆盖当前工程
/// </summary> /// </summary>
@ -211,9 +274,10 @@ public class MainMenuModel : MonoBehaviour
{ {
string json = File.ReadAllText(path); string json = File.ReadAllText(path);
PersistentChartData = JsonConvert.DeserializeObject<Chart>(json); PersistentChartData = JsonConvert.DeserializeObject<Chart>(json);
Debug.Log(PersistentChartData.ToString());
} }
/// <summary> /// <summary>
/// 将谱面文件序列化json字符串 /// 将谱面文件序列化Json字符串
/// </summary> /// </summary>
public string GetChartJson() public string GetChartJson()
{ {
@ -223,4 +287,6 @@ public class MainMenuModel : MonoBehaviour
print(jsonString); print(jsonString);
return jsonString; return jsonString;
} }
#endregion
} }

View File

@ -15,7 +15,7 @@ public class MainMenuView : MonoBehaviour
public NoteEditWindowsView NoteEditWindows { get; private set; } public NoteEditWindowsView NoteEditWindows { get; private set; }
//可游玩物体的预制件引用 //可游玩物体的预制件引用
public NoteController NotePrefab { get; private set; } public TapController TapPrefab { get; private set; }
public DragController DragPrefab { get; private set; } public DragController DragPrefab { get; private set; }
public FlickController FlickPrefab { get; private set; } public FlickController FlickPrefab { get; private set; }
public DataFlowController DataFlowPrefab { get; private set; } public DataFlowController DataFlowPrefab { get; private set; }
@ -34,7 +34,7 @@ public class MainMenuView : MonoBehaviour
{ {
_Transform = gameObject.GetComponent<Transform>(); _Transform = gameObject.GetComponent<Transform>();
LoadDirationSprites(); LoadDirectionSprites();
LoadPlayObjectViewPrefab(); LoadPlayObjectViewPrefab();
LoadDecorateObject(); LoadDecorateObject();
LoadRightClickDialogWindow(); LoadRightClickDialogWindow();
@ -57,7 +57,7 @@ public class MainMenuView : MonoBehaviour
/// </summary> /// </summary>
private void LoadPlayObjectViewPrefab() private void LoadPlayObjectViewPrefab()
{ {
NotePrefab = Resources.Load<NoteController>("NotePrefabs/note"); TapPrefab = Resources.Load<TapController>("NotePrefabs/Tap");
DragPrefab = Resources.Load<DragController>("NotePrefabs/Drag"); DragPrefab = Resources.Load<DragController>("NotePrefabs/Drag");
FlickPrefab = Resources.Load<FlickController>("NotePrefabs/Flick"); FlickPrefab = Resources.Load<FlickController>("NotePrefabs/Flick");
DataFlowPrefab = Resources.Load<DataFlowController>("NotePrefabs/DataFlow"); DataFlowPrefab = Resources.Load<DataFlowController>("NotePrefabs/DataFlow");
@ -67,7 +67,7 @@ public class MainMenuView : MonoBehaviour
/// <summary> /// <summary>
/// 用于加载FLick所有方向贴图 /// 用于加载FLick所有方向贴图
/// </summary> /// </summary>
private void LoadDirationSprites() private void LoadDirectionSprites()
{ {
FlickSpritePairs.Add(FlickDirection.Any, Resources.Load<Sprite>("NoteSprites/AllFlick/AllFlick_0")); FlickSpritePairs.Add(FlickDirection.Any, Resources.Load<Sprite>("NoteSprites/AllFlick/AllFlick_0"));
FlickSpritePairs.Add(FlickDirection.Up, Resources.Load<Sprite>("NoteSprites/AllFlick/AllFlick_1")); FlickSpritePairs.Add(FlickDirection.Up, Resources.Load<Sprite>("NoteSprites/AllFlick/AllFlick_1"));

View File

@ -56,16 +56,16 @@ public class NoteEditWindowsView : MonoBehaviour
/// </summary> /// </summary>
public void UpdateWindowData(RuntimeBaseNoteData data) public void UpdateWindowData(RuntimeBaseNoteData data)
{ {
Debug.Log("窗口编辑器中显示数据的类型为:"+data.GetType()); Debug.Log(this.name + ":窗口编辑器中显示数据的类型为:" + data.GetType());
switch (data) switch (data)
{ {
case RuntimeNoteData: case RuntimeTapData:
{ {
³õʼ»¯´°¿Ú(); ³õʼ»¯´°¿Ú();
Title.text = "Tap"; Title.text = "Tap";
Start_x.text=data.xPos.ToString(); Start_x.text = data.xPos.ToString();
Start_y.text=data.yPos.ToString(); Start_y.text = data.yPos.ToString();
TargetTime.text=data.targetTime.ToString(); TargetTime.text = data.targetTime.ToString();
break; break;
} }
case RuntimeDragData: case RuntimeDragData:
@ -122,14 +122,14 @@ public class NoteEditWindowsView : MonoBehaviour
} }
} }
private void ³õʼ»¯´°¿Ú() private void ³õʼ»¯´°¿Ú()
{ {
Title.text = "null"; Title.text = "null";
Start_x.text="null"; Start_x.text = "null";
Start_y.text= "null"; Start_y.text = "null";
TargetTime.text = "null"; TargetTime.text = "null";
End_x.text = "null"; End_x.text = "null";
End_y.text = "null"; End_y.text = "null";