Recycling models, is it worth it?

All topics about ZGameEditor goes here.

Moderator: Moderators

Post Reply
User avatar
Ats
Posts: 770
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Recycling models, is it worth it?

Post by Ats »

Between the enemies, the buildings, the weapons and the debris, I have a lot of models being created and destroyed all the time in my game.
So I was wondering if I should keep it that way, or if it would be better to recycle them.

I guess it would consist of adding the created models in an array, and kind of deactivate them with a boolean when they are destroyed, instead of calling RemoveModel().
Then, when I need to create a new model, I would cycle through the array and see if any model is deactivated in order to revive it.
And if every model in the array is activated, then I just create a new model and add it to the array.

So, do you guys think it is worth doing that, or is it just a waste of time? Maybe models are already well handled in the background by ZGE?
User avatar
Kjell
Posts: 1915
Joined: Sat Feb 23, 2008 11:15 pm

Re: Recycling models, is it worth it?

Post by Kjell »

Hi Ats,
Ats wrote: Thu Feb 16, 2023 7:00 pmSo, do you guys think it is worth doing that, or is it just a waste of time?
If you're experiencing hiccups during gameplay due to models being spawned, recycling models can certainly be a relatively easy remedy. However, if your game already runs completely smooth at the desired framerate on a computer that you consider to be the minimum system requirements, why bother? :wink:

K
User avatar
Ats
Posts: 770
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: Recycling models, is it worth it?

Post by Ats »

It freezes for a few frames on some recent phones when I spawn more than 30 enemies at a time...
So I made a little working example, but I'm not happy with setting the Thing parameters in the general activateThing function. I would prefer them to be set in the model, so I don't have to search everywhere for that bit of code. But I can't seem to find how to simply do that :?

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" FileVersion="2">
  <OnLoaded>
    <ZLibrary>
      <Source>
<![CDATA[void activateThing(model m)
{
  m.Alive = 1;
  m.Shape = round(rnd());
  m.Position.X = -6;
  m.Position.Y = random(0,3);
  m.Speed = rnd();

  CountAlive ++;
  Total ++;
}

void createNewThing()
{
  model m = createModel(ThingModel);
  SpoolArray.SizeDim1 ++;
  SpoolArray[SpoolArray.SizeDim1 - 1] = m;
  activateThing(m);
}

void recycleThing()
{
  if (SpoolArray.SizeDim1 > 0)
  {
    // Check for deactivated thing in the spool array
    for (int i=0; i<SpoolArray.SizeDim1; i++)
    {
      model m = SpoolArray[i];
      if (!m.Alive)
      {
        activateThing(m);
        return;
      }
    }
  }

  // No deactivated thing was found, add a new thing to the spool
  createNewThing();
}]]>
      </Source>
    </ZLibrary>
    <ZExpression Expression="SpoolArray.SizeDim1 = 0;"/>
  </OnLoaded>
  <OnUpdate>
    <Timer Name="Spawner" Interval="0.1105">
      <OnTimer>
        <ZExpression>
          <Expression>
<![CDATA[Spawner.CurrentRelativeTime = 0;
Spawner.Interval = rnd()/2;

recycleThing();]]>
          </Expression>
        </ZExpression>
      </OnTimer>
    </Timer>
  </OnUpdate>
  <OnRender>
    <RenderText Comment="Alive / Spool" Y="0.9" Scale="0.4" TextExpression="intToStr(CountAlive) + &quot; / &quot; + intToStr(SpoolArray.SizeDim1) + &quot; instead of &quot; + intToStr(Total);"/>
  </OnRender>
  <Content>
    <Mesh Name="SphereMesh">
      <Producers>
        <MeshSphere Scale="0.2 0.2 0.2" ZSamples="20" RadialSamples="20"/>
      </Producers>
    </Mesh>
    <Mesh Name="BoxMesh">
      <Producers>
        <MeshBox Scale="0.2 0.2 0.2"/>
      </Producers>
    </Mesh>
    <Model Name="ThingModel">
      <Definitions>
        <Variable Name="Alive" Type="4"/>
        <Variable Name="Shape" Type="4"/>
        <Variable Name="Speed"/>
        <ZLibrary>
          <Source>
<![CDATA[void deactivate()
{
  CurrentModel.Alive = 0;
  CurrentModel.Position.X = 100;

  CountAlive --;
}]]>
          </Source>
        </ZLibrary>
      </Definitions>
      <OnUpdate>
        <ZExpression>
          <Expression>
<![CDATA[if (CurrentModel.Alive)
{
  CurrentModel.Position.X += CurrentModel.Speed;
  if (CurrentModel.Position.X > 6) deactivate();
}]]>
          </Expression>
        </ZExpression>
      </OnUpdate>
      <OnRender>
        <ZExpression>
          <Expression>
