Josh @ Dreamland
|
|
Reply #45 Posted on: March 31, 2010, 05:27:54 pm |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
How can you specify a blank draw component? Just a pointer to a dummy? In either case, the tier system is implemented and doing a fabulous job. Rebuild for an additional tier or two isn't much to ask when you already have to rebuild one, especially considering the total build time for the entire project, fully optimized, isn't far past 20 seconds. At this point, I don't see much to gain, even at the cost of only a pointer (That system shouldn't require an accessor if it's including its own structure; I'm still not even considering accessors).
Also, I never claimed that GM games all run at 7fps. I showed that that's what can happen. 5,000 isn't an unreasonable number of lines; GM couldn't manage it 10 fps, ENIGMA wasn't even phased by it. It doesn't matter how they'd be accomplished in GM; GM users are used to working around its incapability. I started a 3D Metroid clone once; couldn't import my model; found a way to, but it ran at 2FPS because of it (where it rendered at 60 in the editor). Ended up rendering it ahead of time and drawing it as a cheap overlay. Looked horrible. All the walls had to be flat... It was sad. But I was happy with it, because it was the best I could do in GM.
miky: The way I see it, the amount of flexibility I'd gain from this system over the tier system isn't really enough to justify any sort of speed loss whatsoever. Maybe the extra pointer dereference if it really brought anything to the table in the long run. I'd much rather put the doubling of workload on the compiler.
|
|
« Last Edit: March 31, 2010, 05:31:08 pm by Josh @ Dreamland »
|
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 #47 Posted on: March 31, 2010, 07:04:31 pm |
|
|
Joined: Feb 2008
Posts: 954
|
5000 may very well be an unreasonable number of lines if you're not using hardware acceleration of some kind. In GM you could use the particle system, line lists or models. While Enigma is faster, that doesn't mean all that much. Anyone can come up with a giant computation problem and say "look, this runs faster compiled." Also, again, GM wasn't designed for 3D, engine or editor. I understand the reasons for the demo, but it would make more sense to outdo GM without using it badly.
If you want removable systems you have to sacrifice something. You seem to favor imperceptible speed improvements over flexibility, for some reason. A component system is a vast improvement in flexibility over a tier system, at the cost of a single extra pointer dereference when accessing members from outside an object:
More precise code reuse- tiers only let you use specific, pre-made combinations; components would let you pick any possible set of systems to include. Components would be more share-able between different types of objects.
Minimal recompilation- if all your components are already there and you don't change any code to use the new components, the only change is the object's constructor.
Better organization- engine code will be partitioned much more obviously into graphics code, collision code, etc. instead of being all in one object (this one's not that big though, as a lot of the subsystems would be in the tiers anyway).
Possibility of runtime configuration- you would be able to switch systems mid-game. While that's not so important with things like GL v DX in the graphics subsystem, it's huge with things like instance_change or new mechanics only possible with a new system (for example, AI states could be components rather than giant switch statements if the system were exposed to the programmer).
Decorators- debugging would be insanely easy. You could make "decorator" components that wrap other components to do things like logging, enabling/disabling specific behavior at runtime and implementing build mode on top of the normal object behavior. These debugging features could be completely removed in non-debug mode without a bunch of ugly #ifdefs- it would all be in completely separate files and the only change would be the affected objects' constructors.
|
|
|
Logged
|
|
|
|
Josh @ Dreamland
|
|
Reply #48 Posted on: March 31, 2010, 07:13:32 pm |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
More precise code reuse- Shouldn't matter in a compiled system; anything unused that's declared in a structure will simply be ignored. Just include the highest tier you need shit from. Minimal recompilation- As I said, I'd rather double or even triple the compile time when a recompile is necessary (it will be necessary at about the same time for both systems) than double the clocks needed to look up a local. Even if doubling it is as little as one more dereference. Better organization- No, the tiers do that, too. Each tier gets its own header and, if necessary, source file. Possibility of runtime configuration- Not even slightly interested. I don't see how it helps instance_change, either: with the tier system, instance change is a memcpy(y,x,sizeof(highest tier)) followed by more specific code that the component system wouldn't avoid. In fact, component system makes instance_change slightly more complicated (The compiler would likely take care of the complications, though, if we had a method in each one that could be inlined). Decorators- What could possibly stop me from doing that with the tier system? It seems the key difference between us is that you want to move as much as possible to run time, where I want to do just the opposite.
|
|
|
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 #49 Posted on: March 31, 2010, 07:46:55 pm |
|
|
Joined: Feb 2008
Posts: 954
|
Code reuse- what on earth does that have to do with anything? Selecting the highest tier you need is the problem- tiers imply a specific order to things you can have and not have. With graphics and physics, you would end up having to make only one removable without the other. With components, you pick exactly what systems you want. Instead of a drop-down menu or something of "core, graphics, physics", "core, graphics", "core", you could select each of core, graphics and physics separately for every possible combination. With the right interfaces, these components could work entirely separately.
Recompilation- compile time is rather large as it is. A simple GM game takes only a second or so to compile, and it doesn't grow much with extra code, only resources. Because you have to parse the GML, compile it and then link it all, the amount of code matters a lot more. Long compile times get completely unusable- they're one major reason people use scripting languages in the first place- zero recompilation. Also, you still have no idea how much a dereference would matter. How often do you access members of other objects, anyway?
Runtime configuration- with components, instance_change use pointer assignment instead of memcpy, because the common stuff is already separated from the main object. Components could also be extended to new functionality, like I explained before. Even if you aren't interested in that, the fact that a system is more extensible is generally a good sign, and others definitely will be interested in that. It's a common C++ technique to delegate behavior to member objects, and this would be another way to help people move to C++.
Decorators- the entire idea behind the tier system is to keep systems the same size to avoid total recompilation or virtual accessors, no? Decorators would often need to change the size of a subsystem. Even if you're find with more compile time, you still wouldn't be able to enable, disable and switch decorators at runtime (which definitely matters in debugging) without adding every possibility into one tier and adding a bunch of extra runtime checks. Components would also make it possible for users to add their own decorators for their own decorators.
|
|
|
Logged
|
|
|
|
Josh @ Dreamland
|
|
Reply #50 Posted on: March 31, 2010, 10:09:47 pm |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
Your instance_change argument had me reconsidering the implications of your proposal for a few seconds before I remembered what it would look like for an event to access any of your component-ized locals. I assume this is where your proposed accessor comes in, which I said before wouldn't really be needed: I could parse in a "componentname->" before each local. However, I don't want to do so, and I don't believe anyone else does either. I was discussing this with Luda; he asked what the point was. I referred him to your independence and instance_change arguments (those were your good ones; coincidentally, they were your only two that were worth a second glance). He then remembered that instance_change existed, he decided it was ugly. I agree, of course. It looks great from a distance when you start forgetting about the lower components you're cursing.
The reason I don't want to parse in componentname-> is not even to do with the amount of work. First off, Luda thought dynamic allocation was ugly; I think requiring a list of what's in each component is ugly. To add that in before the correct variables, I'd need to know what variable is in what component. We have no C++ way of signifying what's a component, so I'd need to keep a list of locals again, or read them from some messy INI. I refuse to do that.
I wanted the system to be extensible from the low level more than the high, really; easy to add more systems to using C++. I have been doing some serious reorganization towards that in every system.
And again, my tier hierarchy is designed to try to emulate true dependence. Consider this; In order to check collisions (the highest tier in my system), I require the following: - IDs and Object Indexes from object_basic (tier 0) - Coordinates on the screen from object_planar (tier 1) - Image Index (to tell which mask to use) from object_graphics (tier 2) - Bounding boxes and bit masks from object_collisions (tier 3)
That's every tier. If you want to use a DLL like Ultimate3D instead of the built-in drawing systems, but utilize Ludamad's collision system as well, that doesn't really make a bit of sense; Luda uses bitmasks based on sprites. Mutually exclusive tiers can be included just that way, and a source file only has to utilize the one it was designed for. For example, it'd make more sense to use some physics library like Newton instead of Colligma to accompany Ultimate3D. So, a Newton tier could be engineered to only require the first two tiers. This'd be a total of two combinations, really; I'll bet you can't really afford to swap out the planar system if you know how many coordinates you need.
Anyway, I'm proceeding with the tier system until further notice. If you can convince Luda, serp, Ism, ...anyone other than your brother, really, I'll investigate it a bit further. Until then it's better I stick with what's now implemented.
We also discussed how instance_change isn't really used a lot. Normally I'd hate to use that as an excuse, but the function is an oddball. You picked up on that as well. It's one of the very few functions that approached justifying an interpreted language. Also, it's one of the few things R3 randomly lacked that no one even asked about. Despite me not thinking highly of it, I would include an option to employ a component system just to improve any game seriously whoring that function (though neither Luda nor I can think of a good reason for a game to do so), but the choice for this system has far too deep-rooted consequences. It's one of the new backbones of the project; perhaps that's why you're so avidly proposing the components.
Ultimately, too, most of the flexibility issues with removing tiers from my system would manifest as similar problems in moving them from a component system; except we'd just be removing one pointer rather than changing entire chunks of data. The size of the change really doesn't matter; it's that it changed that throws off other systems.
|
|
|
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 #51 Posted on: April 01, 2010, 10:32:14 am |
|
|
Joined: Feb 2008
Posts: 954
|
instance_change isn't really that ugly. In a purely GM context, you could use it for new objects that get created on destroy without requiring a(s much) reallocation. Especially if you could statically create the components beforehand, AI (or other) states would be very nice with components. You wouldn't need a list of locals either, I don't think. Non-standard members could go in the main object as before, while any new members or methods on new components could either use a #include for additional inline accessors to the main object or just require them to know about components and use it directly.
Your dependencies make sense. However, switching out tiers does as well. What if, instead of just switching to U3D, you wanted to switch to your own graphics system besides DX or GL, perhaps some library that works on more platforms or your own version for the DS or something. Or maybe you'd want to switch the physics engine to something that doesn't have GM's default behavior with friction, gravity, etc. If you were willing to deal with some things GCC couldn't verify for you, you could even use components to switch the types of the default members without as much recompilation.
Components are better at handling removal and changes because they're not part of the actual object. Removing one doesn't let you remove the pointer, but dummy components are always an option that would at least get rid of GM's default behaviors, if not the space the members take up. New systems can easily add their own private members as needed without screwing up the sizes. Then there's the debugging stuff- how on earth do you plan to do that with tiers?
|
|
|
Logged
|
|
|
|
Josh @ Dreamland
|
|
Reply #52 Posted on: April 01, 2010, 12:07:29 pm |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
The hope behind adding a new graphics system (such as GX for the DS and Wii) is that doing so doesn't change any of the tiers; we're striving to allow lossless cross-compilation. Obviously we'll be sacrificing some things between consoles and the PC (namely the keyboard, at least for the DS) and we will be adding some functionality (such as managing viewports with the DS; I'm not sure how it handles multiple screens). Fortunately, most of that will not have to do with locals and will not even need to interface with the tier system.
I do see where components would be handy; I don't think ENIGMA is such a case.
As for debugging, many of the projects I've seen let you compile a debug configuration and a release configuration. Storing a separate object file for each is an option. If I need a notification on write to a variable, I will add such a directive to "var," which, unfortunately, is the tiers' default type. That will require the recompilation (or storing of a second object file) of one source. Two for types such as hspeed, vspeed, direction, and speed, whose assignments are already special-cased to interact with one another. Making the decision to leave var behind can indeed end up being costly of compile time; the hope is to make that happen only the first time and to keep the object files from there.
I'd also like to point out that the tiers are not to be included by most files; only those that truly need to interface with local variables. For example, that includes a good deal of the collision system, but not the collision testing code. Ludamad won't even include a tier, because his system will operate independently of them. There will be a go-between file that I intend to author that will make calls to his system based on active instances.
|
|
|
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 #53 Posted on: April 01, 2010, 02:39:10 pm |
|
|
Joined: Feb 2008
Posts: 954
|
Yes, different graphics systems would be to keep the same interface with different underlying engines. However, that doesn't mean their internals should or even could remain the same. You need different handles and objects that would inevitably end up taking up different sizes. The tier system loses half of its raison d'etre because of this. Components let you organize the different systems however they need to be set up without worrying about size, and still get the benefits you were looking for in the tier system.
With components, those debugging features could be turned on and off at runtime, without any recompilation. You could just switch out the component being used. In build mode, for example, you could make a decorator component that handles and filters interface events to quickly switch to a user-friendly editor where you could select, create, destroy and move objects while still running their normal draw events. A debugger could enable and disable different events, subsystems, etc. without any checks getting in the way of the rest of the code.
|
|
|
Logged
|
|
|
|
Josh @ Dreamland
|
|
Reply #54 Posted on: April 01, 2010, 06:08:14 pm |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
"to keep the same interface ... that doesn't mean their internals should or even could remain the same." I tried explaining this, maybe not thoroughly enough. The tiering system is only for local variables instantiated along with objects. These are the variables that will be in every single instance, like x and y in GM. They are entirely independent of locals to a system; a system can have as many of those as it wants and still be independent. Certainly you knew that... To have the same interface is to have the same locals.
"With components, those debugging features could be turned on and off at runtime, without any recompilation" The community is going to respond GREAT to this. That was political suicide in the world of GM, sorry. And don't bother attacking me; I'm a little above that. Number one, no one else is; number two, debug things are costly size-wise. Is it your intention to remove the debug things entirely during final compilation? If not, you may as well just leave; otherwise, there's no point to having them removable before that final build anyway.
|
|
|
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
|
|
|
|
|
Josh @ Dreamland
|
|
Reply #57 Posted on: May 06, 2010, 04:44:38 pm |
|
|
Prince of all Goldfish
Location: Pittsburgh, PA, USA Joined: Feb 2008
Posts: 2950
|
"If they simply wanted to make a quick text editor do they really need the graphics library? Or the collision? Audio?
Thought not, you need to look at the benefits of a component based framework rather than your own miss-guided attempts at optimization."
I'm thinking I didn't come across clear enough. The difference between the tiering and component system is in two places. 1) The tier system doesn't require me to parse in accessors nor tax the CPU To lookup, store, push, and jump to that accessor. 2) If you remove the Graphics Tier, the Collision Tier goes with it; that's the only problem. It is very easily removed, and doesn't leave residue, unlike a component system.
So, the only drawback of mine is that you can't have collisions without graphics. I don't even see that as a problem.
And another thing, there is no audio tier. Nor audio component, if I'd used that system. Sounds in Game Maker don't use local variables, and so don't need a tier.
Rusky's component idea makes tiers entirely removable independent of one another, but uses slightly more memory and CPU time. Hardly a loss, but hardly a gain. Especially since if I thought I could have a collision tier that didn't access members of the graphics tier (such as image_index and image_angle), I wouldn't have placed it below that tier.
Further, this will not increase compile times except when you go from compiling a game that does away with a tier to compiling one that does not do away with a tier. In fact, even in that case, I can probably just leave all tiers in until Release compile.
No alignment is hard-coded; it is just calculated based on the size of each inherited tier. If youY want to edit a lower tier, a recompile is necessary. However, what I didn't realize when I originally posted this is that the system attached to each tier is basically intertwined with each higher tier. Adding to tiers is difficult, yes, but there's no point, I realize, unless you are extending the list of available functions, in which case the user will have to recompile it anyway. There's essentially no point to using any other system; rest assured, your fears are in vein VAIN. VAIN. YOUR FEARS ARE IN VAIN.
|
|
« Last Edit: May 06, 2010, 10:56:15 pm by Josh @ Dreamland »
|
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
|
|
|
|
|
|