Skip to content

ParticleCompositeCurve(min, 0) incorrectly selects Constant mode #3082

Description

@luzhuang

Describe the bug

ParticleCompositeCurve incorrectly selects the single-constant overload when the second constant is 0.

This affects both direct Engine callers and runtime-v2 loaders that construct the value from canonical two-argument constructor data.

Affected code is still present on dev/2.0@bd34daa45612af8b402cd3be916ff181f21ae742 and in the latest published release v2.0.0-alpha.41@8e1147798:

constructor(constantOrCurve: number | ParticleCurve, constantMaxOrCurveMax?: number | ParticleCurve) {
  // ...
  if (typeof constantOrCurve === "number") {
    if (constantMaxOrCurveMax) {
      this.constantMin = constantOrCurve;
      this.constantMax = <number>constantMaxOrCurveMax;
      this.mode = ParticleCurveMode.TwoConstants;
    } else {
      this.constant = constantOrCurve;
      this.mode = ParticleCurveMode.Constant;
    }
  }
}

Minimal reproduction

const count = new ParticleCompositeCurve(5, 0);

console.log(count.mode);        // Actual: ParticleCurveMode.Constant
console.log(count.constantMin); // Actual: 0
console.log(count.constantMax); // Actual: 5

Expected behavior

count.mode === ParticleCurveMode.TwoConstants;
count.constantMin === 5;
count.constantMax === 0;

The two-argument overload must be selected by argument presence, not by the truthiness of the second value. 0 is a valid numeric endpoint.

Root cause and proposed fix

The constructor uses if (constantMaxOrCurveMax), so the valid numeric value 0 is treated as if the second argument were omitted.

Use an explicit presence check in both overload branches:

if (constantMaxOrCurveMax !== undefined) {
  // TwoConstants or TwoCurves
}

The one-argument overload should remain unchanged.

Acceptance criteria

  • new ParticleCompositeCurve(5, 0) produces TwoConstants, constantMin = 5, and constantMax = 0.
  • new ParticleCompositeCurve(5) still produces Constant with value 5.
  • The two-curve overload remains unchanged.
  • Add a regression that asserts the final Engine object, not only serialized constructor arguments.
  • Publish the fix in a new 2.0.0-alpha.* release so downstream runtime-v2 producers can use the canonical two-argument representation.

Downstream impact

galacean/editor#3813 emits canonical particle Burst count constructor data, including $args: [5, 0]. The Engine-side implementation is galacean/engine#3083. Editor is rolling out its canonical protocol first; after #3083 is merged and published in a new 2.0.0-alpha.*, Editor will bump the pinned packages and restore the API → source-v2 → Builder → Loader → Engine object regression.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions