A particle is a function of its age, not a thing that is stepped (#73)
game-maker / suite (push) Failing after 4m22s
game-maker / suite (push) Failing after 4m22s
The asset type `particles` is placeable and carries a graph at the same time — `behavior` was the blueprint. Because a continuous emitter gives birth to particle n at time n/rate, the whole field is a function of the clock rather than of the frames: no ring-buffer bookkeeping, exact time jumps, reproducibility as a measurable property. compile.ts follows compileShader's frame but emits JS closures into a Float64Array instead of GLSL, and without eval; a node with two consumers is evaluated once. Drawing is one Pixi ParticleContainer per source, so one draw call. Collision, wind and braking in flight are out for good — that is the price of the formula model, not an omission. The tab count goes from nine to ten, which is exactly the case #84 was built for one day earlier: at 1280 px the row no longer holds every tab, so guard 14b now asks for hidden.length > 0 instead of === 0.
This commit is contained in:
1 parent
f83c568999
commit
0f9e1611d1
39 files changed
+2386
-32
No files matched your search
@@ -28,6 +28,7 @@ import {
|
||||
} from '../../core/graph';
|
||||
import type { GraphAsset } from '../../core/model/Asset';
|
||||
import { graphLookup } from '../../core/model/graphLookup';
|
||||
import { particleLibrary } from '../../viewport/ParticleLibrary';
|
||||
import { shaderLibrary } from '../../viewport/ShaderLibrary';
|
||||
import { findAsset, findGraphAsset } from '../../core/model/Project';
|
||||
import { type Trace, TRACE_FADE } from '../../runtime/systems/BehaviorSystem';
|
||||
@@ -219,8 +220,13 @@ export class GraphCanvas extends Widget {
|
||||
}
|
||||
const seen = new Set<string>();
|
||||
const lookup = graphLookup(this.state.project);
|
||||
// A shader node's problem is the compiler's, not a call's.
|
||||
const shaderProblems = asset.type === 'shader' ? shaderLibrary.buildFor(asset).problems : null;
|
||||
// In a compiled graph a node's problem is the compiler's, not a call's.
|
||||
const compilerProblems =
|
||||
asset.type === 'shader'
|
||||
? shaderLibrary.buildFor(asset).problems
|
||||
: asset.type === 'particles'
|
||||
? particleLibrary.buildFor(asset).problems
|
||||
: null;
|
||||
for (const node of asset.graph.nodes) {
|
||||
const def = resolveDef(node, asset.graph, lookup);
|
||||
if (!def) continue;
|
||||
@@ -233,8 +239,8 @@ export class GraphCanvas extends Widget {
|
||||
this.views.set(node.id, view);
|
||||
this.nodeLayer.addChild(view);
|
||||
}
|
||||
const problem = shaderProblems
|
||||
? (shaderProblems[node.id] ?? null)
|
||||
const problem = compilerProblems
|
||||
? (compilerProblems[node.id] ?? null)
|
||||
: callProblem(node, lookup, asset.id);
|
||||
view.sync(node, asset.graph, this.state.project, def, problem);
|
||||
}
|
||||
|
||||
@@ -53,6 +53,8 @@ export function categoryColor(category: NodeCategory): number {
|
||||
return c.categoryState;
|
||||
case 'shader':
|
||||
return c.categoryShader;
|
||||
case 'particles':
|
||||
return c.categoryParticles;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,14 @@ import type { GraphAsset } from '../../core/model/Asset';
|
||||
import { graphLookup } from '../../core/model/graphLookup';
|
||||
import type { PropertyBag } from '../../core/model/Properties';
|
||||
import type { Project } from '../../core/model/Project';
|
||||
import {
|
||||
isParticlePropertyNode,
|
||||
PARTICLE_PROPERTY,
|
||||
PROPERTY_NAME_PARAM as PARTICLE_NAME_PARAM,
|
||||
propertyNameOf,
|
||||
} from '../../core/properties/particles';
|
||||
import { nextPropertyName, PROPERTY_NAME_PARAM, SHADER_PROPERTY } from '../../core/properties/shaders';
|
||||
import { nextParticlePropertyName, PARTICLE_NODES, PARTICLE_OUTPUT } from '../../core/particles/nodes';
|
||||
import { SHADER_NODES, SHADER_OUTPUT } from '../../core/shader/nodes';
|
||||
|
||||
/**
|
||||
@@ -48,9 +55,19 @@ export function paletteEntries(project: Project, asset: GraphAsset): PaletteEntr
|
||||
return { id: def.type, hint: def.category, def, params };
|
||||
});
|
||||
}
|
||||
if (asset.type === 'particles') {
|
||||
const hasOutput = asset.graph.nodes.some((n) => n.type === PARTICLE_OUTPUT);
|
||||
const taken = new Set(asset.graph.nodes.filter(isParticlePropertyNode).map(propertyNameOf));
|
||||
return PARTICLE_NODES.filter((def) => def.type !== PARTICLE_OUTPUT || !hasOutput).map((def) => {
|
||||
const params: PropertyBag =
|
||||
def.type === PARTICLE_PROPERTY ? { [PARTICLE_NAME_PARAM]: nextParticlePropertyName(taken) } : {};
|
||||
return { id: def.type, hint: def.category, def, params };
|
||||
});
|
||||
}
|
||||
const entries: PaletteEntry[] = [];
|
||||
for (const def of allNodeDefs()) {
|
||||
if (def.type === RUN_BEHAVIOR || def.category === 'state' || def.category === 'shader') continue;
|
||||
if (def.type === RUN_BEHAVIOR || def.category === 'state') continue;
|
||||
if (def.category === 'shader' || def.category === 'particles') continue;
|
||||
if (isTerminalType(def.type) && terminalNode(asset.graph, def.type)) continue;
|
||||
entries.push({ id: def.type, hint: def.category, def, params: {} });
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user