Another way of programming, taking it slow

Whenever I sit down to write some code, I always get an itch to finish whatever problem is staring me in the face right at that moment. Over the last 2 years, I’ve realized that if you can afford to tackle a problem over a long period of time, you should absolutely go for that option.

There are major benefits that arise from this approach. The final code ends up more developed than what you would have been capable of writing at the beginning. You end up spending less time on the actual problem, because you only work on it when you have a good idea. And, after sitting with it for so long there’s a good chance that even if not fully correct, it will still move you in the right direction. Taking it slow leads to an aha moment in the future along with the insight required to solve the problem.

I was inspired to write this article from an extreme example in my own code around making a prefab class for my entity system. When I first wrote the class, I had the intention to create it right then and there, but quickly realized I didn’t have the knowledge to do so. It required doing type specific operations on generic pointers, with no types!

A quick overview of an entity system & the root of the problem

Entities are made from sets of components. Components are made up of data. Ideally, they would be Plain Old Data classes, but more complex components that store data in dynamic memory are eventually required. This could be in the form of lists, maps, or things like shared pointers.

When copying a class in C++ we make use of the copy constructor, which takes care of these special cases by calling the copy constructors of the underlying containers, resulting in a deep copy.

Prefabs need to store a list of components and their respected data to spawn an entity in the future. The only way to store multiple types in a single list is to use generic void pointers. There is a fundamental problem that comes up frequently when using this practice; because of the use of voids, we dropped all knowledge of what type of data we are pointing to. When it comes time to spawn the entity, each component’s data needs to be copied into the entity system, but without type information there is no way to know which copy constructor to call, so we can’t make deep copies.

My process

I took the first stab at my prefab class in February, but only completed it a couple days ago in June! This was a non-critical, time saver class, so I could afford not to worry about it for several months while working on other stuff. I’m glad I waited though because it opened my mind to this new way of thinking.

I made the first real attempt in early June but was stopped yet again by a lack of type information. The prefab needed to store void*s in a list and copy them into other void*s in the entity system. The simplest way to do this is with a memcpy which works great for POD classes, but when a component requires a deep copy, it will miss most of the real data. Components that make use of containers or inheritance don’t get copied correctly because most of the data is behind pointers.

I got stuck at this point because it seemed impossible to get type information back from the void*s. I knew I was really close to having the solution, I just needed a way to deep copy void*s, but I couldn’t think of any way of doing that, so I put it on pause again.

Cut to 3 weeks later; I was working on a bug in the physics engine where lambdas were not getting copied correctly and finally had that aha moment. Forget about copying lambdas, what if I could use lambdas to do the copying? In the entity system there is a Component class that stores metadata like the name and size. I could just add a lambda to it that would call the correct copy constructor. A lambda with a completely generic signature could get created in a template function and called whenever a component needs to get copied.

This solution requires that at some point you use a template function in the entity system. That’s a fair price when the alternatives would require the user to create at least one more function for each component, or add to some list, etc. I love solutions that are completely behind the scenes. Why should the user need to worry about things this low level if all they are trying to do is spawn entities?

Here is the code that creates the lambda. When you register a component, it calls GetCopyFunc and gets the lambda that copies for that component type. This seems like a powerful concept that I want to explore further, the idea that you can call a template function once and store information from it in generic types, making it so there is no need to template further. You can see my attempt at this in the entity system in my engine.

using func_DeepCopy = std::function<void(void*, void*)>;

struct Component {
      ...
      func_DeepCopy DeepCopyFunc;
      ...
};

template<typename _t>
func_DeepCopy GetCopyFunc() {
     return [](void* ptr, void* data) {
               _t* p = (_t*)ptr;
               _t* d = (_t*)data;
               new(p) _t(*d); // Placement new is used because the mem in p is not guaranteed to be anything, but is already allocated
      };
}

