NoteRenderContext
这一页是签名与行为参考。渲染期的轨道布局坐标与扩展数据。直接做一遍:教程 · 添加新音符类型。
音符渲染上下文,每帧 render 传入。坐标是未叠加轨道变换的布局(世界)坐标,而画布缝本身已带轨道变换——两者配合即"默认跟随轨道几何"。
方法速览
| 方法 | 用途 |
|---|---|
x() / y() | 音符中心坐标(世界坐标) |
width() | 轨道绘制宽度(像素) |
musicTimeMs() | 当前音乐时间(毫秒,用于动画) |
lane() | 音符所属轨道 |
isHoldEnd() | 是否为长音符结尾(宿主当前恒传 false) |
judgeLineY() | 当前轨道有效判定线 y |
scrollSpeed() | 滚动速度(像素/秒) |
endTime() | 长音符结束时间(非长音符 null) |
extensionData() | 运行时扩展数据只读透传 |
skinImage() | 解析好的音符皮肤图(实验性) |
x()
签名:
double x();行为:音符中心的 x 坐标(世界坐标,即轨道中心线;未叠加轨道旋转/缩放/裁剪变换)。
示例:
double cx = ctx.x();y()
签名:
double y();行为:音符中心的 y 坐标,已包含音乐时间偏移(即当前帧的下落位置);同样未叠加轨道变换。
示例:
double cy = ctx.y();width()
签名:
double width();行为:轨道绘制宽度(像素)。用它决定音符横向尺寸可自动适配不同轨道宽度。
示例:
double w = Math.min(ctx.width(), 48);musicTimeMs()
签名:
long musicTimeMs();行为:当前音乐时间(毫秒),用于逐帧动画(脉冲、闪烁等)。倒带重演窗口内非单调,纯视觉动画不受影响。
示例:
double pulse = 0.5 + 0.5 * Math.sin(ctx.musicTimeMs() / 180.0);lane()
签名:
int lane();行为:音符所属轨道索引(0-based),可用于按轨道做差异化绘制。
示例:
if (ctx.lane() % 2 == 0) { /* 偶数轨样式 */ }isHoldEnd()
签名:
boolean isHoldEnd();行为:声明"本次绘制的是否为长音符结尾"。宿主当前在音符渲染分派中恒传 false(长音符尾部由类型自己按 endTime() + scrollSpeed() 绘制),字段保留以兼容未来/其它宿主实现。
示例:
if (ctx.isHoldEnd()) { /* 理论上不会进入 */ }judgeLineY()
签名:
double judgeLineY();行为:当前轨道有效判定线的 y 坐标(世界坐标,已计入轨道高度/透视等有效值)。可直接用 judgeLineY() - y() 得到音符到判定线的剩余距离。
示例:
double remainPx = Math.max(0.0, ctx.judgeLineY() - ctx.y());scrollSpeed()
签名:
double scrollSpeed();行为:当前滚动速度(像素/秒),与全局流速、轨道流速倍率一致,满足 位移 = 时间差(ms) * scrollSpeed / 1000。用于把时间长度换算成画面长度(如长音符尾部)。
示例:
double pxPerMs = ctx.scrollSpeed() / 1000.0;
double tailPx = (ctx.endTime() == null ? 0 : 300) * pxPerMs; // 300ms 示例时长endTime()
签名:
Long endTime();行为:长音符结束时间(毫秒);非长音符为 null,绘制尾部前必须判空。
示例:
Long end = ctx.endTime();extensionData()
签名:
default Object extensionData();行为:NoteData.setExtensionData 写入值的只读透传;与判定回调经 NoteView.extensionData() 取到的是同一份数据。内置类型返回 null。默认返回 null。
示例:
AimState state = ctx.extensionData() instanceof AimState s ? s : null;skinImage()
签名:
default RenderImage skinImage();行为(源码标注为实验性):宿主为本类型解析好的皮肤图。解析链为「当前皮肤的本类型专属槽位(玩家皮肤优先)→ 定义的 defaultImage()」,两者都不可用返回 null,由模组自行绘制几何兜底。位置与方向由模组自定(宿主不会替你画)。默认返回 null。
示例:
RenderImage img = ctx.skinImage();
if (img != null) {
double w = ctx.width();
double h = w * img.height() / img.width();
canvas.drawImage(img, ctx.x() - w / 2, ctx.y() - h / 2, w, h);
}完整签名
public interface NoteRenderContext {
double x();
double y();
double width();
long musicTimeMs();
int lane();
boolean isHoldEnd();
double judgeLineY();
double scrollSpeed();
Long endTime();
default Object extensionData();
default RenderImage skinImage();
}线程:源码未声明额外线程约束;宿主在游玩渲染线程同步调用。
生命周期阶段:运行期每帧渲染回调内使用。
稳定性:2.0 起冻结:2.x 内只增不破(禁止删签名/改签名/改语义)。skinImage() 在源码中标注为实验性。