4 ms·
Experienced modern game programmers would never write a "Duck" class though. For instance, in Unity, it would be a set of small components representing narrow b
by overgard 7y ago
Experienced modern game programmers would never write a "Duck" class though. For instance, in Unity, it would be a set of small components representing narrow behaviors attached to a generic scene graph object. So the "Duck" would only exist as a data object that happens to have maybe a unique Quack component, along with a lot of common non-duck components like MeshRenderer, AudioSource, Collider, RigidBody, etc. You would see similar things in something like Unreal, or even in-house engines. The implementation is likely also to be way more interested in acting on aggregate data streams rather than enforcing strict encapsulation and object boundaries and such.
It's still very OOP, but not in the sense of representing real-world taxonomies.
I know there's an argument that this real-world metaphor is good for beginners, but at least in my personal experience I don't think that's the case. I remember when I was a kid, my dad tried to teach me coding with a lot of object oriented examples with like Cats and Dogs and stuff. He was really well meaning, but it never really made sense to me. I only kind of "got it" when I did something nobody would recommend anymore, and learned QBasic, and wrote a bunch of ghastly code with goto's all over the place and practically everything being a global. Awful code, but 10 year old me was able to reason about that a lot easier than polymorphism/encapsulation/scoping/etc.
- eckza 7y ago> I only kind of "got it" when I did something nobody would recommend anymore, and learned QBasic, and wrote a bunch of ghastly code with goto's all over the place and practically everything being a global. An aside: It's okay to learn that way, when you're 10. A lot of my own big programming revelations have come from ignoring best practices and accidentally trying to implement or construct them from first principles once my problem becomes unmanageable. "Doing it wrong" is an even better teacher than "doing it right all of the time", because the mistakes you make can lead you to a deeper understanding of why things are done a certain way.
- overgard 7y agoTotally agree. I think we make a mistake trying to harp on doing things "right" too much for new programmers, because they end up with analysis paralysis.
- TeMPOraL 7y agoThat's my current approach to teaching people programming concepts. I try to provide an example of not using that concept, point out the quickly growing complexity of the code, and then show how that complexity can be reduced with the new concept I'm introducing. (And yes, as a kid, I was hurt by all those "Cat : public Animal" examples too. It took me many years before I figured out why they didn't work in practice for me.)
- abricot 7y agoI think this is why you often see people reinvent GOTO. Everyone who started with BASIC (and moved on) knows why you won't do that any more. But someone today starting with python might not understand. [replace GOTO with any bad example]
- ben509 7y agoTBH, I haven't written any real games, and the simulation work I do is in finance, so if we have an account, it's really just an account. But securities and accounts and such are all well-defined abstractions that lend themselves very well to direct representation in code, so my experience is not representative. Maybe it's possible to be less misleading, but I still think it's a mistake to try to write a tutorial that tries to present basic concepts in the fashion that production code is written. There's just so much stuff you do in prod that is not relevant to the concepts you're trying to convey. > I only kind of "got it" when I did something nobody would recommend anymore, and learned QBasic, and wrote a bunch of ghastly code with goto's all over the place... I learned on a C64 when I was a kid, too. I'd absolutely recommend learning structured imperative programming before OOP.
- morelisp 7y ago> It's still very OOP, but not in the sense of representing real-world taxonomies. 1. OOP was never about "representing real-world taxonomies." 2. Real-world taxonomies are often not very good at representing real-word taxonomies. Programmers are highly susceptible to scientism, and it's ruined whatever chance OOP had of being a tool rather than an ideology.
- DonHopkins 7y agoBoth Unity and COM use aggregation instead of implementation inheritance to compose bunches of small sub-objects together. Unity has the notion of components (inheriting from MonoBehaviour => Behaviour => Component => Object), which can be multiply attached to GameObjects (inheriting from Object), that you can switch between with gameObject.GetComponent<ComponentClass>(). COM has the notion of multiple interfaces to the same "controlling unknown" object (analogous to GameObject), that you can switch between with QueryInterface. https://docs.microsoft.com/en-us/windows/win32/com/aggregation https://docs.microsoft.com/en-us/windows/win32/com/aggregati... https://flylib.com/books/en/3.357.1.89/1/ https://flylib.com/books/en/3.357.1.89/1/ http://www.369o.com/data/books/atl/0321159624/ch06lev1sec5.html http://www.369o.com/data/books/atl/0321159624/ch06lev1sec5.h... https://en.wikipedia.org/wiki/Object_composition#Aggregation https://en.wikipedia.org/wiki/Object_composition#Aggregation They're basically the same idea, but slightly different in the details and implementation. COM is essentially C++ pure virtual interfaces implemented by one or more concrete classes using multiple inheritance (like the way Java lets you multiply inherit interfaces, but only singly inherit classes). Different COM interfaces can refer to the same shared C++ implementation object, or separate delegate objects, and "tear off" objects created on demand. Unity's component model is implemented in C#, but isn't an essential language feature of C#, just a way of using it to implement aggregation.
- kragen 7y agoFrom your point of view, are GameObjects in Unity an implementation of entities from the entity–component–system pattern, or is there a difference?
- DonHopkins 7y agoThere are some abstract similarities, but neither COM nor Unity GameObjects/Components are an "implementation" of that pattern, since they were both invented a long time before 2007 when Adam Martin defined ECS in "Entity Systems are the future of MMOG development": http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-of-mmog-development-part-1/ http://t-machine.org/index.php/2007/09/03/entity-systems-are... ECS builds on top of some of the ideas of COM and GameObject/Component, but loses much of the baggage, takes it much further in a different direction, and has a lot of other advantages, like storing the data in separate contiguous cache-friendly buffers. https://en.wikipedia.org/wiki/Entity_component_system https://en.wikipedia.org/wiki/Entity_component_system >In naïve ECS implementations, every system iterates through the complete list of all entities, and selects only those entities that are needed. The total iteration cost for all systems becomes too costly if the number of systems grows or the number of entities is large. In other ECS architectures, every component type is stored in a separate list, so whatever systems operate on a given type of component are only iterating over objects they care about by default. In this common ECS architecture, the described disadvantage actually becomes a major performance advantage, by more efficiently leveraging the CPU instruction and data caches. http://t-machine.org/index.php/2014/03/08/data-structures-for-entity-systems-contiguous-memory/ http://t-machine.org/index.php/2014/03/08/data-structures-fo... >Net effect: Contiguous memory is King >If you store your data contiguously in RAM, it’ll be fast onto the Bus, the CPU will pre-fetch it, and it’ll remain in cache long enough for the CPU(s) to use it with no extra delays. >NB: this is independent of the programming-language you’re using. In C/C++ you can directly control the data flow, and manually optimize CPU-caching – but whatever language you use, it’ll be compiled down to something similar. Careful selection and use of data-structures will improve CPU/cache performance in almost all languages Also: Entity–component–system (ECS) back and forth (skypjack.github.io): https://news.ycombinator.com/item?id=19166910 https://news.ycombinator.com/item?id=19166910 Entity Component System Framework that is CPU cache friendly: https://stackoverflow.com/questions/23473783/entity-component-system-framework-that-is-cpu-cache-friendly https://stackoverflow.com/questions/23473783/entity-componen... Designing a cache-friendly entity component system: https://cerulean-skies.com/index.php?article=1 https://cerulean-skies.com/index.php?article=1 Unity is rolling out a new officially supported entity component system that's a totally different stack than GameObject/Component. (But they interoperate, of course.) https://docs.unity3d.com/Packages/com.unity.entities@0.1/manual/index.html https://docs.unity3d.com/Packages/com.unity.entities@0.1/man... One (but not the only) fundamental difference between COM and GameObject/Component, is that you query for COM interfaces with an interface GUID, so you can only have one interface on an object for each GUID. But Unity lets you slap as many of the same component class on an object as you like. The singular Component GetComponent<ComponentClass>() method will just return the first one, but the plural Component[] gameObject.GetComponents<ComponentClass>() returns an array of all the components of the given class. For example, it is useful to attach several different Colliders to the same GameObject (each with its own position/size/shape/etc). They all just work together as you would expect. A RaycastHit will identify which Collider was hit, as well as the sibling Transform of the GameObject it was attached to. Another fundamental difference is that with GameObject/Component, each GameObject and component is always a completely separate independent object, but COM allows the implementation class to implement any number of different interfaces with the same instance (using C++ multiple inheritance, so each interface implementation has its own vtable pointing back to the same implementation class's different methods), or delegate to other sub-objects using "aggregation", or even make sub-objects lazily on demand with "tear-off interfaces".