Infinite Runner Obstacle Spawning best practices?

As the title implies, I’m working on an infinite runner-style game. The longer it goes, the harder it gets, and things are coming together pretty nicely as development continues. I’m at the point where I’m starting to look at optimizing and fine-tuning the events that can play during gameplay, and I was hoping to do some brain-picking/ discussing on how some others have approached this style of game.

Basically, I’ve got four groups of things that might spawn in the player’s path: Coins, enemies, obstacles, and ramps. They’re spawned in the player’s path with a combination of timers and random numbers, with how long the player’s been playing factored in. For example, the enemy that tries to cut the player off and get in their way will spawn every 10-15 seconds, but as you progress it might spawn as part of a group size that’s been randomly decided.

As the game gets more crowded, things get less clean. Coins start to spawn inside obstacles, the safe paths through the crowd get smaller, or even vanish entirely. One change I’ll be implementing this week is to have enemies collide and destroy themselves against obstacles, but I wanted to take a step back to the bigger picture from a design perspective and make sure I’m approaching this from the right angle.

I’m not really looking for technical and code specifics, this is more of a design discussion, but id be happy to provide code if the conversation winds up heading that way. Thanks a lot for the feedback, devs.