API 参考 / 只读视图、场景、音频与文本
组合用法示例
下面的示例只使用前文出现过的真实类型与方法:从 GameplayContext 读谱面信息与准度、用 TextField 做输入、经 SceneHost 打开/关闭模组场景、在结算覆盖渲染参数中读成绩快照与布局原语。示例为纯只读用法,不修改任何游戏状态。
java
package mymod.example;
import com.seecmd.mod.api.ModContext;
import com.seecmd.mod.api.capability.SceneHost;
import com.seecmd.mod.api.context.ChartView;
import com.seecmd.mod.api.context.GameplayContext;
import com.seecmd.mod.api.context.LaneView;
import com.seecmd.mod.api.context.NoteView;
import com.seecmd.mod.api.context.ResultLayout;
import com.seecmd.mod.api.context.ResultSnapshot;
import com.seecmd.mod.api.event.gameplay.ChartLoadEvent;
import com.seecmd.mod.api.render.RenderCanvas;
import com.seecmd.mod.api.scene.InputEvent;
import com.seecmd.mod.api.scene.InputType;
import com.seecmd.mod.api.scene.Scene;
import com.seecmd.mod.api.text.TextField;
import java.nio.file.Path;
import java.util.List;
/** 只读用法示例:谱面读取 + 准度读取 + 模组场景 + 文本输入。 */
public final class ReadOnlyExampleScene implements Scene {
private final TextField query = new TextField(32, false);
private String title = "";
private Path chartPath;
@Override
public String id() {
return "mymod:readonly-example";
}
@Override
public void onEnter() {
query.reset("");
query.reportImeAnchor(40, 652); // 自绘场景可手动上报;用 render 时会自动上报
}
@Override
public void update(double dt) {
// 逻辑更新放在这里,不要依赖 render 的调用频率
}
@Override
public void render(RenderCanvas canvas) {
// 标准输入框外观;focused = true 时组件自动上报 IME 锚点
query.render(canvas, 20, 320, 300, 32, true);
}
@Override
public boolean handleInput(InputEvent event) {
if (event.type() != InputType.KEY_PRESSED && event.type() != InputType.TEXT_INPUT) {
return false; // 其余事件类型组件一律不消费
}
return query.handleInput(event); // 仅把输入转发给聚焦组件
}
/** 谱面加载完成:读谱面元数据(不要缓存宿主返回的列表作为实时数据)。 */
public void onChartLoad(ChartLoadEvent event) {
GameplayContext ctx = event.context();
ChartView chart = ctx.chartView();
title = chart.title();
chartPath = chart.chartPath(); // 可能为 null,需判空
int bpm = chart.bpm();
int laneCount = chart.laneCount();
long durationMs = chart.durationMs();
NoteView next = ctx.nextNote(); // 比 pendingNotes() 轻量
List<LaneView> lanes = ctx.lanes(); // 快照列表,不要每帧取用
}
/** 判定后读取进度与准度(两种进度口径不可混用)。 */
public void onJudged(GameplayContext ctx) {
double byNotes = ctx.progress(); // 已判音符数 / 总音符数
double byMusic = ctx.musicPositionRatio(); // 音乐时间线位置
double acc = ctx.accuracy(); // 0-1,未判定不计入
int combo = ctx.combo(); // 当前连击
int best = ctx.maxCombo(); // 历史最大连击
int remaining = ctx.remainingNoteCount(); // total - judged
if (ctx.isRewinding()) {
// 倒带重演窗口内 musicTimeMs() 非单调,累积型状态需按 τ 重建
}
}
/** 结算界面覆盖渲染中可直接读取的快照与定位原语。 */
public void onResultFrame(ResultSnapshot snapshot, ResultLayout layout) {
double accPercent = snapshot.accuracy(); // 0-100,与结算界面口径一致
List<Integer> builtin = snapshot.builtinCounts(); // PERFECT/GREAT/MISS
int windowX = layout.windowX();
int canvasWidth = layout.canvasWidth();
}
/** 打开本场景(压入场景栈,当前场景挂起)。 */
public void open(ModContext mod) {
SceneHost host = mod.capabilities().get(SceneHost.class);
host.push(this);
String currentSceneId = host.current().id(); // 模组场景返回声明 id
}
/** 关闭本场景(弹出当前场景,返回上一个场景)。 */
public void close(ModContext mod) {
mod.capabilities().get(SceneHost.class).pop();
}
}