refactor: various improvements
This commit is contained in:
+7
-3
@@ -10,21 +10,25 @@ export type Context = {
|
||||
export const GameContext = createModel((root: Context) => {
|
||||
const parts = createEntityCollection<Part>();
|
||||
const regions = createEntityCollection<Region>();
|
||||
const contexts = signal([signal(root)]);
|
||||
const contexts = signal<Signal<Context>[]>([]);
|
||||
contexts.value = [signal(root)];
|
||||
function pushContext(context: Context) {
|
||||
const ctxSignal = signal(context);
|
||||
contexts.value = [...contexts.value, ctxSignal];
|
||||
return context;
|
||||
}
|
||||
function popContext() {
|
||||
contexts.value = contexts.value.slice(0, -1);
|
||||
if (contexts.value.length > 1) {
|
||||
contexts.value = contexts.value.slice(0, -1);
|
||||
}
|
||||
}
|
||||
function latestContext<T extends Context>(type: T['type']){
|
||||
function latestContext<T extends Context>(type: T['type']): Signal<T> | undefined {
|
||||
for(let i = contexts.value.length - 1; i >= 0; i--){
|
||||
if(contexts.value[i].value.type === type){
|
||||
return contexts.value[i] as Signal<T>;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
+9
-9
@@ -28,36 +28,36 @@ export type RegionAxis = {
|
||||
export function applyAlign(region: Region){
|
||||
if (region.children.length === 0) return;
|
||||
|
||||
// 对每个 axis 分别处理,但保持空间关系
|
||||
// Process each axis independently while preserving spatial relationships
|
||||
for (let axisIndex = 0; axisIndex < region.axes.length; axisIndex++) {
|
||||
const axis = region.axes[axisIndex];
|
||||
if (!axis.align) continue;
|
||||
|
||||
// 收集当前轴上的所有唯一位置值,保持原有顺序
|
||||
// Collect all unique position values on this axis, preserving original order
|
||||
const positionValues = new Set<number>();
|
||||
for (const accessor of region.children) {
|
||||
positionValues.add(accessor.value.position[axisIndex] ?? 0);
|
||||
}
|
||||
|
||||
// 排序位置值
|
||||
// Sort position values
|
||||
const sortedPositions = Array.from(positionValues).sort((a, b) => a - b);
|
||||
|
||||
// 创建位置映射:原位置 -> 新位置
|
||||
// Create position mapping: old position -> new position
|
||||
const positionMap = new Map<number, number>();
|
||||
|
||||
if (axis.align === 'start' && axis.min !== undefined) {
|
||||
// 从 min 开始紧凑排列,保持相对顺序
|
||||
// Compact from min, preserving relative order
|
||||
sortedPositions.forEach((pos, index) => {
|
||||
positionMap.set(pos, axis.min! + index);
|
||||
});
|
||||
} else if (axis.align === 'end' && axis.max !== undefined) {
|
||||
// 从 max 开始向前紧凑排列
|
||||
// Compact towards max
|
||||
const count = sortedPositions.length;
|
||||
sortedPositions.forEach((pos, index) => {
|
||||
positionMap.set(pos, axis.max! - (count - 1 - index));
|
||||
});
|
||||
} else if (axis.align === 'center') {
|
||||
// 居中排列
|
||||
// Center alignment
|
||||
const count = sortedPositions.length;
|
||||
const min = axis.min ?? 0;
|
||||
const max = axis.max ?? count - 1;
|
||||
@@ -70,14 +70,14 @@ export function applyAlign(region: Region){
|
||||
});
|
||||
}
|
||||
|
||||
// 应用位置映射到所有 part
|
||||
// Apply position mapping to all parts
|
||||
for (const accessor of region.children) {
|
||||
const currentPos = accessor.value.position[axisIndex] ?? 0;
|
||||
accessor.value.position[axisIndex] = positionMap.get(currentPos) ?? currentPos;
|
||||
}
|
||||
}
|
||||
|
||||
// 最后按所有轴排序 children
|
||||
// Sort children by all axes at the end
|
||||
region.children.sort((a, b) => {
|
||||
for (let i = 0; i < region.axes.length; i++) {
|
||||
const diff = (a.value.position[i] ?? 0) - (b.value.position[i] ?? 0);
|
||||
|
||||
+15
-23
@@ -1,4 +1,4 @@
|
||||
import {Context} from "./context";
|
||||
import {Context} from "./context";
|
||||
import {Command} from "../utils/command";
|
||||
import {effect} from "@preact/signals-core";
|
||||
|
||||
@@ -17,8 +17,8 @@ export type RuleContext<T> = Context & {
|
||||
* @returns 规则执行结果
|
||||
*/
|
||||
export function invokeRuleContext<T>(
|
||||
pushContext: (context: Context) => void,
|
||||
type: string,
|
||||
pushContext: (context: Context) => void,
|
||||
type: string,
|
||||
rule: Generator<string, T, Command>
|
||||
): RuleContext<T> {
|
||||
const ctx: RuleContext<T> = {
|
||||
@@ -29,41 +29,39 @@ export function invokeRuleContext<T>(
|
||||
resolution: undefined,
|
||||
};
|
||||
|
||||
// 执行生成器直到完成或需要等待动作
|
||||
let disposed = false;
|
||||
|
||||
const executeRule = () => {
|
||||
if (disposed || ctx.resolution !== undefined) return;
|
||||
|
||||
try {
|
||||
const result = rule.next();
|
||||
|
||||
|
||||
if (result.done) {
|
||||
// 规则执行完成,设置结果
|
||||
ctx.resolution = result.value;
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果生成器 yield 了一个动作类型,等待处理
|
||||
// 这里可以扩展为实际的动作处理逻辑
|
||||
const actionType = result.value;
|
||||
|
||||
// 继续执行直到有动作需要处理或规则完成
|
||||
if (!result.done) {
|
||||
executeRule();
|
||||
|
||||
if (actionType) {
|
||||
// 暂停于 yield 点,等待外部处理动作
|
||||
// 当外部更新 actions 后,effect 会重新触发
|
||||
}
|
||||
} catch (error) {
|
||||
// 规则执行出错,抛出错误
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// 使用 effect 来跟踪响应式依赖
|
||||
const dispose = effect(() => {
|
||||
if (ctx.resolution !== undefined) {
|
||||
dispose();
|
||||
disposed = true;
|
||||
return;
|
||||
}
|
||||
executeRule();
|
||||
});
|
||||
|
||||
// 将规则上下文推入栈中
|
||||
pushContext(ctx);
|
||||
|
||||
return ctx;
|
||||
@@ -77,12 +75,6 @@ export function invokeRuleContext<T>(
|
||||
export function createRule<T>(
|
||||
type: string,
|
||||
fn: (ctx: RuleContext<T>) => Generator<string, T, Command>
|
||||
): Generator<string, T, Command> {
|
||||
return fn({
|
||||
type,
|
||||
actions: [],
|
||||
handledActions: 0,
|
||||
invocations: [],
|
||||
resolution: undefined,
|
||||
});
|
||||
): (ctx: RuleContext<T>) => Generator<string, T, Command> {
|
||||
return fn;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user