1
0
Fork 0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-12-23 01:59:43 +01:00

Optimize entity collision checking to O(n)

I noticed that if I have a large amount of entities in the room, the
game starts to freeze and one frame would take a very long time. I
identified an obvious cause of this, which is that the entity collision
checking in entityclass::entitycollisioncheck() is O(n²), n being the
number of entities in the room.

But it doesn't need to be O(n²). The only entities you need to check
against all other entities are the player and the supercrewmate. You
don't need to "test entity to entity" if 99% of the pairs of entities
you're checking don't involve the player or supercrewmate.

How do we make it O(n)? Well, just hoist the rule 0 and type 14 checks
out of the inner for-loop. That way, the inner for-loop won't be
unconditionally ran, meaning that in most cases it will always be O(n).
However, if you start having large amounts of duplicate player or
supercrewmate entities (I don't know why you would), it would start
approaching O(n²), but I feel like that's fair in that case. But most of
the time, it will be O(n).

So that's how collision checking is now O(n) instead.
This commit is contained in:
Misa 2020-09-07 16:36:38 -07:00 committed by Ethan Lee
parent d4336b9a33
commit 662a658cf6

View file

@ -4651,12 +4651,16 @@ void entityclass::entitycollisioncheck()
for (size_t i = 0; i < entities.size(); i++)
{
if (entities[i].rule != 0)
{
continue;
}
//We test entity to entity
for (size_t j = 0; j < entities.size(); j++)
{
if (i!=j)
{
if (entities[i].rule == 0 && entities[j].rule == 1 && entities[j].harmful)
if (entities[j].rule == 1 && entities[j].harmful)
{
//player i hits enemy or enemy bullet j
if (entitycollide(i, j) && !map.invincibility)
@ -4685,18 +4689,18 @@ void entityclass::entitycollisioncheck()
}
}
}
if (entities[i].rule == 0 && entities[j].rule == 2) //Moving platforms
if (entities[j].rule == 2) //Moving platforms
{
if (entitycollide(i, j)) removeblockat(entities[j].xp, entities[j].yp);
}
if (entities[i].rule == 0 && entities[j].rule == 3) //Entity to entity
if (entities[j].rule == 3) //Entity to entity
{
if(entities[j].onentity>0)
{
if (entitycollide(i, j)) entities[j].state = entities[j].onentity;
}
}
if (entities[i].rule == 0 && entities[j].rule == 4) //Player vs horizontal line!
if (entities[j].rule == 4) //Player vs horizontal line!
{
if(game.deathseq==-1)
{
@ -4724,7 +4728,7 @@ void entityclass::entitycollisioncheck()
}
}
}
if (entities[i].rule == 0 && entities[j].rule == 5) //Player vs vertical line!
if (entities[j].rule == 5) //Player vs vertical line!
{
if(game.deathseq==-1)
{
@ -4738,7 +4742,7 @@ void entityclass::entitycollisioncheck()
}
}
}
if (entities[i].rule == 0 && entities[j].rule == 6) //Player versus crumbly blocks! Special case
if (entities[j].rule == 6) //Player versus crumbly blocks! Special case
{
if (entities[j].onentity > 0)
{
@ -4754,10 +4758,19 @@ void entityclass::entitycollisioncheck()
}
}
}
if (game.supercrewmate)
}
}
}
if (game.supercrewmate)
{
for (size_t i = 0; i < entities.size(); i++)
{
//some extra collisions
if (entities[i].type == 14) //i is the supercrewmate
{
for (size_t j = 0; j < entities.size(); j++)
{
//some extra collisions
if (entities[i].type == 14) //i is the supercrewmate
if (i != j)
{
if (entities[j].rule == 1 && entities[j].harmful) //j is a harmful enemy
{