-
Notifications
You must be signed in to change notification settings - Fork 346
feat: [project-sequencer-statemachine] ステートマシンに置き換える #2544
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
feat: [project-sequencer-statemachine] ステートマシンに置き換える #2544
Conversation
| <div | ||
| ref="rectSelectHitbox" | ||
| v-if="previewRectForRectSelect != undefined" | ||
| class="rect-select-preview" | ||
| :style="{ | ||
| display: isRectSelecting ? 'block' : 'none', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
表示/非表示の切り替えをdisplayからv-ifに変更しました。
Hiroshiba
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ほぼLGTMです!!
これをマージしたら完成でしょうか!!
であればマージ後、issue側で色んな人による動作確認を募集する流れが良さそうだなーと!!
| const idleStateId = computed((): IdleStateId => { | ||
| if (state.sequencerEditTarget === "NOTE") { | ||
| if (state.sequencerNoteTool === "SELECT_FIRST") { | ||
| return "selectNotesToolIdle"; | ||
| } else if (state.sequencerNoteTool === "EDIT_FIRST") { | ||
| return "editNotesToolIdle"; | ||
| } else { | ||
| throw new ExhaustiveError(state.sequencerNoteTool); | ||
| } | ||
| } else if (state.sequencerEditTarget === "PITCH") { | ||
| if (state.sequencerPitchTool === "DRAW") { | ||
| return "drawPitchToolIdle"; | ||
| } else if (state.sequencerPitchTool === "ERASE") { | ||
| return "erasePitchToolIdle"; | ||
| } else { | ||
| throw new ExhaustiveError(state.sequencerPitchTool); | ||
| } | ||
| } else { | ||
| throw new ExhaustiveError(state.sequencerEditTarget); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ここ結構危ない気がしますね!
まず目的が2つになってそうです。
useSequencerStateMachineに渡してステートマシンの初期状態を決める計算に使われてるのと、watchしてステートマシンを置き換えてるのと。
「フラグ3種からIdleStateIdを計算する」関数を切り出して2箇所から関数を叩く形がより良いかもです!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
「フラグ3種からIdleStateIdを計算する」関数を切り出して2箇所から関数を叩く形がより良いかもです!
以下のような形でしょうか?
(関数にするとwatchする変数を別で指定しないといけなくなるので、computed(今の形)の方が良い気がしています)
const computeIdleStateId = (): IdleStateId => {
if (state.sequencerEditTarget === "NOTE") {
if (state.sequencerNoteTool === "SELECT_FIRST") {
return "selectNotesToolIdle";
} else if (state.sequencerNoteTool === "EDIT_FIRST") {
return "editNotesToolIdle";
} else {
throw new ExhaustiveError(state.sequencerNoteTool);
}
} else if (state.sequencerEditTarget === "PITCH") {
if (state.sequencerPitchTool === "DRAW") {
return "drawPitchToolIdle";
} else if (state.sequencerPitchTool === "ERASE") {
return "erasePitchToolIdle";
} else {
throw new ExhaustiveError(state.sequencerPitchTool);
}
} else {
throw new ExhaustiveError(state.sequencerEditTarget);
}
};
const {
stateMachine,
previewMode,
previewNotes,
previewRectForRectSelect,
previewPitchEdit,
cursorState,
guideLineTicks,
} = useSequencerStateMachine(store, computeIdleStateId());
watch(() => [
state.sequencerEditTarget,
state.sequencerNoteTool,
state.sequencerPitchTool,
], () => {
const IdleStateId = computeIdleStateId();
if (stateMachine.currentStateId !== IdleStateId) {
stateMachine.transitionTo(IdleStateId, undefined);
}
});There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
watchのとこはこういう感じを想像してました!
const idleStateId = computed(() => computeIdleStateId());
watch(idleStateId, (value) => {
if (stateMachine.currentStateId !== value) {
stateMachine.transitionTo(value, undefined);
}
});けどまあ、ほとんど変わらない気もします。
(watchが不要になるのが一番良さそう感?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
なるほどです、ひとまずこのPRではcomputed(現在の形)で実装しようと思います…!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
とりあえず了解です。
ちなみに一つのものに複数の意味を持たせるのは、SOLID原則のS(単一責任の原則)に違反してたりします。
ちょくちょく本読んでるのでまたわかったらお伝えします!
| watch(idleStateId, (value) => { | ||
| if (stateMachine.currentStateId !== value) { | ||
| stateMachine.transitionTo(value, undefined); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ここ、やっぱりステートマシンの外からステートマシンの操作をしてるので、なかなか危なそうだなと感じます!
変な状態遷移が発生し得るので。例えば範囲選択中にツールが切り替えられちゃうとか。
おそらく「ツールを切り替える」というイベントをStateMachineのprocessに流し、ツールの状態変数もステートマシンのContextで管理するのが良いんだろうなーと。
ただ結構大変だと思うのと、より良い設計も思いつけるかもなので、いったんTODOコメントを書き足すというのはどうでしょうか?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
例えば範囲選択中にツールが切り替えられちゃうとか。
これは想定しています。(範囲選択中にツール切り替えのショートカットを押したときなど)
操作中にツールの切り替えが発生した場合は操作をキャンセルする、という仕様でひとまず実装しています。
おそらく「ツールを切り替える」というイベントをStateMachineのprocessに流し、ツールの状態変数もステートマシンのContextで管理するのが良いんだろうなーと。
複合状態(ステートの中にステートがある)を扱える設計にすれば可能だと思います。
また、イベントは、なるべくステートによって扱いが変わるもの(マウスイベントとキーボードイベント)のみ扱うようにするのが良いかなと思っています。
ツールの切り替えはステートマシンで扱わず、ツールごとにステートマシンを用意して、ツールが切り替わったらステートマシンも切り替える、という設計も良いかもと思っています。
このPRではひとまずTODOコメントの追加のみ行おうと思います。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
操作中にツールの切り替えが発生した場合は操作をキャンセルする、という仕様でひとまず実装しています。
なるほどです!
この辺りどこかのドキュメントに書いてまとめて行った方がいいかもですね。
StateMachineディレクトリとかにREADME置くとか、ファイルの先頭にメモを書くとか。
あと操作がキャンセルできないものも将来的にはありえるかも・・・?
適当ですが、自動生成中とか。
でもなんかキャンセルするしかないかもですね!
複合状態(ステートの中にステートがある)を扱える設計にすれば可能だと思います。
「ToolButtonが押された」というイベントを流すだけなので、複合状態が扱えなくても可能かも・・・?
このPRではひとまずTODOコメントの追加のみ行おうと思います。
了解です!
|
🚀 プレビュー用ページを作成しました 🚀 更新時点でのコミットハッシュ: |
Co-authored-by: Hiroshiba <[email protected]>
| this.context = context; | ||
|
|
||
| this.currentState = stateFactories[initialStateId](undefined); | ||
| this.currentState.onEnter(context); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
onEnterを呼んでいなかったので修正しました。
bf4cf38
into
VOICEVOX:project-sequencer-statemachine
Hiroshiba
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!!
ステートマシンは完成でしょうか!!
であればみんなで試してみるフェーズかなと!!
内容
ScoreSequencer.vueのプレビュー処理のところをステートマシンに置き換えます。コメントの整理も行います。
関連 Issue
その他