HartoukChartEditor/Assets/Script/PlayObject/BaseNote.cs

175 lines
8.2 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 用于描述Note判定情况的委托
/// </summary>
public delegate void JudgeEventHandler(JugdeLevel level, Vector3 NotePos, BaseNote baseNote);
public delegate void ReturnPoolEventHandler(BaseNote note);
public enum JugdeLevel
{
Prefect, Great, Bad, Miss
};
/// <summary>
/// 游戏中所有物件的基类
/// </summary>
/// <remarks>
/// <para>
/// 在这里,所有基于这个类派生出来的子对象我们都称之为<paramref name="物件"/>
/// </para>
/// <para>
/// 它们都拥有<paramref name="被创建的时间"/>,以及<paramref name="被回收的时间"/>,因此,一个物件至少需要指定一个<paramref name="TargetTime"/>
/// 我们可以将装饰物件从这个类派生出来。并且添加<paramref name="IsDecorated"/>去标识那些物件是装饰,使得我们能每一个物件都受到时间组控制。
/// </para>
/// <para>
/// 所以一个每一个物件对象至少都含有一个时间组对象的引用。也许关卡设计者会需要一些装饰物件,装饰物件同样也符合之前物件的特点够更加方便的管理他们。
/// 我们有时还需要统计这些物件的数量,以便于我们去完成更加复杂的逻辑。
/// </para>
/// <para>
/// <term>因此每一个物件都应该拥有以下属性:</term>
/// <paramref name="TargetTime"/>,
/// <paramref name="ItemQuantity"/>,
/// <paramref name="IsValid"/>,
/// <paramref name="IsDecorated"/>
/// </para>
/// <para>
/// 对于物件的行为,可以分为几种情况
/// 一个是物件的运动,物件若是想要确定自己的位置,它就必须拥有歌曲当前的时间,还有当前的速度。
/// 一个是物件的判定,判定的过程需要判定的区间,判定的范围,判定的所需的手指使用情况,并且传递自身的坐标,判定结果
/// 最后是物件的回收,当一个物件完成了所有的未尽事宜之后,就会自己返回对象池。
/// </para>
/// </remarks>
public abstract class BaseNote : MonoBehaviour
{
/// <summary>
/// 用于存储自身在数据类的引用,用于检索,该字段仅在谱面编辑器中存在
/// </summary>
public RuntimeBaseNoteData SelfRef;
/// <summary>
/// 物件自身的Transform组件引用
/// </summary>
protected Transform _transform;
/// <summary>
/// 物件渲染层Transform引用
/// </summary>
protected Transform _rendererTransform;
/// <summary>
/// 物件定位标记的Transform引用
/// </summary>
protected Transform _anchorPointTransform;
/// <summary>
/// 目标时间,即一个物件生存周期的终点
/// </summary>
[SerializeField]
public float TargetTime { get; protected set; }
/// <summary>
/// 自身物件数,用于分数统计
/// </summary>
protected int ItemQuantity { get; set; }
/// <summary>
/// 当前Note是否已经失效,当被标记为失效是将移除出管理器的判定序列
/// </summary>
public bool IsValid { get; set; }
/// <summary>
/// 是否为装饰,勾选之后该物件将不会进入判定流程,它只在被实例化时决定
/// </summary>
public bool IsDecorated { get; set; }
/// <summary>
/// 歌曲必要信息的容器,提供歌曲时间
/// </summary>
public SongInformationContainer _songInformation { get; set; }
/// <summary>
/// 物件所属的BPM组
/// </summary>
public BPMGroup _BPMGroup { get; set; }
/// <summary>
/// 当游玩物件被判定时触发该事件
/// </summary>
public event JudgeEventHandler OnNoteJudged;
/// <summary>
/// 当物件在最后阶段触发,向对象池传递自身的引用
/// </summary>
public event ReturnPoolEventHandler OnNoteUesd;
/// <summary>
/// 基于当前时间计算该物件的渲染的位置
/// </summary>
protected virtual void UpdateRenderer(float currentTime, float noteSpeed)
{
/*
*
*
* - +
*
*
*
* 0f(currentTime)=NoteSpeed*(targetTime-currentTime)
*
*
* instantiateOffsetNoteSpeed
* 0
* (targetTime-currentTime)0
* 使
* 穿
*
*
*
*
* 使
*
* 使
*/
float z = (TargetTime - currentTime) * noteSpeed;
//使用世界坐标进行赋值
_transform.position = new Vector3(_transform.position.x, _transform.position.y, z);
}
protected virtual void UpdateAnchorPoint(float currentTime, float noteSpeed, float beatTime)
{
if (_anchorPointTransform.gameObject.activeSelf == true) return;
if (_rendererTransform.position.z > 800 * noteSpeed * 0.001) return;
_anchorPointTransform.gameObject.SetActive(true);
}
protected virtual void ThisObjectIsValid()
{
/*
*
* 便
*
*/
IsValid = true;
}
protected virtual void ReturnNoteToPool()
{
OnNoteUesd?.Invoke(this);
//因为在对象池回收时,存储在这些时间里面的函数并不会清空,需要手动清理
OnNoteJudged = null;
}
/// <summary>
/// 检查自身是否超过判定时间(子类可重写)
/// </summary>
protected virtual void CheckMiss(float CurrentTime, float missInterval)
{
if (CurrentTime < TargetTime + missInterval) return;
IsValid = true;
OnNoteJudged?.Invoke(JugdeLevel.Miss, _transform.position, this);
OnNoteUesd?.Invoke(this);
}
/// <summary>
/// 用于执行Note的判定
/// </summary>
public virtual void CheckHit(Dictionary<int, bool> isValidFingerID, Camera MainCamera)
{
OnNoteJudged?.Invoke(JugdeLevel.Prefect, _transform.position, this);
}
/// <summary>
/// 用于初始化游戏所需配置等
/// </summary>
public void InitConfigFile()
{
//像判定区间,还有游戏难度,关卡属性,可以放在这里初始化
}
}