Sunday 11 June 2023

React Physics 3D : First Impressions

With my home engine coming to the state of being able to visually represent a world and move about within it, I've decided to set about sorting out a physics representation.

Very much as I did with the mathematics where I set about writing all my own code and then adopting a library; in order to best learn the process from first principles I also set about writing my own physics engine and visualizer (the latter using the much more familiar to me fixed function pipeline of DirectX 9 - Yes it still has a use in 2023!)

The physics implementation I went with was a simple rigid body test for cuboids and spheres.  Then a ray cast.  At which point I set about seeking a library as it's a huge topic I didn't want to sink too much time into.

I settled, after about a fortnight of reading and trying on React Physics 3D.

My initial impressions are that it is easy to set up, supports CMake and just worked; though I'm yet to fully get to grips with it, I am happy I have my world and simulation set up and working.

I've also happily separated my game objects from my visual objects with the use of my Ecs and I'm able to do the same, by registering a new Ecs update system with my entity list and simply piping the commands to create and destroy physics objects per frame.

The update pumping of time matches my engine instantly, so I had a lot of wins.

However, I am not building in a permissive manner, I have maximum warnings as errors, I have strictness on and permissive off; I also remove all compiler specific extensions, so I am using only C++ in it's rawest, most portable form.

Immediately, even though I've compiled React separately and then just link to the library statically, I have a bunch of the React headers giving me errors; notably map, BroadPhaseSystem and DefaultLogger.

The first two are the same sort of issue, which just surprised me, there's a constexpr uint64 set to minus one (so it's max) an unsigned value set to a signed negative to under roll it... Well it's quite bad practice:

static constexpr uint64 INVALID_INDEX = -1;

And I immediately updated this to:

static constexpr uint64 INVALID_INDEX { std::numeric_limits<uint64_t>::max() };

I may feed this back to the author, he most likely knows, maybe there's even a reason for it, personally I'd always stick to numeric limits and max in this case though, not least as it is constexpr and not a hack ;) 

The other one was a lambda expression in a call to std::transform for making all logging strings lower case, the code simply used ::tolower.  However, it was not type safe, it was converting int to char, but that's not explicit and so I changed it over to read:

std::string toLowerCase(const std::string& text) {
                std::string textLower{ text };
                std::transform(textLower.begin(), textLower.end(), textLower.begin(), [](const char& character) -> char { return static_cast<char>(std::tolower(character)); });
                return textLower;
            }

The lambda here is hard to read, so lets split it out:

[](const char& character) -> char 
{
    return static_cast<char>(std::tolower(character));
}

We take in a character, return a character, explicitly, so we have to cast the int return of std::tolower... simple really, but hard to read.  It compiles down well; but just using "::tolower" well that's a decay to int and you have to be permissive in your type exchange... I don't like that, express yourself in your code type correctly, and it'll be type safe.

No comments:

Post a Comment