Quote:Original post by EmrldDrgnThe factory is capable of taking the path from a/the file, or accepting it as a parameter; it doesn't need to be hard coded.
Um... nuh-uh. Fire tile changed to ice tile, both ways:
My way - Make new img file, change path/index to it, change applicable parameters. Run.
Factory - Make new img file, change path/index to it in code, change applicable parameters in code. Change file to new "token". Add new token to Factory method (so it knows what to do with it). Recompile. Run.
Or am I completely off-base here? I'm very confused...
There are a number of different ways to create factories depending on what you want them to do, but essentially their job is this: They move the job of creating new instances away the point where you need an instance to be made.
So your script reading function is parsing this file, identifies that a tile needs to be made. You can either put the code for creating new tiles/sprites directly into that script reading function or move that job out to a factory and instead have it make a call to the factory.
Either way your script reading function still needs to collect up the parameters from the file (the file structure needn't change at all) but instead of it then figuring out how they all work together to create a tile, it just chucks all the parameters at a factory and gets back a newly constructed tile.
Quote:Should have mentioned - I meant example in code (wow, same tag, same emphasis, totally different point).Hmm, I'll let someone else get that. Unless you had something in mind? I'm not sure I understand how showing you a renderer will help demonstrate its usefulness over simply explaining why it's useful as a concept - code is just an implementation of a concept.
The difference is essentially between:
me.draw();
and:
draw( me );
Or, in point of fact, often:
draw( meta_description_of_me );
This is because the renderer doesn't actually need to know me to draw me, all it needs is a visual description of me. There are many more facets to me than just what I look like (phew!) but the renderer is shallow and only cares about my looks.
Quote:Light doesn't know anything in that situation... it hits the apple and is scattered. The apple does the action. Fail. Lol.The light is the one being scattered, not the apple, so light is the one doing the action. When the light hits the surface of an object (an apple or otherwise), it inspects the surface properties (angle, opacity, diffuse colour, specular colour, etc) and makes a decision about what to do based on that - Light is making a decision about itself! If you consider light to be an object (in the OO sense) then there's no reason why the apple object should be making behavioural decisions for the light object.
Quote:Plus that'd be sub-optimal anyway, since the Light class would need to define different behaviors for each possible Object. Much better to use a virtual metrhod in the Object base class. But I digress...Re the bit in bold: Many renderers are somewhat similar to that:
renderer.drawPlayer(..);
renderer.drawMonster(..);
renderer.drawTile(..);
It's not necessarily the best way but it still has the benefits over having the player, monster and tile all drawing themselves. The downside is the need to modify the renderer whenever you want to add a new type of renderable object - although you'd still be having to implement a new render function if you had objects draw themselves anyway.
A more generalised renderer is possible, one that doesn't have to know about different object types (which actually violates the open-closed principle anyway)...
Quote:In this theoretical implementation, how does one tell the renderer about all the objects that need to be rendered, and how they need to be rendered, so that it can sort them and achieve this oh-so-magical optimization?I gave a crude example previously in this post with the renderer that only cares about my visual description.
The premise is to find a generalised - data driven - way to describe the visual appearance of an object you want rendererd. In the case of a tile engine, that's easy, it's just the name/index of a sprite to render with along with some way to represent the position is needs to be drawn; that's all the renderer needs to know (and this information could be kept in the sprite_set).
In the case of a more sophisticated renderer you need to generalise a lot more and so it will need to know a lot more information: like its geometry, its translation/rotation/skew, which shader to use, how many lights there are affecting the object, whether it emits light itself, how it reflects incoming light (diffuse, specular, reflective?, etc), its opacity, its subsurface properties for refraction, its texture(s), whether this object is big or small, whether it's moving quickly or slowly, the distance from the camera, how old the object is, and so on. All these things are abstracted away in different ways (like Material and LightModel classes) but at some point they're accumulated and all come together to describe a renderable object and get fed to/retrieved by the renderer.
Quote:And doesn't the massive amount of data that you'd need to pass to this class sort of break encapsulation?No because we know nothing about the internals of any class. All we know is that by using public interfaces we can build or retrieve enough information to describe the visual appearance of an object. Again for a tile engine, that's easy, example:
tile t = field(x, y); // get the current tile from the mapsprite img = sprites[ t.name() ]; // get the sprite from the sprite_setvector pos(x * tile_width, y * tile_height); // calculate where to draw itenqueue(img, pos); // add to the render queue// later once all sprites are enqueued:optimise_states(); // sort queue to optimise state changesdraw(); // draw everything enqueued