Even though this prefab system took 5 months, I only spent around an hour or so on it. I think that the result is much better than anything that I could have written months ago. Because I had to live without a prefab system for so long, I got a good idea for what it really needed to do, instead of wanting a prefab system because it’s cool and guessing at the use cases. I also avoided doing any research apart from a single google search for how to make that lambda above that landed me at https://stackoverflow.com, which shows some other constructors.

I think that this style of coding is very powerful, and I want to try and use it in other places in my code more frequently. It seems hard to do though because you need something to work at some point, so I guess I’ll leave it to future aha’ed me to see if it works...

Comments

3 replies

The page margins on your blog on mobile are excessive.

Iain

Thanks! I missed a second layer of divs I added, now it lines up with every thing else

Leave a Reply

Your email address will not be published.

Other Articles

Making an infinite world with Falling Sand part 2

Welcome back to the sand series, this post directly follows from what we did last time, so if you missed that, here’s the link. In this post we’ll first split the world into chunks, then look at some ways to speed it up. Splitting the world into chunks The main feature that chunks allow for […]

March 27, 2021
Making games with Falling Sand part 1

I want to get familiar with the process of releasing a game before I finish Metal Sphere Rising, so I’m planning on making a game in a month, and then releasing it on Steam or something. My brother and I were talking about it and came up with the idea of a space version of […]

December 30, 2020
EPA: Collision response algorithm for 2D/3D

Last time we looked at an algorithm for testing collisions between two convex polygons called GJK. It’s a useful algorithm for sure, but it doesn’t give us enough information to respond to the collisions it detects. In this article I’ll describe an extension that allows us to find the correct normal and depth of the […]

November 17, 2020
Mesh generation

This post is less about some specific information and more about something I’ve been cooking up over at winter.dev/prims. When working in 3D everything is made out of meshes. In their simplest form these are big lists of positions that get fed into the GPU for rendering. These lists can be generated or loaded from […]

October 6, 2020
GJK: Collision detection algorithm in 2D/3D

In my last article, I only covered sphere vs. sphere collisions because they are the simplest to compute. Spheres are nice and all, but there comes a time when more complex shapes are needed. One popular algorithm for testing collisions is the Gilbert–Johnson–Keerthi algorithm, or GJK for short. With it we can detect collisions between […]

August 29, 2020
Designing a physics engine

By coincidence, right when The Cherno announced his game engine series I was just starting to get going on my own engine. I couldn’t wait to finally have a professional opinion on how to make one. With self-taught programming it’s hard to not doubt yourself constantly, wondering if you are doing things right or just […]

July 31, 2020
World 1 demo brings you to the outer forests

Calling all playtesters, After 2 months from the last playtest, the third demo is ready for review. This one brings the first real graphics to the game; with the addition of Voxel Cone Tracing there’s a warm glow to the whole forest. Right now that’s the biggest time sink per-frame so I am doing some […]

July 4, 2020

Projects

Game engine

IwEngine is an engine that I started as a way to lean about how computer games are made. Right now I am trying to make my first publishable game with it. I started by making something that was linear and story based and got about 50% done with it, but I wanted to try and publish something smaller and more arcade like first. That has turned into these sand games...

Mesh generation

Every shape has some method of generating a mesh for it, but there is no good central spot. This website will eventially contain a full list of differnt algorithms for every shape.

YouTube Subscriber tracker

Youtube removed the exact subscriber count. This resolves that issue and graphs my count ever hour.

Support

BY MAIL

Support with your eyes. I enjoy writing these posts and editing the videos that go along with them. It is very satisfying reading the comments and seeing people enjoying and hopefully learning something from what I make. Sign up to get an email notification for whenever I make a new post. It seems like my pace is around once a month, so don't worry about spam :)


ON YOUTUBE

Did you know I make video version of these posts? Check out the 5-10 minute condenced versions over on YouTube. I end up putting about the same amount of time into them as the posts themselves, so would appreciate a view!

ON TWITTER

Over on Twitter I post updates about videos while they're being made along with other random thoughts. If that sounds more your speed, I'd appreciate a follow :)