阶段七落盘文档
This commit is contained in:
1 parent
5f4667f736
commit
031359586d
4 files changed
+452
-9
No files matched your search
+28
-3
@@ -68,7 +68,7 @@
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { Application, Container, Graphics, Text, Texture } from 'pixi.js'
|
||||
import { ParticleEmitter, ensureEmitterConfig, type ParticleState } from '../core/particleEmitter'
|
||||
import { useParticleStore, type ScenePath } from '../store/particleStore'
|
||||
import { useParticleStore, type CollisionBody, type ScenePath } from '../store/particleStore'
|
||||
import { SpineRuntimeLayer } from '../spine/SpineRuntimeLayer'
|
||||
|
||||
const store = useParticleStore()
|
||||
@@ -108,6 +108,7 @@ let dotTex: Texture<any> | null = null
|
||||
let trailTex: Texture<any> | null = null
|
||||
|
||||
const emitterMap = new Map<number, ParticleEmitter>()
|
||||
let previewColliders: CollisionBody[] = []
|
||||
const emitterPreviewTransform = new Map<number, { x: number; y: number; rotation: number }>()
|
||||
const selectedPathNodes = new Set<number>()
|
||||
let suppressNextPathDoubleClick = false
|
||||
@@ -908,7 +909,7 @@ function drawCollisionBodies() {
|
||||
if (!collisionGfx) return
|
||||
const g = collisionGfx
|
||||
g.clear()
|
||||
for (const collider of store.colliders) {
|
||||
for (const collider of previewColliders) {
|
||||
const selected = store.activeObjectType === 'collision' && store.activeObjectId === collider.id
|
||||
const color = collider.enabled ? (selected ? 0xff5e72 : 0xd4475b) : 0x586174
|
||||
const angle = collider.rotation * Math.PI / 180
|
||||
@@ -1050,6 +1051,29 @@ function sampleScenePath(path: ScenePath, progress: number) {
|
||||
return { x, y, angle: Math.atan2(next.y - previous.y, next.x - previous.x) * 180 / Math.PI }
|
||||
}
|
||||
|
||||
function buildPreviewColliders(timeSeconds: number) {
|
||||
previewColliders = store.colliders.map((collider) => {
|
||||
if (!collider.followPath || !collider.followPathId) return collider
|
||||
const path = store.paths.find((item) => item.id === collider.followPathId && item.enabled)
|
||||
if (!path?.points.length) return collider
|
||||
const duration = Math.max(0.05, Number(collider.followDuration) || 2)
|
||||
const normalized = Math.min(1, Math.max(0, timeSeconds / duration))
|
||||
const curve = Array.isArray(collider.followCurve) ? collider.followCurve : [{ x: 0, y: 0 }, { x: 1, y: 1 }]
|
||||
const progress = collider.followCurveMode === '线性'
|
||||
? normalized
|
||||
: Math.min(1, Math.max(0, followCurveValue(curve, normalized)))
|
||||
const sample = sampleScenePath(path, progress)
|
||||
return sample
|
||||
? {
|
||||
...collider,
|
||||
x: sample.x,
|
||||
y: sample.y,
|
||||
rotation: collider.rotation + (collider.followPathRotation ? sample.angle : 0),
|
||||
}
|
||||
: collider
|
||||
})
|
||||
}
|
||||
|
||||
function worldPointToEmitterLocal(config: { centerX: number; centerY: number; rootRotation: number; rootScaleX: number; rootScaleY: number }, worldX: number, worldY: number) {
|
||||
const scaleX = Math.max(0.0001, Math.abs(config.rootScaleX))
|
||||
const scaleY = Math.max(0.0001, Math.abs(config.rootScaleY))
|
||||
@@ -1075,12 +1099,13 @@ function loop() {
|
||||
syncEmitters()
|
||||
// 根节点(root)变换:位置(centerX/centerY)=位移,rotation/scale 绕 root 中心,与场景对象参数联动
|
||||
const followTime = store.timeline.frame / Math.max(1, store.timeline.fps)
|
||||
buildPreviewColliders(followTime)
|
||||
for (const sys of store.systems) {
|
||||
const em = emitterMap.get(sys.id)
|
||||
if (!em) continue
|
||||
const c = sys.config
|
||||
em.scale.set(c.rootScaleX, c.rootScaleY)
|
||||
em.setColliders(store.colliders)
|
||||
em.setColliders(previewColliders)
|
||||
em.setEmitterFollowSpawn(0, 0, 0)
|
||||
let preview = { x: c.centerX, y: c.centerY, rotation: c.rootRotation }
|
||||
const followPath = c.emitterFollow && c.emitterFollowMode === 'path'
|
||||
|
||||
Reference in new issue
Block a user