88 lines
4.0 KiB
JavaScript
88 lines
4.0 KiB
JavaScript
import { build } from 'esbuild'
|
|
|
|
const source = `
|
|
import { createPinia, setActivePinia } from 'pinia'
|
|
import { useParticleStore } from './src/store/particleStore.ts'
|
|
import { subEmitterTriggerTimings } from './src/core/subEmitterTiming.ts'
|
|
import { collectSubEmitterIds } from './src/core/subEmitterIds.ts'
|
|
|
|
setActivePinia(createPinia())
|
|
const store = useParticleStore()
|
|
const parent = store.addSystem()
|
|
const child = store.addSystem()
|
|
const assert = (condition, message) => { if (!condition) throw new Error(message) }
|
|
const setLife = (system, life) => {
|
|
system.config.lifeMode = 'fixed'
|
|
system.config.lifeMin = life
|
|
system.config.lifeMax = life
|
|
}
|
|
|
|
parent.config.mode = 'stream'
|
|
parent.config.streamBehavior = 'normal'
|
|
parent.config.delay = 0
|
|
parent.config.duration = 1
|
|
setLife(parent, 2)
|
|
parent.config.eventEnabled = true
|
|
parent.config.events = [{
|
|
id: 1, event: 'death', targetSystemId: child.id,
|
|
probability: 1, collisionLimit: 1, inherit: [], colorInheritMode: 'add',
|
|
}]
|
|
|
|
// 子发射器自身的 10s 发射时长不应算入时间轴。
|
|
child.config.mode = 'stream'
|
|
child.config.streamBehavior = 'normal'
|
|
child.config.delay = 0
|
|
child.config.duration = 10
|
|
setLife(child, 1.5)
|
|
|
|
// 死亡触发:父粒子最晚 3s 死亡,子发射器再存活 1.5s → 4.5s。
|
|
let frames = store.recalcTotalFrames()
|
|
assert(frames === Math.ceil(4.5 * 30) + 1, '死亡子发射器时间轴错误:' + frames)
|
|
const deathTiming = subEmitterTriggerTimings(store.systems, 30).get(child.id)
|
|
assert(deathTiming && Math.abs(deathTiming.firstTrigger - 2) < 1e-6, '死亡子发射器起点应为第一次死亡 2s')
|
|
assert(deathTiming && Math.abs(deathTiming.lastTrigger - 3) < 1e-6, '死亡子发射器最后触发应为 3s')
|
|
assert(deathTiming && Math.abs(deathTiming.end - 4.5) < 1e-6, '死亡子发射器终点应为 4.5s')
|
|
|
|
// 子发射器自身 delay 在父事件之后继续延后发射。
|
|
child.config.delay = 0.2
|
|
frames = store.recalcTotalFrames()
|
|
assert(frames === Math.ceil(4.7 * 30) + 1, '子发射器延迟未计入时间轴:' + frames)
|
|
child.config.delay = 0
|
|
|
|
// 出生触发:子发射器与父粒子同时开始,取较长者 2s → 3s。
|
|
parent.config.events[0].event = 'birth'
|
|
frames = store.recalcTotalFrames()
|
|
assert(frames === Math.ceil(3 * 30) + 1, '出生子发射器时间轴错误:' + frames)
|
|
const birthTiming = subEmitterTriggerTimings(store.systems, 30).get(child.id)
|
|
assert(birthTiming && Math.abs(birthTiming.firstTrigger - 0) < 1e-6, '出生子发射器应从父粒子首次出生开始')
|
|
assert(birthTiming && Math.abs(birthTiming.lastTrigger - 1) < 1e-6, '出生子发射器最后触发应为发射结束 1s')
|
|
assert(birthTiming && Math.abs(birthTiming.end - 2.5) < 1e-6, '出生子发射器终点应为 2.5s')
|
|
|
|
// 关闭“开启子发射器”后,保留的规则不应继续把目标标记为子发射器。
|
|
parent.config.eventEnabled = false
|
|
assert(!collectSubEmitterIds(store.systems).has(child.id), '关闭子发射器后目标仍被当作子发射器')
|
|
assert(!subEmitterTriggerTimings(store.systems, 30).has(child.id), '关闭子发射器后仍有时间轴触发区间')
|
|
frames = store.recalcTotalFrames()
|
|
assert(frames === Math.ceil(11.5 * 30) + 1, '关闭子发射器后目标未恢复独立时长')
|
|
|
|
// 移除引用后子发射器恢复正常,自身的 10s 发射时长重新计入。
|
|
parent.config.eventEnabled = true
|
|
parent.config.events = []
|
|
frames = store.recalcTotalFrames()
|
|
assert(frames === Math.ceil(11.5 * 30) + 1, '移除引用后时间轴错误:' + frames)
|
|
|
|
console.log('子发射器时间轴校验通过:死亡/出生触发与移除引用后的总长度')
|
|
`
|
|
|
|
const result = await build({
|
|
stdin: { contents: source, resolveDir: process.cwd(), sourcefile: 'verify-sub-emitter-timeline.ts', loader: 'ts' },
|
|
bundle: true,
|
|
platform: 'node',
|
|
format: 'esm',
|
|
write: false,
|
|
logLevel: 'silent',
|
|
})
|
|
|
|
const code = Buffer.from(result.outputFiles[0].contents).toString('base64')
|
|
await import(`data:text/javascript;base64,${code}`)
|