Search code examples
c#enumsswitch-statement

Generating a unique value using 2 different enums to act as cases in a switch statement


I am trying to make a collision system with multiple collider types (ie AABB and circle). A unique method for checking collision needs to be run for each type of collider. In order to determine the type I have given each collider an enum stating its type. Then when the program checks collisions it could compare their type and run the corresponding method for checking that type of collision.

I could do this using if else-if spam like so

if (colliderA.ColliderType == ColliderType.Circle && colliderB.ColliderType == ColliderType.Circle)
{
    // Check circle-circle collision
}
else if (colliderA.ColliderType == ColliderType.Circle && colliderB.ColliderType == ColliderType.Box)
{
    // Check circle-box collision
}
else if (...)
{
    // And so on
}

But this sucks for multiple obvious reasons most obviously being that it only checks if a is x and b is y but not the other case with the same outcome (a is y and b is x).

It makes more sense to use a switch statement with enums anyways but that leads to another issue of getting a unique number that represents the states of 2 different enums. I came up with a solution that works but has some weird issues that I don't like. My method to convert each enum to it's number representation and then bitshift the second enum to create a unique number.

int enumValue = ((int)colliderA.ColliderType << 8) + (int)colliderB.ColliderType;

This solution has two issues that are bothering me. The first is how difficult it is to read the code when done like this

switch (enumValue)
{
    case 1:
    case 256:
        // Both of these cases are for circle-box collisions
        // They are both far apart from each other and difficult to tell what they mean at a glance
        break;
}

I could do it like this but its also a little weird to read

case ((int)ColliderType.Circle << 8) + (int)ColliderType.Box:
case ((int)ColliderType.Box << 8) + (int)ColliderType.Circle:

This feels like something that would have a simple solution built into languages like C# (what I'm using) just like things like enum flags, but even if it's not I feel like there still must be a general way to do what I'm looking for in an efficient and readable way. Can anybody give me some pointers?

TLDR: Given two enums is it possible to generate a unique number that represents both their states (where inputs (A, B) and (B, A) give the same output)


Solution

  • You can make the enum constants have powers of 2 as their values, and use bitwise or to combine them into a single enum value.

    Example:

    // You can optionally add the [Flags] attribute to this
    enum ColliderType {
        A = 1,
        B = 2,
        C = 4,
        D = 8
        // and so on
    }
    
    ...
    
    ColliderType combinedType = collider1.Type | collider2.Type;
    
    switch (combinedType) {
        case ColliderType.A | ColliderType.B: // this is the same value as ColliderType.B | ColliderType.A
            ...
            break;
        case ColliderType.A | ColliderType.A: // or just ColliderType.A, depending on what you find more readable
            ... 
            break;
        // and so on
    }
    

    Alternatively, if you cannot modify the enum, you can make a tuple to represent the pair of collider types:

    var combinedType = (collider1.Type, collider2.Type);
    
    switch (combinedType) {
        case (ColliderType.A, ColliderType.B):
        case (ColliderType.B, ColliderType.A):
            ...
            break;
        // and so on
    }