|
Josh @ Dreamland
|
|
Reply #31 Posted on: May 10, 2010, 02:08:12 pm |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
I meant that other developers are mythological creatures. But yes, as far as ENIGMA is concerned, components still seem unrealistic to me as well.
|
|
|
Logged
|
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble "I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
|
|
|
Rusky
|
|
Reply #32 Posted on: May 10, 2010, 03:26:42 pm |
|
|
Joined: Feb 2008
Posts: 954
|
draw_sprite would call a method on a sprite object. It has nothing to do with components.
In the component system, you don't even need to know the bottom tier. You just make a class and give your object a member of that type. Components can be organized in the file system exactly the same way as tiers.
Changing those core systems out at runtime makes more sense in debug/build mode. You could have build mode draw handles on the objects that let you move them. You could capture audio events and show them in a log window. You could trigger a pause on certain events (collision, for example) that pulls you back into build mode. I can easily imagine you wanting to turn these on and off for the game or even for individual objects while the game is running.
None of these debug mode things would have anything to do with the final exe. I've explained this before- just because you can switch them on and off at runtime doesn't mean they have to be included at runtime. Because you swap a pointer instead of a flag, the actual debug code can exist completely separately. No bit flip for debug mode. It's all gone in the release build.
There is no single debug component here, either- each system has the potential to behave differently in debug mode- build mode controls, logging, user-controlled breakpoints, etc. Each of these systems can be implemented as a wrapper component that takes a reference to the one it's modifying. When you switch on one of these systems, the debugger can replace the object's component pointer with one to its new debug version of that component. It's just like your hypothetical debug_proxy<> but for systems and switchable at runtime.
Component wrapping doesn't change the behavior of components. It adds something to it. Functions will still behave the way users expect; the only difference is that the debug system gets notified. Now, in some situations it would be great to change the way those functions work. You could turn off audio by switching to a null audio component. You could switch off certain graphical effects during build mode and then turn them back on when you're done.
Reusable behaviors was a suggestion for a new Enigma feature, something that doesn't exist in GM. Sometimes, plain old inheritance isn't good enough when you're sharing behaviors. Take a multiplayer game and say you wanted to support hotseat and networked. Each player might be controlled by an AI, the keyboard or packets coming across the network. Rather than writing three classes for each ship or character or whatever, you could make one that uses a movement control component. Then, you could hook up the input component you want at runtime. For an example of this system in real use, check out Construct.
I wasn't saying components would make dependency resolution easier; I agree that they make it harder. However, it forces you think about what those dependencies really are, and you can reuse that work on new systems like reusable behaviors. Yes, you have to implement the components with the built-ins in mind, but it's the same thing with tiers. If you need yet another method of finding component locals, try this- look up the members of the Component members of your object. Looking up names in parents is just as much work as looking up names in *Component-type members.
I don't see how components have the same problems as the pre-tier system. It makes things far more decoupled- you should never have to include Object unless you're actually dealing with one. The idea would be to try to use only components when possible, which would limit recompilation. Beyond that, you you try to use the component the highest up the hierarchy, which limits it further. If you only need SpriteComponent, you wouldn't include RasterSprite, and there would be no recompilation. On the other hand, if you need something from RasterSprite, you're going to have to recompile when it's modified whether you're using tiers, components or something else.
I know Enigma isn't just a GM clone. That's my point- rather than just adding functions (which can be done through extensions) or tacking on C++ (which doesn't help the overall framework one bit), I'm suggesting ways that you could actually improve on GM's paradigm. Extra pointers are just a means to this end. Components are just a way to make things less dependent on each other. When you make that smaller dependence explicit in the code by only operating on components rather than Objects, you get a more flexible system.
Ism: What is it exactly you think is unrealistic?
|
|
|
Logged
|
|
|
|
|
Rusky
|
|
Reply #34 Posted on: May 10, 2010, 04:41:48 pm |
|
|
Joined: Feb 2008
Posts: 954
|
Rather than inheriting locals and having systems access objects as the parent type they need, locals are in separate objects, with the main object holding pointers to these components.
With tiers, replace one level of the inheritance hierarchy and you end up changing the whole type from there on down to the actual object. Components, on the other hand, operate with member pointers to interfaces and can be replaced less disruptively.
Accessing certain parts of an object in the tier system means a cast to the parent type. The idea with components is to just take a reference to the component you need, preferably just the interface. Then you can switch out the component being used to change an object's behavior.
To keep a GM-like interface, components require a bit more work because locals generally aren't in Object anymore, they're in some member of Object. The way it works in my example is by giving Object a set of accessor methods so that .x() will give you sprite.x by reference.
Or does that not have anything to do with your question?
|
|
|
Logged
|
|
|
|
Josh @ Dreamland
|
|
Reply #35 Posted on: May 10, 2010, 06:18:38 pm |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
Rusky, your argument has started a motion towards how everything wrong with the component system is wrong with the tier system, and that's a big part of what I've been saying from the start. Now we've established that dependency resolution is harder with components; that doesn't help me.
"Looking up names in parents is just as much work as looking up names in *Component-type members." You're getting this from where? My system parses C++; it, by design, HAS to traverse structures' parents to gain insight into members. All I have to do is invoke that same system, not invoke some hackish loop for any membered types beginning with "component_". I can name the tiers whatever I want; if it's inherited, it's already implemented.
Reusable behaviors are nice for users; not for me, and I assume not for other developers. Other developers should design the system with special purposes in mind. General behavior code -> Hasty generalizations about what the code should do -> Haste -> Waste.
As a proposal for a way to help users out, components are great, and I will probably look into an implementation. However, they only serve to clutter engine code; all the examples you named (especially handles in build mode), I have already planned to implement using a more general means. Since the compiler structures events into their respective member functions, I can insert anything I want. This is how vector/force variables such as hspeed, vspeed, gravity, etc. are handled. I truly have no personal need for components.
I'd prefer debug behaviors be preprocessed out; that's how they work in var, which only complains on undefined access and checks for division by zero during debug. However, I do understand the beauty in using functions for some such options; aborting on non-fatal errors is handled using a function at the moment, but that was because of laziness and I will eventually look for a way to remove the need to do so.
I also know how useful function pointers are; I've used them since R1 to enable room create codes. Instead of making each room a structure, they all share one which is assigned a create code on load time. It's relatively low-cost considering how infrequently rooms are changed.
Now something I will be using function pointers for in the future is allowing users to compile new objects into a DLL, then linking in that DLL with a system vaguely resembling your component system; each new object provides a function pointer which calls the constructor of the new object struct; that function is called on create, and it adds itself to the instance lists flawlessly, which takes care of the rest. "The rest" being event execution and instance iteration.
I know I'm hard on new proposals and it can be indistinguishable from ignorance, but I'm not lost in any of this. I've had a plan for a long, long time, regardless of how long its taking to realize it. Components weren't a part of this plan; they'd grossly slow me down and require a deal of recoding. Not to mention there's still considerations of how much should be included in your parent component object so functions like sprite_add can be reused; it doesn't seem possible without adding another--yes--tier. For instances where some code can be shared, but others can't be, I mean. The system just isn't ideal enough for me to say, "components are the way to go!"
|
|
|
Logged
|
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble "I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
|
|
|
Rusky
|
|
Reply #36 Posted on: May 10, 2010, 07:07:00 pm |
|
|
Joined: Feb 2008
Posts: 954
|
Yes, your system parses C++. The thing is, Enigma isn't C++. Tiers are a semantic part of the system- I'm assuming the way you remove/change them is in some control panel. Enigma is more than just a C++ library, so why is it a problem to add/change semantics? You already did that when you decided to parse GML.
Reusable behaviors are nice for users. That should be a good reason to implement them. The point of Enigma is not to be easy on you, it's to help users in making their games. A system should be pretty near impossible before you start considering implementation difficulty over usefulness.
Saying that everything should be designed with the system's specific purpose in mind is ridiculous, and you've completely gone against it anyway. If you were to take your own advice, you would design EDL with Enigma in mind, not just stick another language on GML. This idea completely blows away any concept of libraries (which you use), compilers (which you use) and even microprocessors in general. Libraries (which can take the form of reusable behaviors) are designed with generality in mind, so they can be adapted to more situations.
Debug behaviors with components would still be preprocessed out. The difference is that they're more flexible at runtime. How are you planning to implement those things in a more general way? Components make debug mode completely separate from the rest of the engine; they can be dropped in and out with only the debug code knowing about them, even through the preprocessor.
If you were okay with accessors for built-ins, components would be even more powerful. The interface component would just give a list of required accessors, akin to C# properties. Implementations could work any way they wanted, storing as much or as little as needed. Of course, that would require an extra couple of CPU cycle per access, which is a problem even though we can run a space shuttle with a 1Mb, 1.2Mhz embedded processor.
|
|
|
Logged
|
|
|
|
Josh @ Dreamland
|
|
Reply #37 Posted on: May 10, 2010, 09:41:21 pm |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
I read this line from you: "Saying that everything should be designed with the system's specific purpose in mind is ridiculous, and you've completely gone against it anyway." And I remembered this line from you: "The built-ins go in Object, and you know which component to look in because, as built-ins, the whole system will be implemented with them in mind." And I wasn't really sure what to make of your argument anymore, but I'll continue anyway. Libraries are designed quite specifically, but tend to include a lot of options. GL offers hundreds of functions, many redundant, for things so simple as drawing points. glVertex[2-3][f,i,d]... It's general as a whole, yes, but the functions are designed for operating specifically. GL is actually pretty bloated compared to, say, GX, which is an ugly system expecting exactly a pre-specified format and freezing if it doesn't get it. I actually prefer it that way; it's how I know exactly what's being done for me. But that's beside the point.
"ENIGMA isn't C++..." Yes, a semantic aspect is required to allow switching tiers. It's like that in both systems; the tier system just greatly reduces it as I can generate a list of all locals from only the name of the uppermost tier. Even with a list of all your components, I couldn't just traverse their contents; the point of your components is to extend outward from themselves, as tiers do. That is the only way they save compile time; when none are edited, only extended. How am I to keep track of all the extensions? I can't. I'd require the developer to name them all in a file. Sounds like a pain to be a developer.
There's a control panel of roughly five items so far to specify semantics. More will soon be read from individual files in each folder under Graphics_Systems and Platforms, mostly to inform the user of which options are available and give them a brief description. The files so far have no bearing on how code is compiled.
Also, my goal has been for a while now to move ENIGMA closer and closer to C++. The way R4 is geared, only three items of GML will be changed to migrate to C++. 1) Semicolons and other punctuation will be added. ENIGMA is more tolerant than GM in that "for ;;;" parses to "for (; ; );", among other such items. 2) Switch statements will be hijacked to allow for switching floating point values and strings. Additionally, they will be replaced with if-else combos if case labels are not constant (This is what GM does always). 3) Dot based accessing (x.y) will be replaced with an accessor function if x is not an instance of a structure containing y. Additionally, variables in with() statements will be prepended with enimga::withiter-> or similar.
Other than that, EDL and C++ are indistinguishable with the current configuration.
If you think I'm going to extend the C++ language for ENIGMA developers (as in, those working ON, not WITH Enigma), well, I'm not. ENIGMA is C++, regardless of how many things I'm adding to the language for EDL. ENIGMA's system is not written in EDL. There are no with()s in the instance functions, no variant types in the object code, and least of all, no C# properties in the tier system.
"Reusable behaviors are nice for users. That should be a good reason to implement them. The point of Enigma is not to be easy on you, it's to help users in making their games. A system should be pretty near impossible before you start considering implementation difficulty over usefulness." My argument wasn't "it's difficult, therefore it's not worth it." In fact, it was my impression that said argument hurts you more. "Reusable behaviors are nice for users." You're advocating them because they are nice... for users. But they aren't nice for me? ENIGMA being so close to C++, how can what helps the users fail to help me?
The users aren't making direct use of the component system if it is used only by the compiler as a method to switch systems, now are they? So how does that help the users? This is why I thought it was to help me. To help developers in general. That ENIGMA would be gloriously easy to extend for all developer, myself included. Because all you have to do now is enumerate all the possible components and pass one as a flag to all the instances you are creating instead of just adding a single, nasty, old #define in there. So which is it? Whose life is this improving?
Most will never even know how ENIGMA organizes its lower systems, much less need to know. Of course, here I'm using your premise "Reusable behaviors are nice for users" instead of that the system will be a pain in the ass to implement but that it should be the developers' (aka, my) job to grin and bear it for the "users." Which users, exactly? What will users do knowing that their objects are component based instead of tier based?
The only way that what you're saying isn't self-contradictory is if you're trying to imply that my parser life becomes difficult, but that it will make the system much easier to develop for later. That's not true, either. Just naming the bottom tier in a text file called configure would suffice for me, maybe giving a description after it and lower tiers, all optionally. Your system requires that all components and all possible component extensions that may implement variables be named, that I may actually collect a sufficient list of locals for the accessors. And any way you try to contort your idea, I still need that list. That's a real pain in the ass for myself and any developers. With tiers, you just extend them and go. In fact, I'll already have a planar and intend to have a spacial tier in. Developers will just extend the one they require (planar for 2D, spacial for 3D, some new one if neither apply) with an alternative graphics system, or extend the current graphics tier with a new collision system (like box2D). I don't cater to games that want to implement a 3D mesh rendering tier but wish to use Colligma, a pixel-perfect, 2D collision system, on top of that. How would such a system make sense? You or miky gave an example of a game that used vector graphics but still wished to use Colligma. Well, I don't know why, but okay; the tier system would require recompile of collision functions (Colligma is separate in both cases) because the sprite tier was edited; your system, at this point, would also, as Sprite/RasterSprite would no longer be used. Where's the gain?
At this juncture, most of the benefits you've proposed once upon a time (such as swapping out graphics systems on runtime) you have dropped, without warning and with little regard afterward. Those that you have not are slowly unraveling as I demand more code. Here I'll ask for instance_nearest. Here's mine:
#include <math.h> #include "var_cr3.h" #include "planar_object.h"
int instance_nearest(int x,int y,int obj) { double dist_lowest=-1,retid=-4; int objind=(int) obj; double xl,yl; for (enigma::instance_iterator=enigma::instance_list.begin(); enigma::instance_iterator != enigma::instance_list.end(); enigma::instance_iterator++) { if ((*enigma::instance_iterator).second->object_index==objind) { xl = ((enigma::object_planar*)enigma::instance_iterator->second)->x; yl = ((enigma::object_planar*)enigma::instance_iterator->second)->y; const double dstclc = hypot(xl,yl); if (dstclc < dist_lowest or dist_lowest == -1) { dist_lowest = dstclc; retid = (*enigma::instance_iterator).second->id; } } } return retid; } I'm interested to see where the name of the component and location of the instance comes from.
|
|
|
Logged
|
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble "I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
|
|
|
Rusky
|
|
Reply #38 Posted on: May 10, 2010, 10:46:30 pm |
|
|
Joined: Feb 2008
Posts: 954
|
The components would be designed for the GM-like system, of course. But they're also designed with extra extensibility in mind, so that you can use them for more than just GM compatibility. What I'm saying is that while you should design with your goals in mind (how else would you design?), designing for only those goals in a tool that's supposedly extensible makes no sense. Libraries and tools are not designed for one specific use case, and reusable behaviors are just another library. I don't see what the problem is.
"Reusable behaviors are nice for users; not for me, and I assume not for other developers." What on earth does this mean if not that you want the system to be nice for you as a developer of Enigma? You said yourself that Enigma isn't written in EDL and you're not extending C++ for Enigma developers. Thus, the component system is nice for the users and not for you. You've already extended semantics for users with things like GM objects and with statements, why is this all of a sudden different?
You never have to pass components to all the instances you create. I don't know where you got that idea; my example code keeps all the component choices inside OBJ_object0. I've also explained over and over where you could get a list of members from. I'll explain again what I think is the best way in detail: components would have header files meant to be included where the component would be used. You would put a #include line in either Object or a specific OBJ_*. It would declare a component and all the accessors you need to use it. No extra name lookups, no extra text file to parse, and it's all defined using C++ semantics.
Once you hit reusable behaviors, the users will absolutely be making direct use of the component system. What would start as a way to switch systems (which would help the user anyway in debug mode) could be extended to a way to reuse code without as much duplicated work. When they make a new behavior, they'll be making a new component. The compiler would handle the hooking together, making Enigma "gloriously easy to extend for all developers."
I don't see how my proposed benefits are being dropped. Which ones have I dropped? Which ones are "unraveling?" Swapping out graphics systems wouldn't generally make any sense, sure. But swapping out a layer on top of it to draw build mode handles or enable and disable stuff while you're editing the level makes perfect sense. Turning on and off different systems for different objects or catching certain events also makes perfect sense. Reusable behaviors as another method of organizing code make perfect sense.
Here's instance_nearest:
#include <math.h> #include "var_cr3.h" #include "Object.h"
int instance_nearest(int x, int y, int obj) { double lowest = -1, ret = -4; for (enimga::instance_iterator = enigma::instance_list.begin(); enigma::instance_iterator != enigma::instance_list.end(); enigma::instance_iterator++) { if (enigma::instance_iterator->second->object_index() == obj) { double xl = enigma::instance_iterator->second->x(); double yl = enigma::instance_iterator->second->y(); const double dstclc = hypot(xl, yl); if (dstclc < lowest || lowest == -1) { lowest = dstclc; ret = enigma::instance_iterator->second->id(); } } }
return ret; } Object has whichever component keeps track of x and y #included, which gives it its component and accessors. It's nearly identical to yours. You could also get enigma::instance_iterator->second->that_component at the beginning of the loop and then access them directly if you wanted. These kinds of functions are not where components make a difference.
|
|
|
Logged
|
|
|
|
Josh @ Dreamland
|
|
Reply #39 Posted on: May 10, 2010, 11:01:53 pm |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
"You've already extended semantics for users with things like GM objects and with statements, why is this all of a sudden different?" There's a difference between adding a file of information for informations' sake and implementing a system that I don't like and that no one will ever see.
You've "explained over and over" progressively improving ideas, all of which were slop until this one, which is much, much better, and is in fact a plausible method at this point.
"When they make a new behavior, they'll be making a new component" Yes. Why does this require that the underlying systems likewise be component based instead of tier based? So the actual C++ can continue to be ugly as fuck? And yes, x() is still fuck-ugly compared to just x. At least it's not one of certain other language's long-winded jobs... The rest of ENIGMA, up to this point, save switch() and the innards of with(), is identical to C++. I wouldn't object to coding in ENIGMA without the parser, it remains that simple. And you want to add () to everything.
And I wouldn't even venture a guess at how many users would "absolutely be making direct use of the component system." The count stands at six presently; I imagine it will eventually end up about where map<> users will, if not even worse off. You're assuming that a community derived mostly from that of GM will be as enamored with the system as you, rather than as much so as me. I'd implement it above the tier system just for them, though. But you'll have to really justify the lower systems, the ones in question, being components if you expect me to recode all of that.
Which proposed benefits you've dropped is relatively unclear; among them are swapping out systems at runtime, which you dropped long ago. Others include, and this is ambiguous; how much better-organized components are than tiers, when components are a bigger bitch to resolve dependencies for. Tiers can only have one alignment; I don't see how you can beat that in organization. You keep trying to resurrect the idea that components can be easily "turned off", but when confronted you return to the realization that it will leave mess.
Now, regarding your instance_nearest code, we have a dilemma. You included Object.h: do you regard that as a mistake? That means that if you wish to add a new type of component, you're recompiling anything that makes use of any component's implemented locals. The tier system was designed specifically to avoid that. If you're not using the planar tier, your game isn't 2D, and you're not using instance_nearest. That's the concept. I can't really add or remove pointers now, except if the user implements one in a derived class from Object. Wasn't this one of the huge things components avoided?
|
|
|
Logged
|
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble "I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
|
|
|
Rusky
|
|
Reply #40 Posted on: May 11, 2010, 09:07:59 am |
|
|
Joined: Feb 2008
Posts: 954
|
Nobody would see the component system (without behaviors), but nobody would see the tier system either. What they see is the results, and the component system gives better results.
I've explained the same ideas, just in progressively more detail because apparently I'm really bad at getting what I mean across. Just because I didn't bring up all these details doesn't mean I didn't have them in mind from the beginning.
What's so ugly about components? Adding () to members is just to keep GM compatibility; parsed C++ is really just intermediate code that nobody should see in normal use. Generated assembly is often pretty ugly when judged by human standards, but it works and you don't really see it in normal use.
You don't have to write behaviors to use the component system either. I'm fairly sure that being able to drag and drop "platform physics" onto an object and just tweak its numbers would be useful to plenty of GM users.
I never dropped swapping systems at runtime. I was just talking about it with debug mode. While you may not want to swap core systems like GL/DX or the collision engine, the graphics or audio engines would be great to be able to filter/swap/drop. Components are better-organized than tiers because separate behaviors are more separated from the main Object. Rather than being parents, where a change screws up the object's type (polymorphically), components are members that only operate through interfaces. Rather than casting Objects to their tiers, you could just take a reference to their component and have nothing to do with Object at all. Disabling a component works just fine. Replace them with a null component that does nothing. The only reason this wouldn't save as much space as tiers is that you object to non-inline accessors, which would let null components actually not have the built-in members. This solution is also safer; it's harder to accidentally cast to a tier that doesn't exist and segfault your game. It would just not do anything rather than exploding.
For instance_nearest, Object.h doesn't have the actual component implementations. It only uses the interfaces. Changing RasterSprite or whatever component actually implements the coordinates wouldn't affect Object.h. The idea is to design a minimal interface that doesn't need to change to implement GM's library, and let the actual systems that use extra stuff be the only code that knows about anything beyond the interface.
|
|
|
Logged
|
|
|
|
|
Josh @ Dreamland
|
|
Reply #42 Posted on: May 11, 2010, 11:50:09 am |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
"What they see is the results, and the component system gives better results." <<Components are better because they give better results. They give better results because they are better.>> For the purpose of the underlying systems--sprites, collisions, etc--the systems give the same results. No user will know the difference.
"What's so ugly about components? Adding () to members is just to keep GM compatibility;" Yes. Except, my system doesn't require the (), it's as close to GM as possible by nature.
"You don't have to write behaviors to use the component system either. I'm fairly sure that being able to drag and drop "platform physics" onto an object and just tweak its numbers would be useful to plenty of GM users." Aware. That leaves the question, "what is this improving, then?" And yes, the system you describe would be quite nice. I was going to do this with templates--not in the C++ sense, but in the sense that you just include a prescripted engine, perhaps via a wizard with its own scripting language. I'd prefer such be separate from the real code.
"Components are better-organized than tiers because separate behaviors are more separated from the main Object." You included "Object.h" just to implement instance_nearest. Don't give me any bullshit. If I decide to add a tier pointer, your ass will be recompiling everything that uses a single local, just like my system before tiers. That set of functions requires two tiers in my system; so long as your game is 2D and uses instances, you won't need to recompile; and in the case that it is, you probably don't need instance_nearest, and it won't help you.
"This solution is also safer; it's harder to accidentally cast to a tier that doesn't exist and segfault your game. It would just not do anything rather than exploding." I'd prefer it explode--That's how I know I've done something wrong.
"For instance_nearest, Object.h doesn't have the actual component implementations. It only uses the interfaces. Changing RasterSprite or whatever component actually implements the coordinates wouldn't affect Object.h. The idea is to design a minimal interface that doesn't need to change to implement GM's library, and let the actual systems that use extra stuff be the only code that knows about anything beyond the interface." The same is true for tiers. Objects include the tiers only to know the locations of locals. The sources are compiled independently.
|
|
|
Logged
|
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble "I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
|
|
|
Rusky
|
|
Reply #43 Posted on: May 11, 2010, 12:55:26 pm |
|
|
Joined: Feb 2008
Posts: 954
|
I've already explained how components give better results. You can't claim circular reasoning if you don't pay attention to my arguments. For the purpose of debugging with the underlying systems, components will give either better results or at least better organize the system to make modifications simpler and faster.
Code reuse through templates and wizards isn't really code reuse. It's copy-paste. Templates also can't be combined very easily or changed at runtime. Think about Mario- he would have platform physics, but also different power-up states- nothing, mushroom, flower, star, etc. Then what about when you have both Mario and Luigi? They both behave exactly the same way, with slightly tweaked physics and different sprites. How would you accomplish this without making several different object types?
Why does it matter how close the underlying system is to GM? Even C, with structs and functions and scope, is pretty far away from the underlying machine code. Why is it useful to separate the higher-level logic from the "real" code? The logic exists at some level, why not in the "real" code? What matters is how well the system is organized and how well it works.
Why would you decide to add a component pointer? The pointers would all always be there, pointing at no-op components if they're not in use. The key is interfaces, not just pointers. Those no-op components could be rigged to explode instead of not doing anything if you wanted. They could be rigged to explode in any way you want, not just a segfault or strange behavior. They could tell you exactly what you did wrong rather than just that you did something wrong. Either way, some people would rather that it not explode in release mode.
|
|
|
Logged
|
|
|
|
Josh @ Dreamland
|
|
Reply #44 Posted on: May 11, 2010, 01:24:07 pm |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
In GM, you would create object Character and then have objects Mario and Luigi inherit from that, incorporate a jump_height in Character so Luigi's can be higher than Mario's, as well as setting a sprite_base, then call inherited event if need be. Granted, GM's gross system of resource ID-ing could inhibit that sprite_base idea. That can be worked out later (LGM already has some features for that).
Does it truly matter how close the end result is to the EDL? No, not really. But if I get it close enough, I can let users choose to stop relying on the parser and do their coding entirely in C++, which would be an interesting opportunity to leave open. Besides, should they choose to start developing their own C++ functions, having to put an () after all the variables would be required and is annoying.
The path system is a great example of a waste of a component/tier. It implements some seven variables for its own purpose, using only about two from other tiers/components. I could think of a hundred additional systems I can do that with. Paths, and any systems like them, would be best suited to components because they have very little dependence on anything else. Paths incorporate their own speed variables, their own index variable; the only thing they really need from other tiers is x and y. Paths, and components like them about which the system is not designed, are a good reason to add a component pointer.
Of course, my component pointer would be done somewhat differently than yours. Because I understand that I am in control of the layout of object, the pointer would be achieved by making the compiler instantiate the path component inline. As in, say the path component contained path_index, path_position, and path_speed. Those three would be added in-place into the structure by the compiler, and the component pointer would be taken by casting the (Object::*) to (PathComponent*), which would be non-virtual.
The lower tiers, on the other hand, including graphics and collisions, I have denounced all your reasons to use components for. They will be of no more use to me in debugging than preprocessor expressions and a separate folder for debug object files. They only serve to complicate dependencies since they are all ground level, and they don't improve performance in any way. Not to mention that they make code ugly.
|
|
|
Logged
|
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble "I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
|
|
|
|