Montag, 27. April 2015

HowTo#1 Avoid inflexible several if else statements/ switches

There are sometimes situations when you want to check an object and depending of the object you want a corresponding result, so you have some kind of mapping. Therefore you want to check the input if it is this or that etc. To be more specific let's consider the following situation:

void ProcessSomething(Color color) {

    FlowerType flowerType;

    if (color == Color.Red) {
        flowerType = Red_Rose;
    } else if (color == Color.Blue) {
        flowerType = Blue_Rose;
    } else if (color == Color.Grey) {
        flowerType = Grey_Rose;
    } else if (color == Color.Yellow) {
        flowerType = Yellow_Rose;
    }  

    // Do something
}

Obviously this is a bad style and leads to inflexible code, but what is the alternative? You could use a switch statement, but this wouldn't lead to a more elegant code.
If you have some kind of mapping for example between Enums, you can do the following:

// Java
public static enum Color {
    Red, Blue, Grey, Yellow;

    private static EnumMap map = new EnumMap(Color.class);

    static {
        map.put(Color.Red, FlowerType.Red_Rose);
        map.put(Color.Blue, FlowerType.Blue_Rose);
        map.put(Color.Grey, FlowerType.Grey_Rose);
        map.put(Color.Yellow, FlowerType.Yellow_Rose);
    }

    public static FlowerType getCorrespondigValue(Color value) {
        return map.get(value);
    }
}
// Apparently there is a bug with the syntaxhighlighter
// In line 5 the correct version is "FlowerType"
// And it adds  in the end, probably it has a problem with "<"

In the case of Enums we can use an EnumMap and use a static block to map the corresponding types. As a result we have a neverchanging and flexible static getCorrespondigValue method, which returns reliably the FlowerType. If you don't use Enums you can use instead of EnumMap a HashMap.


Here is an extract from my Pokemon game in C++ Unreal Engine:
// C++
static TMap MapNameEItemEnum;

UENUM(BlueprintType)
enum class EItemEnum : uint8
{
    Potion                 UMETA(DisplayName = "Potion"),
    Pokeball             UMETA(DisplayName = "Pokeball"),
    Superball            UMETA(DisplayName = "Superball"),
    None                UMETA(DisplayName = "None")
};

static void init()
{
    MapNameEItemEnum.Add(FString(TEXT("Potion")), EItemEnum::Potion);
    MapNameEItemEnum.Add(FString(TEXT("Pokeball")), EItemEnum::Pokeball);
    MapNameEItemEnum.Add(FString(TEXT("Superball")), EItemEnum::Superball);
    MapNameEItemEnum.Add(FString(TEXT("None")), EItemEnum::None);
}


EItemEnum GetCorrespondingStringAsEItemEnum(const FString Str)
{
    EItemEnum* Item = MapNameEItemEnum.Find(Str);

    if (Item)
        return *Item;
    else
        return EItemEnum::None;
}
// Again a bug with the syntaxhighlighter in line 2
// "FString, EItemEnum" is the correct version

Of course you can use the same concept in normal C++, if you don't work with Unreal Engine. Note that there are no simple static blocks in C++ like in Java.



Dienstag, 21. April 2015

Unreal Engine 4 - Pure virtual functions

Unreal Engine 4 - Pure virtual functions

This is a little guide for everyone who tries to make use of pure virtual functions in Unreal Engine:

You cannot simply create an abstract UCLASS(), because Unreal Engine expects every UClass Element to be instantiable. Therefore you have to use the PURE_VIRTUAL macro. This is a small extract from my current Pokemon game I'm working on:

UCLASS(abstract)
class UE4POKEMON1_API ABaseActor : public AActor
{
    GENERATED_BODY()

protected:
    virtual void SetupAssets() PURE_VIRTUAL(ABaseActor::SetupAssets, ;);
    ...
}

You can mark the UCLASS as abstract. In this case "SetupAssets" is a void function so after the comma after the declaration "ABaseActor::SetupAssets" in PURE_VIRTUAL, you can leave it free. If you have any other return type for example int32: you can write "return 4;".
You don't have to implement the function in the .cpp file, but you have to pay attention, if you try to call that function from the constructor. If you do this, the following error occures:

"Pure virtual not implemented"
 To avoid this you can call this function in BeginPlay() (not that elegant) or in the constructor of the deriving class (better).