<![CDATA[if (CurrentModel.Alive)
{
  if (CurrentModel.Shape) @RenderMesh(Mesh:BoxMesh);
  else @RenderMesh(Mesh:SphereMesh);
}]]>
          </Expression>
        </ZExpression>
      </OnRender>
    </Model>
    <Array Name="SpoolArray" Type="3" SizeDim1="6"/>
    <Variable Name="CountAlive" Type="1"/>
    <Variable Name="Total" Type="1"/>
  </Content>
</ZApplication>
User avatar
Kjell
Posts: 1915
Joined: Sat Feb 23, 2008 11:15 pm

Re: Recycling models, is it worth it?

Post by Kjell »

Hi Ats,
Ats wrote: Fri Feb 17, 2023 10:27 amSo I made a little working example, but I'm not happy with setting the Thing parameters in the general activateThing function. I would prefer them to be set in the model, so I don't have to search everywhere for that bit of code. But I can't seem to find how to simply do that :?
If you only need to reset a model you can put a CallComponent in Definitions and call that. Here's a simple example ( use left-mouse-button ).

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" FileVersion="2">
  <OnLoaded>
    <ZExpression>
      <Expression>
<![CDATA[// Spawn 4 boxes

for(int i=0; i<4; i++)
{
  BoxArray[i] = createModel(Box);
}]]>
      </Expression>
    </ZExpression>
  </OnLoaded>
  <OnUpdate>
    <KeyPress Keys="{" RepeatDelay="0.25">
      <OnPressed>
        <ZExpression>
          <Expression>
<![CDATA[// On left click "reset" all boxes by calling BoxResetCall

for(int i=0; i<4; i++)
{
  @CallComponent(Component: BoxArray[i].BoxResetCall);
}]]>
          </Expression>
        </ZExpression>
      </OnPressed>
    </KeyPress>
  </OnUpdate>
  <Content>
    <Model Name="Box">
      <Definitions>
        <CallComponent Name="BoxResetCall" Component="BoxReset"/>
      </Definitions>
      <OnSpawn>
        <ZExpression Name="BoxReset">
          <Expression>
<![CDATA[//

Box.Position.X = random(0, 8);
Box.Position.Y = random(0, 4);

Box.Rotation.X = random(0, 1);
Box.Rotation.Y = random(0, 1);

//

BoxColor.Color.R = 0;
BoxColor.Color.G = 0;
BoxColor.Color.B = 1;]]>
          </Expression>
        </ZExpression>
      </OnSpawn>
      <OnUpdate>
        <ZExpression>
          <Expression>
<![CDATA[// Animate color

BoxColor.Color.R += App.DeltaTime;]]>
          </Expression>
        </ZExpression>
      </OnUpdate>
      <OnRender>
        <RenderSetColor Name="BoxColor"/>
        <RenderMesh Mesh="BoxMesh"/>
      </OnRender>
    </Model>
    <Mesh Name="BoxMesh">
      <Producers>
        <MeshBox/>
      </Producers>
    </Mesh>
    <Array Name="BoxArray" Type="3" SizeDim1="4"/>
  </Content>
</ZApplication>
Alternatively you could use a condition that checks a variable from Definitions. Depends a bit on your model whether this makes more sense or not.

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" FileVersion="2">
  <OnLoaded>
    <ZExpression>
      <Expression>
<![CDATA[// Spawn 4 boxes

for(int i=0; i<4; i++)
{
  BoxArray[i] = createModel(Box);
}]]>
      </Expression>
    </ZExpression>
  </OnLoaded>
  <OnUpdate>
    <KeyPress Keys="{" RepeatDelay="0.25">
      <OnPressed>
        <ZExpression>
          <Expression>
<![CDATA[// On left click "reset" all boxes by setting BoxState to 1 ( reset )

for(int i=0; i<4; i++)
{
  BoxArray[i].BoxState = 1;
}]]>
          </Expression>
        </ZExpression>
      </OnPressed>
    </KeyPress>
  </OnUpdate>
  <Content>
    <Model Name="Box">
      <Definitions>
        <Variable Name="BoxState" Type="1"/>
      </Definitions>
      <OnSpawn>
        <ZExpression Name="BoxReset">
          <Expression>
<![CDATA[//

Box.Position.X = random(0, 8);
Box.Position.Y = random(0, 4);

Box.Rotation.X = random(0, 1);
Box.Rotation.Y = random(0, 1);

//

BoxColor.Color.R = 0;
BoxColor.Color.G = 0;
BoxColor.Color.B = 1;]]>
          </Expression>
        </ZExpression>
      </OnSpawn>
      <OnUpdate>
        <Condition Expression="return BoxState;">
          <OnTrue>
            <CallComponent Component="BoxReset"/>
            <ZExpression>
              <Expression>
<![CDATA[// Reset is done, set state back to 0

BoxState = 0;]]>
              </Expression>
            </ZExpression>
          </OnTrue>
        </Condition>
        <ZExpression>
          <Expression>
