子发射器
This commit is contained in:
1 parent
d4ebb18777
commit
d224939efd
33 files changed
+5690
-1355
No files matched your search
@@ -14,19 +14,21 @@
|
||||
<div class="group-body" v-show="!collapsed.scene">
|
||||
<div class="tree scene-tree">
|
||||
<div
|
||||
v-for="(system, i) in store.systems"
|
||||
:key="`particle-${system.id}`"
|
||||
v-for="entry in displaySystems"
|
||||
:key="`particle-${entry.system.id}`"
|
||||
class="tree-item scene-object-item"
|
||||
:class="{ on: activeObjectType === 'particle' && system.id === store.activeObjectId }"
|
||||
@click="select(i)"
|
||||
:class="{ on: activeObjectType === 'particle' && entry.system.id === store.activeObjectId, 'scene-object-child': entry.depth > 0 }"
|
||||
:style="entry.depth > 0 ? { paddingLeft: `${entry.depth * 18}px` } : undefined"
|
||||
@click="store.selectSystem(entry.system.id)"
|
||||
>
|
||||
<span class="tdot">●</span>
|
||||
<span class="tlabel">{{ system.config.name || 'ParticleSystem' + (i + 1) }}</span>
|
||||
<button class="scene-object-eye" :class="{ off: system.visible === false }" :title="system.visible === false ? '显示粒子系统' : '隐藏粒子系统'" :aria-label="system.visible === false ? '显示粒子系统' : '隐藏粒子系统'" @click.stop="system.visible = system.visible === false">
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M2.5 12s3.5-6 9.5-6 9.5 6 9.5 6-3.5 6-9.5 6-9.5-6-9.5-6Z"/><circle cx="12" cy="12" r="2.8"/><path v-if="system.visible === false" class="eye-slash" d="M4 4l16 16"/></svg>
|
||||
<span v-if="entry.depth > 0" class="sub-branch">└</span>
|
||||
<span v-else class="tdot">●</span>
|
||||
<span class="tlabel">{{ entry.system.config.name || 'ParticleSystem' }}</span>
|
||||
<button class="scene-object-eye" :class="{ off: entry.system.visible === false }" :title="entry.system.visible === false ? '显示粒子系统' : '隐藏粒子系统'" :aria-label="entry.system.visible === false ? '显示粒子系统' : '隐藏粒子系统'" @click.stop="entry.system.visible = entry.system.visible === false">
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M2.5 12s3.5-6 9.5-6 9.5 6 9.5 6-3.5 6-9.5 6-9.5-6-9.5-6Z"/><circle cx="12" cy="12" r="2.8"/><path v-if="entry.system.visible === false" class="eye-slash" d="M4 4l16 16"/></svg>
|
||||
</button>
|
||||
<span class="scene-object-kind">粒子</span>
|
||||
<button class="scene-object-delete" title="删除粒子系统" @click.stop="store.removeSystem(system.id)">✕</button>
|
||||
<span class="scene-object-kind" :class="{ 'sub-emitter-kind': entry.depth > 0 }">{{ entry.depth > 0 ? '子发射器' : '粒子' }}</span>
|
||||
<button class="scene-object-delete" title="删除粒子系统" @click.stop="store.removeSystem(entry.system.id)">✕</button>
|
||||
</div>
|
||||
<div
|
||||
v-for="collider in store.colliders"
|
||||
@@ -182,6 +184,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import NumSlider from '../NumSlider.vue'
|
||||
import CurveEditor from '../CurveEditor.vue'
|
||||
import ParticleAttributeControl from '../ParticleAttributeControl.vue'
|
||||
@@ -189,7 +192,44 @@ import ColorGradientEditor from '../ColorGradientEditor.vue'
|
||||
import ImageResourceCard from '../ImageResourceCard.vue'
|
||||
import SpineObjectPanel from '../../spine/SpineObjectPanel.vue'
|
||||
import { useParticlePanelContext } from './particlePanelContext'
|
||||
const { store, resolvedCurveEditorMode, sys, activeObjectType, activeCollider, activePath, activeSpine, canCopyObject, collapsed, toggle, select, addSys, addCollider, addPath, addSpine, copySelectedObject, applyPathPreset, clearPathAnchors, randomizeSeed, LINEAR_CURVE } = useParticlePanelContext()
|
||||
const { store, resolvedCurveEditorMode, sys, activeObjectType, activeCollider, activePath, activeSpine, canCopyObject, collapsed, toggle, addSys, addCollider, addPath, addSpine, copySelectedObject, applyPathPreset, clearPathAnchors, randomizeSeed, LINEAR_CURVE } = useParticlePanelContext()
|
||||
|
||||
type DisplaySystem = { system: (typeof store.systems)[number]; depth: number }
|
||||
|
||||
/** 子发射器嵌在父系统下方显示,方便直接选中;移除引用后自动回到普通行。 */
|
||||
const displaySystems = computed<DisplaySystem[]>(() => {
|
||||
const byId = new Map(store.systems.map((system) => [system.id, system]))
|
||||
const parentOf = new Map<number, number>()
|
||||
for (const system of store.systems) {
|
||||
if (system.config.eventEnabled === false) continue
|
||||
for (const rule of system.config.events || []) {
|
||||
if (rule.targetSystemId <= 0 || rule.targetSystemId === system.id) continue
|
||||
if (!byId.has(rule.targetSystemId) || parentOf.has(rule.targetSystemId)) continue
|
||||
parentOf.set(rule.targetSystemId, system.id)
|
||||
}
|
||||
}
|
||||
const children = new Map<number, number[]>()
|
||||
for (const [child, parent] of parentOf) {
|
||||
const list = children.get(parent)
|
||||
if (list) list.push(child)
|
||||
else children.set(parent, [child])
|
||||
}
|
||||
const result: DisplaySystem[] = []
|
||||
const visited = new Set<number>()
|
||||
const walk = (system: (typeof store.systems)[number], depth: number) => {
|
||||
if (visited.has(system.id)) return
|
||||
visited.add(system.id)
|
||||
result.push({ system, depth })
|
||||
for (const childId of children.get(system.id) || []) {
|
||||
const child = byId.get(childId)
|
||||
if (child) walk(child, depth + 1)
|
||||
}
|
||||
}
|
||||
for (const system of store.systems) if (!parentOf.has(system.id)) walk(system, 0)
|
||||
// 环形引用兜底:保证所有系统仍然可见、可选中。
|
||||
for (const system of store.systems) if (!visited.has(system.id)) walk(system, 0)
|
||||
return result
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -219,11 +259,14 @@ const { store, resolvedCurveEditorMode, sys, activeObjectType, activeCollider, a
|
||||
.tree-item .tdot.collision-dot { color: #ff7070; }
|
||||
.tree-item .tdot.path-dot { color: #ff933e; font-size: 14px; }
|
||||
.tree-item .tdot.spine-dot { color: #c08cff; font-size: 11px; }
|
||||
.tree-item .sub-branch { color: #5f7090; font-size: 12px; }
|
||||
.tree-item .tlabel { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.scene-tree { padding-bottom: 8px; border-bottom: 1px solid #2a2a3c; }
|
||||
.scene-object-item { min-height: 28px; cursor: pointer; }
|
||||
.scene-object-item:hover { background: #202b40; }
|
||||
.scene-object-child { background: rgba(30, 42, 62, .35); }
|
||||
.scene-object-kind { color: #75829c; font-size: 10px; }
|
||||
.scene-object-kind.sub-emitter-kind { color: #8f8cff; }
|
||||
.scene-object-eye {
|
||||
width: 24px; height: 22px; padding: 3px; flex: 0 0 24px; border: 1px solid transparent; border-radius: 5px;
|
||||
background: transparent; color: #9aa6bf; cursor: pointer;
|
||||
|
||||
Reference in new issue
Block a user