Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[改善] コメント座標の遅延評価機能を追加 #93

Merged
merged 4 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/@types/IComment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { IRenderer } from "@/@types/renderer";
export interface IComment {
comment: FormattedCommentWithSize;
invisible: boolean;
index: number;
loc: CommentLoc;
width: number;
long: number;
Expand Down
1 change: 1 addition & 0 deletions src/@types/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export type BaseOptions = {
showFPS: boolean;
useLegacy: boolean;
video: HTMLVideoElement | undefined;
lazy: boolean;
};
export type Options = Partial<BaseOptions>;

Expand Down
5 changes: 4 additions & 1 deletion src/comments/BaseComment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,22 @@ class BaseComment implements IComment {
public readonly pluginName: string = "BaseComment";
public image?: IRenderer | null;
public buttonImage?: IRenderer | null;
public index: number;

/**
* コンストラクタ
* @param comment 処理対象のコメント
* @param renderer 描画対象のレンダラークラス
* @param index コメントのインデックス
*/
constructor(comment: FormattedComment, renderer: IRenderer) {
constructor(comment: FormattedComment, renderer: IRenderer, index: number) {
this.renderer = renderer;
this.posY = 0;
this.pos = { x: 0, y: 0 };
comment.content = comment.content.replace(/\t/g, "\u2003\u2003");
this.comment = this.convertComment(comment);
this.cacheKey = this.getCacheKey();
this.index = index;
}
get invisible() {
return this.comment.invisible;
Expand Down
4 changes: 2 additions & 2 deletions src/comments/FlashComment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ class FlashComment extends BaseComment {
private _globalScale: number;
override readonly pluginName: string = "FlashComment";
override buttonImage: IRenderer;
constructor(comment: FormattedComment, renderer: IRenderer) {
super(comment, renderer);
constructor(comment: FormattedComment, renderer: IRenderer, index: number) {
super(comment, renderer, index);
this._globalScale ??= getConfig(config.commentScale, true);
this.buttonImage = renderer.getCanvas();
}
Expand Down
4 changes: 2 additions & 2 deletions src/comments/HTML5Comment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ import { BaseComment } from "./BaseComment";

class HTML5Comment extends BaseComment {
override readonly pluginName: string = "HTML5Comment";
constructor(comment: FormattedComment, context: IRenderer) {
super(comment, context);
constructor(comment: FormattedComment, context: IRenderer, index: number) {
super(comment, context, index);
this.posY = 0;
}

Expand Down
1 change: 1 addition & 0 deletions src/definition/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const defaultOptions: BaseOptions = {
showFPS: false,
useLegacy: false,
video: undefined,
lazy: false,
};

let config: BaseConfig;
Expand Down
39 changes: 28 additions & 11 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ class NiconiComments {
public showFPS: boolean;
public showCommentCount: boolean;
private lastVpos: number;
private processedCommentIndex: number;
private comments: IComment[];
private readonly renderer: IRenderer;
private readonly collision: Collision;
private readonly timeline: Timeline;
Expand Down Expand Up @@ -135,26 +137,29 @@ class NiconiComments {
right: [],
};
this.lastVpos = -1;
this.preRendering(parsedData);
this.processedCommentIndex = 0;

this.comments = this.preRendering(parsedData);

logger(`constructor complete: ${performance.now() - constructorStart}ms`);
}

/**
* 事前に当たり判定を考慮してコメントの描画場所を決定する
* @param rawData コメントデータ
* @returns コメントのインスタンス配列
*/
private preRendering(rawData: FormattedComment[]) {
const preRenderingStart = performance.now();
if (options.keepCA) {
rawData = changeCALayer(rawData);
}
let instances = rawData.reduce<IComment[]>((pv, val) => {
pv.push(createCommentInstance(val, this.renderer));
let instances = rawData.reduce<IComment[]>((pv, val, index) => {
pv.push(createCommentInstance(val, this.renderer, index));
return pv;
}, []);
this.getCommentPos(instances);
this.sortComment();
this.getCommentPos(instances, instances.length, options.lazy);
this.sortTimelineComment();

const plugins: IPluginList = [];
for (const plugin of config.plugins) {
Expand All @@ -175,25 +180,34 @@ class NiconiComments {

setPlugins(plugins);
logger(`preRendering complete: ${performance.now() - preRenderingStart}ms`);
return instances;
}

/**
* 計算された描画サイズをもとに各コメントの配置位置を決定する
* @param data コメントデータ
* @param end 終了インデックス
* @param lazy 遅延処理を行うか
*/
private getCommentPos(data: IComment[]) {
private getCommentPos(data: IComment[], end: number, lazy: boolean = false) {
const getCommentPosStart = performance.now();
for (const comment of data) {
if (this.processedCommentIndex + 1 >= end) return;
for (const comment of data.slice(this.processedCommentIndex, end)) {
if (comment.invisible) continue;
if (comment.loc === "naka") {
processMovableComment(comment, this.collision, this.timeline);
processMovableComment(comment, this.collision, this.timeline, lazy);
} else {
processFixedComment(
comment,
this.collision[comment.loc],
this.timeline,
lazy,
);
}
this.processedCommentIndex = comment.index;
}
if (lazy) {
this.processedCommentIndex = 0;
}
logger(
`getCommentPos complete: ${performance.now() - getCommentPosStart}ms`,
Expand All @@ -203,7 +217,7 @@ class NiconiComments {
/**
* 投稿者コメントを前に移動
*/
private sortComment() {
private sortTimelineComment() {
const sortCommentStart = performance.now();
for (const vpos of Object.keys(this.timeline)) {
const item = this.timeline[Number(vpos)];
Expand All @@ -228,8 +242,10 @@ class NiconiComments {
* @param rawComments コメントデータ
*/
public addComments(...rawComments: FormattedComment[]) {
const comments = rawComments.reduce<IComment[]>((pv, val) => {
pv.push(createCommentInstance(val, this.renderer));
const comments = rawComments.reduce<IComment[]>((pv, val, index) => {
pv.push(
createCommentInstance(val, this.renderer, this.comments.length + index),
);
return pv;
}, []);
for (const plugin of plugins) {
Expand Down Expand Up @@ -333,6 +349,7 @@ class NiconiComments {
if (comment.invisible) {
continue;
}
this.getCommentPos(this.comments, comment.index + 1);
comment.draw(vpos, this.showCollision, cursor);
}
}
Expand Down
113 changes: 65 additions & 48 deletions src/utils/comment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -585,25 +585,15 @@ const isBanActive = (vpos: number): boolean => {
* @param comment 固定コメント
* @param collision コメントの衝突判定用配列
* @param timeline コメントのタイムライン
* @param lazy Y座標の計算を遅延させるか
*/
const processFixedComment = (
comment: IComment,
collision: CollisionItem,
timeline: Timeline,
lazy: boolean = false,
) => {
let posY = 0,
isChanged = true,
count = 0;
while (isChanged && count < 10) {
isChanged = false;
count++;
for (let j = 0; j < comment.long; j++) {
const result = getPosY(posY, comment, collision[comment.vpos + j]);
posY = result.currentPos;
isChanged = result.isChanged;
if (result.isBreak) break;
}
}
const posY = lazy ? -1 : getFixedPosY(comment, collision);
for (let j = 0; j < comment.long; j++) {
const vpos = comment.vpos + j;
arrayPush(timeline, vpos, comment);
Expand All @@ -618,49 +608,17 @@ const processFixedComment = (
* @param comment nakaコメント
* @param collision コメントの衝突判定用配列
* @param timeline コメントのタイムライン
* @param lazy Y座標の計算を遅延させるか
*/
const processMovableComment = (
comment: IComment,
collision: Collision,
timeline: Timeline,
lazy: boolean = false,
) => {
const beforeVpos =
Math.round(-288 / ((1632 + comment.width) / (comment.long + 125))) - 100;
const posY = (() => {
if (config.canvasHeight < comment.height) {
return (comment.height - config.canvasHeight) / -2;
}
let posY = 0;
let isChanged = true;
while (isChanged) {
isChanged = false;
for (let j = beforeVpos, n = comment.long + 125; j < n; j++) {
const vpos = comment.vpos + j;
const leftPos = getPosX(comment.comment, vpos);
let isBreak = false;
if (
leftPos + comment.width >= config.collisionRange.right &&
leftPos <= config.collisionRange.right
) {
const result = getPosY(posY, comment, collision.right[vpos]);
posY = result.currentPos;
isChanged ||= result.isChanged;
isBreak = result.isBreak;
}
if (
leftPos + comment.width >= config.collisionRange.left &&
leftPos <= config.collisionRange.left
) {
const result = getPosY(posY, comment, collision.left[vpos]);
posY = result.currentPos;
isChanged ||= result.isChanged;
isBreak = result.isBreak;
}
if (isBreak) return posY;
}
}
return posY;
})();
const posY = lazy ? -1 : getMovablePosY(comment, collision, beforeVpos);
for (let j = beforeVpos, n = comment.long + 125; j < n; j++) {
const vpos = comment.vpos + j;
const leftPos = getPosX(comment.comment, vpos);
Expand All @@ -683,6 +641,63 @@ const processMovableComment = (
comment.posY = posY;
};

const getFixedPosY = (comment: IComment, collision: CollisionItem) => {
let posY = 0,
isChanged = true,
count = 0;
while (isChanged && count < 10) {
isChanged = false;
count++;
for (let j = 0; j < comment.long; j++) {
const result = getPosY(posY, comment, collision[comment.vpos + j]);
posY = result.currentPos;
isChanged = result.isChanged;
if (result.isBreak) break;
}
}
return posY;
};

const getMovablePosY = (
comment: IComment,
collision: Collision,
beforeVpos: number,
) => {
if (config.canvasHeight < comment.height) {
return (comment.height - config.canvasHeight) / -2;
}
let posY = 0;
let isChanged = true;
while (isChanged) {
isChanged = false;
for (let j = beforeVpos, n = comment.long + 125; j < n; j++) {
const vpos = comment.vpos + j;
const leftPos = getPosX(comment.comment, vpos);
let isBreak = false;
if (
leftPos + comment.width >= config.collisionRange.right &&
leftPos <= config.collisionRange.right
) {
const result = getPosY(posY, comment, collision.right[vpos]);
posY = result.currentPos;
isChanged ||= result.isChanged;
isBreak = result.isBreak;
}
if (
leftPos + comment.width >= config.collisionRange.left &&
leftPos <= config.collisionRange.left
) {
const result = getPosY(posY, comment, collision.left[vpos]);
posY = result.currentPos;
isChanged ||= result.isChanged;
isBreak = result.isBreak;
}
if (isBreak) return posY;
}
}
return posY;
};

/**
* 当たり判定からコメントを配置できる場所を探す
* @param currentPos 現在のy座標
Expand Down Expand Up @@ -779,6 +794,8 @@ const parseFont = (font: CommentFont, size: string | number): string => {

export {
getDefaultCommand,
getFixedPosY,
getMovablePosY,
getPosX,
getPosY,
isBanActive,
Expand Down
6 changes: 4 additions & 2 deletions src/utils/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,20 @@ import { config } from "@/definition/config";
* コメントのインスタンスを生成する
* @param comment コメント
* @param context 描画対象のCanvasコンテキスト
* @param index コメントのインデックス
* @returns プラグインまたは内臓のコメントインスタンス
*/
const createCommentInstance = (
comment: FormattedComment,
context: IRenderer,
index: number,
) => {
for (const plugin of config.commentPlugins) {
if (plugin.condition(comment)) {
return new plugin.class(comment, context);
return new plugin.class(comment, context, index);
}
}
return new HTML5Comment(comment, context);
return new HTML5Comment(comment, context, index);
};

export { createCommentInstance };
Loading