5 ms·
Being a game developer, inheritance is a really important language feature. I'm not one to abuse the power. Currently, for school I've been working on an OpenGL
by snake_case 12y ago
Being a game developer, inheritance is a really important language feature. I'm not one to abuse the power. Currently, for school I've been working on an OpenGL game engine in C++. It's a component based system. The only real inheritance situation that's important to me, is to allow the user of the engine to create any object and make it inherit from GameObject (example: Duck would inherit the members and methods from the GameObject class). Everything else is a component that plugs into GameObjects (Mesh component, Transform component, etc.)
Over Christmas break, I played around with Rust and I'm really enjoying it. However, I can't figure out a nice way to inherit members from other structs. My current idea, like many others, is to keep a pointer to a "parent" object. So, Duck would have a GameObject, rather than be a GameObject.
Does anyone have any recommendations for better ways I can achieve what I would like to do? I will also accept the fact that inheritance is not needed in a language, but it does make a few situations easier.
- steveklabnik 12y agoSomething that addresses your concern is coming post 1.0. Servo needs something like inheritance to model the DOM efficiently. It may or may not end up looking like inheritance, though. We determined that our possible solutions are backwards compatible, so we are doing it post 1.0, though. (Oh, and Rust doesn't get everything Servo needs, what I mean to say is "Servo has demonstrated that there is real-world need for something like inheritance, and so we will add it.")
- snake_case 12y agoThat's exactly what I wanted to hear! I heard some mumbles about inheritance coming back in one way or another, mostly on GitHub issues I believe. Can't wait to see what comes of that!
- Rusky 12y agoIf you want closer performance characteristics and simpler use patterns, in the meantime, storing the parent GameObject by value rather than through a pointer might be easier.
- snake_case 12y agoFor some reason I had pointers on the mind. You're right, no real use for pointers in that scenario. Storing by value makes more sense.
- yoklov 12y agoI'm a game developer and I don't use inheritance a lot, and when I do use it it's almost never for virtual dispatch. (I wouldn't mind it being added to Rust, but I don't expect I would use it). Anyway, if you're already doing a component based system, why do you need inheritance? Just do a normal ECS. You don't subclass GameObjects in most implementations of ECS (and this is a good thing).
- dman 12y agoECS - http://en.wikipedia.org/wiki/Entity_component_system http://en.wikipedia.org/wiki/Entity_component_system (Just trying to save a lookup for others)
- snake_case 12y agoI guess I should do some more research regarding that. Although, I just liked the idea of inheriting from a base "empty" game object. It makes it easy to have lists of GameObjects. Also, all of my components inherit from a Component class which makes it possible to AddComponent() and GetComponent(). That way, a user of the game engine could create a new type of component and easily add that to any game object. However, I may be over complicating that as well...
- ossreality 12y agoI think you're making it way more generic than you want. even if you get that working, you're going to hate coding in that codebase. Great, a list of objects that could literally be anything in the game. Now what?!
- yoklov 12y agoHonestly, it sounds like you are over-engineering this... Forgive me if I'm wrong, but the impression I'm getting here is that you're writing the engine before the game. Never do this. Just don't. What you should do instead, is write a game, and while writing that game, write its engine. At the same time (Or even, write a game, and then refactor the engine out as you go). Then, after you're done, that engine can then be extracted and made to be more generic. This is basically how every engine used in the game industry was made (although in many cases the game the engine was written with never shipped). Trying to make a generic engine from the start will be worse in basically every measurable way. It will take longer to write, take more code, use more memory, and be slower... Again, sorry if I misjudged your comments. Anyway. On to what you said specifically: Having an empty base object so you can have lists of GameObject (presumably lists of `GameObject*` in reality) is basically going to destroy performance and the cache. A reasonable rule of thumb is that a read from memory will take about 100 times longer than, say, a float multiplication, unless you know it will be in the cache. Then, to operate on these game objects, you'll probably use virtual methods. Another rule of thumb is that vtables are basically never in the cache (and they're also unpredictable branches). Really what you want to have is several flat arrays of the data each part of the engine needs to operate on. This is also good from an encapsulation standpoint, because then each part of the engine only can see what it needs, and not necessarily the whole game object. Then, the way you'd implement a component system in this style is that you'd make that array the canonical place the data lives. This can work well for some games but isn't worthwhile for every game. (Generally I actually think the biggest benefit is that it makes gameplay and tools for non-developers easier to write.)
- Jare 12y ago> Duck would have a GameObject, rather than be a GameObject Duck should not be a class, it should be a factory function that creates a generic GameObject and configures it with the set of components that allows it to look, walk and quack like a duck.
- JoshTriplett 12y agoCan you elaborate on the reasons for that?
- Jare 12y agoOnce you move to components, these implement all the game-related behaviour and the GameObject becomes a simple piece of scaffolding to hold components together. You don't gain anything by making different GameObject code-level classes that only differ in the components they contain (there may be a debate in the case of languages that support mixins). It's also much easier to data-drive entity types; at some point you will even do away with factory functions for GameObject types and describe these types in data files loaded at runtime. This opens up options for designer-friendly editing tools and even 3rd party modding.
- snake_case 12y agoThis also is a good solution to my problem. Thanks!
- tomlu 12y agoSolution: Don't inherit from GameObject. Make GameObject "final" and simply be a container of components. Move all object-specific behaviour into the components.
- snake_case 12y agoBut, I still need inheritance. DuckComponent would need to inherit from Component in order for my GameObject to add that to the list of components attached. Am I wrong?
- yuriks 12y agoThis sounds like the exact case where you'd use a trait.
- snake_case 12y agoYes, I think you're right!
- tomlu 12y agoYou'd use interfaces (or a similar behaviour-indirection mechanism like function pointers). In Rust I suppose you'd use a trait.