Skip to content

Instantly share code, notes, and snippets.

@Rseding91
Created March 19, 2025 09:28
Show Gist options
  • Select an option

  • Save Rseding91/aecc426adc32039844f6d43bf3f3c63f to your computer and use it in GitHub Desktop.

Select an option

Save Rseding91/aecc426adc32039844f6d43bf3f3c63f to your computer and use it in GitHub Desktop.
How asteroids spawn
void SpacePlatform::spawnAsteroids()
{
const bool randomOrientation = this->speed < 0.2;
if (SpaceLocationID locationID = this->position.getCurrentLocation())
for (auto& spawnDefinition : locationID->asteroidSpawnDefinitions)
this->trySpawnAsteroid(spawnDefinition.asteroid, spawnDefinition.chunk, spawnDefinition, randomOrientation);
else
{
const PointOnSpaceConnection& pointOnConnection = this->position.getPointOnConnection();
for (auto& spawnDefinition : pointOnConnection.connection->asteroidSpawnDefinitions)
this->trySpawnAsteroid(spawnDefinition.asteroid, spawnDefinition.asteroidChunk, spawnDefinition.interpolate(pointOnConnection.distance), randomOrientation);
// Spawn SpaceLocation asteroids on space connections if the platform is in the location's sphere of influence.
this->spawnAsteroidsOnConnectionNearEndPoint(**pointOnConnection.connection->from, pointOnConnection.distance);
this->spawnAsteroidsOnConnectionNearEndPoint(**pointOnConnection.connection->to, 1 - pointOnConnection.distance);
}
}
void SpacePlatform::spawnAsteroidsOnConnectionNearEndPoint(const SpaceLocationPrototype& endPoint, double distanceFromEndPoint)
{
if (distanceFromEndPoint < endPoint.asteroidSpawnInfluence)
for (const SpaceLocationAsteroidSpawnDefinition& spawnDefinition : endPoint.asteroidSpawnDefinitions)
this->trySpawnAsteroid(spawnDefinition.asteroid,
spawnDefinition.chunk,
Math::lerp<AsteroidSpawnPoint>(spawnDefinition,
AsteroidSpawnPoint(0, 0, spawnDefinition.angleWhenStopped),
Math::inverseLerp(0.0, endPoint.asteroidSpawnInfluence, distanceFromEndPoint)),
!this->isMoving());
}
void SpacePlatform::trySpawnAsteroid(EntityID entityID, AsteroidChunkID asteroidChunkID, const AsteroidSpawnPoint& data, bool randomOrientation)
{
static constexpr uint32_t BASE_SPAWNING_AREA = 1024;
double probability = this->getAsteroidSpawningArea().getWidth().getDouble() + this->getAsteroidSpawningArea().getHeight().getDouble();
if (!randomOrientation)
probability += this->getAsteroidSpawningArea().getWidth().getDouble() * this->speed * 10;
else if (!this->position.getCurrentLocation())
probability *= 0.1; // Reduce asteroid spawning for platforms which stopped mid-route.
probability *= *this->map.mapSettings->asteroidSettings.spawningRate / BASE_SPAWNING_AREA * data.probability;
randomOrientation |= this->speed < UtilityConstants::instance().asteroidSpawningWithRandomOrientationMaxSpeed;
for (; probability > 1; --probability)
this->spawnAsteroid(entityID, asteroidChunkID, data, randomOrientation);
if (this->map.getRandomGenerator().testChance(probability))
this->spawnAsteroid(entityID, asteroidChunkID, data, randomOrientation);
}
SimpleBoundingBox SpacePlatform::getAsteroidSpawningArea()
{
const SimpleBoundingBox& asteroidSpawningOffset = UtilityConstants::instance().asteroidSpawningOffset;
return SimpleBoundingBox(this->platformBoundingBox.leftTop.x + asteroidSpawningOffset.leftTop.x,
this->platformBoundingBox.leftTop.y + asteroidSpawningOffset.leftTop.y,
this->platformBoundingBox.rightBottom.x + asteroidSpawningOffset.rightBottom.x,
this->platformBoundingBox.rightBottom.y + asteroidSpawningOffset.rightBottom.y);
}
@FelipeCavichiolliSilvestre
Copy link
Copy Markdown

FelipeCavichiolliSilvestre commented Jul 31, 2025

In what unit is the platform speed? km per tick?
Trying to get a grasp on asteroid rates

@Rseding91
Copy link
Copy Markdown
Author

Yes, km per tick.

@FelipeCavichiolliSilvestre
Copy link
Copy Markdown

Thanks!

@crouleau
Copy link
Copy Markdown

When an asteroid spawns at a stationary platform, does it strictly spawn on the edges of the square defined by asteroidSpawningOffset?

Also, does it spawn with a fully random direction of travel, or is it restricted to some cone such that it won't immediately exit the active area? Is it possible, for example, to spawn an asteroid near the bottom-left corner and have it travel at -45 degrees and exit almost immediately? Could it spawn traveling at +180 degrees exit immediately?

Thanks so much!

@crouleau
Copy link
Copy Markdown

crouleau commented Mar 26, 2026

FYI, I did some testing. I found that it is possible to capture ALL (or at least, nearly all) asteroids that spawn. Using the formula for asteroid spawn rate (where L and W are the length and width of your space platform):
asteroid_rate_per_minute = 90 * (L + W + 72 + 48*3) / 1024
I get a theoretical asteroid spawn rate for Nauvis orbit. (Note: the '90' is the sum of metal/carbon/oxide asteroids from the wiki, https://wiki.factorio.com/Nauvis)

I made a "+ shaped" station that just collected asteroids and tossed them overboard. I used L=48 and W=48.
image
Then I ran a 10 hour sped-up test in the editor, and I got 17.8 metal/min, 12.1 coal/min, and 6.0 ice/min, or a total of 35.9/min. the the asteroid_rate_per_minute calculation is 38.86/min. So this means I am probably capturing every asteroid that spawns, and that therefore the random velocity that asteroids get is set in some way such that they head "generally" toward the space station.

Finally, I ran a test where I had a long line of collectors on one axis (W=96, L=4). In this config I captured only 91.4% of the theoretical asteroids over 10 hours, and I could see many asteroids crossing the full width of the screen without ever getting close enough to the station.
So it seems that it is possible to capture all asteroids as long as the station is large enough on two axes. It's not clear to me if symmetry is important or not.

Thanks to u/ahydra447 for the post on https://www.reddit.com/r/factorio/comments/1jnzf44/indepth_details_about_asteroid_spawning/ which was very helpful in doing this experiment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment