Creating the lightest type of Actor possible?

I want to throw out a lot of slow-moving projectiles in my game, which are basically just single particles with a bare minimum of functionality.

Unfortunately you can’t really “show” anything in the game at a certain location without an Actor it seems, and once you get about 1000 moving actors the game starts chugging apparently due to CPU rather than GPU.

So I’m interested in making an Actor subclass be as light as possible, such that it only supports things like moving around with SetLocation, displaying a particle component, and being available for DynamicActors queries, that means no physics at all and really nothing besides what I’ve mentioned.

Any ideas are very welcome.

Another thing that comes to mind is maybe using a textured quad static mesh instead of a particle component, but I’m still interested in the idea of optimizing the actor itself as much as possible, as it’s a very heavy class to subclass.



class UDNEnemyBullet extends Actor;

var bool cullable, disabled;
var vector z_trans, go_vector;

DefaultProperties
{ cullable = true;
bCollideActors = false;
bProjTarget = false;
bBlockActors = false;
bCollideWorld = false;
bNoEncroachCheck = true;
BlockRigidBody = false;
CollisionType = none;
}

simulated event Tick(float dt)
{
SetLocation(Location + go_vector);

Super.Tick(dt);
}


simulated singular event Touch( Actor Other, PrimitiveComponent OtherComp, vector HitLocation, vector HitNormal )
{
return;
}

simulated singular event Bump( Actor Other, PrimitiveComponent OtherComp, Vector HitNormal )
{
return;
}


I’m also interested in this topic.

In my game I allow players to build structures out of modular pieces, where each piece is an actor.

On some of the dedicated servers I have seen up to 20,000 pieces placed on the map without much impact on performance.

I’m not sure, but I believe Physics has the largest impact on CPU, and I have that set to PHYS_None on my “building piece” actors.

I also use the foliage system to create static mesh instances for their meshes, rather than them each rendering their own static mesh component, which saves a ton of draw calls. You can see the performance result of that if you scroll down on this update, where I show an fps comparison (10x performance boost).

Thank you for the info. I’ve set Physics=PHYS_None and CollisionType=COLLIDE_NoCollision but didn’t see much of a difference so it seems I’ve sufficiently crushed physics already. I may have to look into using static mesh quads and instancing, though making the base actor lighter would be nice too if possible.

If you don’t need collision or physics for these projectiles, can’t you just have a single actor spawn all the visual particles needed and manage their movement (or just configure a single emitter to do all of this)?

It sounds like perhaps it’s the particles themselves that are causing the slowdown rather than the owning actors??

That’s true, I’m mostly staying away from that because of all the codebase changes it would cause plus I’m not sure how I would get one emitter to show particles at two different locations, if I still use one particle component for each bullet then it’s not too much of a performance gain, but it’s still worth looking into.

This is what we have in our touch function




if ( (Other == None) || Other.bDeleteMe || bShuttingDown ) // Other just got destroyed in its touch?
  return;

// don't allow projectiles to explode while spawning on clients
// because if that were accurate, the projectile would've been destroyed immediately on the server
// and therefore it wouldn't have been replicated to the client
if ( Other.StopsProjectile(self) && (Role == ROLE_Authority || bBegunPlay) && (bBlockedByInstigator || (Other != Instigator)) )
{
   ImpactedActor = Other;
   ProcessImpact(Other, OtherComp, HitLocation, HitNormal);
    ImpactedActor = None; } 
} 

this is our ProcessImpact() function




/** * The paintball has hit something. Apply damage and play appropriate effects. */ 
simulated function ProcessImpact(Actor Other, PrimitiveComponent OtherComp, Vector HitLocation, Vector HitNormal)
{
   local TraceHitInfo HitInfo;

    // Get HitInfo for the impact point
    HitInfo = TraceBallImpact(HitLocation, Velocity);

   // Don't apply damage to static objects or pawns that are already dead
   if ( !Other.bStatic && ((PBPawn(Other) == none) || !PBPawn(Other).IsInState('Dying')) ) 
     Other.TakeDamage(Damage,InstigatorController,HitLocation,MomentumTransfer * Velocity, MyDamageType, HitInfo, self);

   // Place the effect or decal depending on the object hit
   if ( (PBPawn(Other) != none) || (SkeletalMeshActor(Other) != none) )
      PlacePaintballEffect(HitLocation, HitNormal, HitInfo, Other);
   else PlacePaintballDecal(HitLocation, HitNormal, HitInfo);

   // Play the impact sound
   if ( !bSuppressSounds )
   {
      if ( (HitInfo.PhysMaterial != none) && (HitInfo.PhysMaterial.ImpactSound != none) )
        PlaySound(HitInfo.PhysMaterial.ImpactSound,,,,HitLocation);
      else if (ExplosionSound != None )
        PlaySound(ExplosionSound,,,,HitLocation);
    }

bSuppressExplosionFX = true; // so we don't get called again 
Shutdown();
} 

Remember to set this to get rid of the decals that are on stuff after so long. Within 10 to 15 minutes of play you will get lag that gets worse as you play. This is caused by you not getting rid of the decals after so long then to many are in the map and cause lag.

Setting



DurationOfDecal=180.0//in 3 minutes decal is cleared 

I set that in ours to stop the bad lag after 10 minutes of play by having to many decals on surfaces. I test that a lot and 3 minutes seemed pretty good to stop the lag. If your experiencing lag turn that down to less time.