<![CDATA[// Animate color

BoxColor.Color.R += App.DeltaTime;]]>
          </Expression>
        </ZExpression>
      </OnUpdate>
      <OnRender>
        <RenderSetColor Name="BoxColor"/>
        <RenderMesh Mesh="BoxMesh"/>
      </OnRender>
    </Model>
    <Mesh Name="BoxMesh">
      <Producers>
        <MeshBox/>
      </Producers>
    </Mesh>
    <Array Name="BoxArray" Type="3" SizeDim1="4"/>
  </Content>
</ZApplication>
K
User avatar
Ats
Posts: 770
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: Recycling models, is it worth it?

Post by Ats »

Thanks Kjell. And with the addition of ModelState, the BoxReset in Box Model can then call substates with their own initialization, which is pretty neat.

Code: Select all

<OnSpawn>
  <ZExpression Name="BoxReset">
    <Expression>
      switch(CurrentModel.Box_Type) {
        case 0: @SetModelState(State:State_Box_Cube); break;
        case 1: @SetModelState(State:State_Box_Sphere); break;
      }
    </Expression>
  </ZExpression>
</OnSpawn>
But that rise a few questions... As I was merging all my FX into only one Model, I realized that some FX have a different RenderOrder or Category number, in order to display them correctly. Can I simply change those settings in the ModelStates, or will it change all the FX models in game, regardless of their ModelState?

And when I create explosions, a lot of FX Models are created. So I was wondering if, in the end, it is better to create and destroy them, or to have all those unused Models in game with a test on their OnUpdate and OnRender to check if they are alive or not, at each frame... I don't know.
User avatar
Kjell
Posts: 1915
Joined: Sat Feb 23, 2008 11:15 pm

Re: Recycling models, is it worth it?

Post by Kjell »

Hi Ats,
Ats wrote: Fri Feb 17, 2023 7:21 pmAs I was merging all my FX into only one Model, I realized that some FX have a different RenderOrder or Category number, in order to display them correctly. Can I simply change those settings in the ModelStates, or will it change all the FX models in game, regardless of their ModelState?
Never tried that before, but it seems like changing it on the fly works just fine.

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" FileVersion="2">
  <OnLoaded>
    <ZExpression>
      <Expression>
<![CDATA[//

for(int i=0; i<16; i++)
{
  float a = i*PI/8;
  float s = PI*2/3;

  SpriteColor.Color.R = sin(a+s*0)*0.5+0.5;
  SpriteColor.Color.G = sin(a+s*1)*0.5+0.5;
  SpriteColor.Color.B = sin(a+s*2)*0.5+0.5;

  Sprite.Position.X = sin(a);
  Sprite.Position.Y = cos(a);
  Sprite.Position.Z = i;

  createModel(Sprite);
}]]>
      </Expression>
    </ZExpression>
  </OnLoaded>
  <Content>
    <Model Name="Sprite" Position="-0.3827 0.9239 15">
      <OnUpdate>
        <ZExpression>
          <Expression>
<![CDATA[//

Sprite.Position.Z += App.DeltaTime;
if(Sprite.Position.Z >= 16)Sprite.Position.Z -= 16;
Sprite.Category = 15-floor(Sprite.Position.Z);]]>
          </Expression>
        </ZExpression>
      </OnUpdate>
      <OnRender>
        <UseMaterial Material="SpriteMaterial"/>
        <RenderSetColor Name="SpriteColor" Color="0.3087 0.9957 0.1956 1"/>
        <RenderSprite/>
      </OnRender>
    </Model>
    <Material Name="SpriteMaterial" Shading="1" Light="0" ZBuffer="0"/>
  </Content>
</ZApplication>
Ats wrote: Fri Feb 17, 2023 7:21 pmAnd when I create explosions, a lot of FX Models are created. So I was wondering if, in the end, it is better to create and destroy them, or to have all those unused Models in game with a test on their OnUpdate and OnRender to check if they are alive or not, at each frame... I don't know.
Pretty difficult to say what is better without doing benchmarks for your specific situation.

Regardless, a built-in flag mask ( or a couple of booleans ) that let's you enable/disable various events of a model ( Update / Render / Collision ) would have been convenient. Having to wrap everything into conditions gets tiresome quickly :wink:

K
User avatar
Ats
Posts: 770
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: Recycling models, is it worth it?

Post by Ats »

hahaha, another simple yet super explicit and colorful example of yours. Thanks.

For the benchmark, I'll do that when I'll finish fusing all the FX into one Model, now that I know Category can be changed without breaking everything. I'll just have to switch on/off the spool and run some tests.
Regardless, a built-in flag mask ( or a couple of booleans ) that let's you enable/disable various events of a model ( Update / Render / Collision ) would have been convenient. Having to wrap everything into conditions gets tiresome quickly :wink:
Just like the Disable Component option that only works in preview mode?
Post Reply