Tag / Metadata on SolidParticle

In the Babylon project that I’m working on, each SolidParticle relates to a real world object. When the user picks a particle, I do a web call to get information on that object.

At the moment, in the initParticles method I do a very non-Typescript-like

(<any>particle).tag = this.myObjectArray[p].id;

to create a new property on the particle and assign it to the read world object Id. I can then read that tag back out when the particle is picked.

It would be nice to have “official” support for this in the way that a Mesh has the metadata property.

There is also the issue that if you do the above in the particlePosition method, the added property (tag in this case) gets removed. (I’m not totally sure why, maybe the object properties are copied).

1 Like

maybe it is useful “officially”, idk.

Great topic nick. Good to see you back.

Also, is easily possible to use a different pattern, a LOOKUP pattern.

Can you give the particle a unique ID?

If so, then consider a lookup in a completely separate (and custom) state matrix.

There are additional advantages to choosing that approach.

It used to be called Namespace design pattern.

Now reduced to: state and context.

Depending who you talk to.

~ : )-.

adding @jerome

It’s definitely possible to code around it in various ways. The SolidParticle does have a unique, immutable id given by Babylon.

However, I have 30k of these “things” as particles in my scene. Updating them all and having to do a lookup to get the real world ID, then another lookup with the real world object is all overhead.

When they are deleted or add I also have to keep the lookup table in sync etc.

1 Like

makes sense. I see what you are looking for now. : )

Well, it’s a concern beyond the solid particles themselves. It’s related to each BJS entity or any other framework provided entity.
Depending on the language capabilities, you can in this case either :

  • maintain a side appart object of your own holding your logic data, what you’re doing with all expected the syncing issues and all the lookup performance problems
  • or extend/modify, if possible, the class of the object provided by the framework, what would probably lead to a framework recompilation or rebuild.

I think that none of both these options fits your need.

So if everyone is ok, I can implement the feature to add some optional properties to the Solid Particle object. Something, maybe, that could be instanciated from the SPS constructor (let me know the name that you prefer) if TypeScript allows this (not sure at this time) :

var sps = new BABYLON.SolidParticleSystem("sps", {particleCustomProperties: ["myProperty1", "myProperty2"]}, scene);
\\ this would lead to give each solid particle 
\\ the properties "myProperty1" and "myProperty2" typed as "Any"
var particle = sps.particles[i];
particle.myProperty1 = myValue1;
particle.myProperty2 = myValue2;

More generally, maybe this kind of feature could be implemented at a higher level for each BJS object constructor so this could solve the framework object to logic object linking issue for anything and anyone.

Well, as dynamic property creation seems impossible with TypeScript, I just added a default custom property, called props (typed “any”, default value “null”), to each solid particle.
So now, you can “extend” as you want the solid particle object by setting this property :
particle.props = {myProp1: val1, myProp2: val2}

1 Like

Create an object with certain keys

function f<T extends string>(keys: readonly T[]) {
  return {} as {
    [k in typeof keys[number]]?: any
  }
}

f(['x', 'y']).x; // ok
f(['x', 'y']).y; // ok
f(['x', 'y']).z; // err; prop 'z' doesn't exist on type {x?:any, y?:any}
1 Like

Very nice.
How would you add some properties to an existing class then ?

public addProperties<T extends string>(keys: readonly T[]) {
  return this as {
    [k in typeof keys[number]]?: any
  }
}

Not sure this would work here, wouldn’t it ?

I think that for your case, tsc fails to determine the type of that class in compile time.

A solution is that create a fn generating a particle instance wrapper, e.g.

// old particle class
class Particle {
  constructor(public foo = 0) { }
}

// new fn generating particle inst wrapper
function F<T extends string>(p: Particle, keys: T[] = []) {
  return Object.create(p) as (Particle & {
    [k in typeof keys[number]]?: any
  });
}

// then
F(new Particle(), ['x', 'y']) instanceof Particle; // true
F(new Particle(), ['x', 'y']).foo; // ok
F(new Particle(), ['x', 'y']).x;   // ok
F(new Particle(), ['x', 'y']).y;   // ok
F(new Particle(), ['x', 'y']).z;   // err; prop 'z' doesn't exist on type ..

The particle system should be like this

class ParticleSystem<T extends string>{
  constructor(
    name: string,
    customProps: T[],
  );
  constructor(
    public name: string,
    public customProps: T[] = [],
    public particles: (Particle & {
      [k in typeof customProps[number]]?: any
    })[] = []
  ) {
    // add one particle for e.g.
    this.particles[0] = F(new Particle(), customProps);
  }
}

const ps = new ParticleSystem('', ['x', 'y']);
ps.particles[0].foo; // ok
ps.particles[0].x; // ok
ps.particles[0].y; // ok
ps.particles[0].z; // err; prop 'z' doesn't exist on type ..

As you can see, the custom props do override Particle{} prop :joy:
you may give them a check in particlesystem ctor…

1 Like

Very smart :slight_smile:

2 Likes