I agree and really like such approach.
But the problem here is the knowledge about "mesh, textures, etc".
Item cannot have that knowledge. Why?
Well, the easiest answer is just because there is a LOT of such knowledge.
Item will blow. Sometimes I can't even access rendering library from domain model (physically).
The other one is a metaphor of painting: I can represent every object in the world in a tremendous possible ways, and this object doesn't even know about that. Its behaviour remains unchanged.
So this is a question. I can use getters like
getDamage() and render everything easily. This is the approach of most applications. But what if I want to use inversion of control and OOP? What if I want to tell object something like "Hey, render yourself to that canvas"?
I think this is impossible, but maybe guys here have ideas or solutions.
RenderableItemcould be totally different objects.
Weaponcould encapsulate/hide its
damageand have only methods like
RenderableItemcould have textures, etc. (and maybe just the ID of
Weaponso it knows which item it represents), and have a method
Well, this is actually really depends on... But, in my example domain, I need at least one getter with resulting enum
ItemType, so that I know, whether this is
Armor. Then I need to check it's durability to know, should I use broken texture or just simple. Also, it's very common that
Item has rarity, so that I can render blue frame or green or orange etc.
So there will be always GETTERS:
And, as you can see, they depend on representation, not vice versa. I don't know a proper way to do correct encapsulation and OO for such things. Yegor offen says "The whole design is wrong", but it's not even design, it's just simple case. By the way, games development domain is far more richer, than any other, because sometimes to implement some features you must be really close to real world.
What I think is may be a good compromise is when
Item itself declares another interface like
ItemCanvas, that interface must generalize rendering for
Item as much as possible. Then I can implement that interface in game client library and use it for a proper rendering.
As renderer I still depend on some DATA, but this data (behaviour) is concentrated in some specific API, which is not mixed with actual
Item interface. Maybe this is a good compromise, I don't know...
Well, it's a key entity in games. It can be stored in inventory, it can be equiped in hand (only weapon, actually), it generalize other items: weapons (can hit, can broke), armor (can defend) and etc. There is a lot of behaviour, on which items can influence. You can drink a potion and restore health.
For example, you have bag — technically the list of
Item — and you need to render it on the screen. Also, there can be tooltip, which shows all information of item: damage, critical chance, dodge chance, etc.
This is ok. But what about rendering? How
ItemDescription will know, whether it's weapon or not, what it's durability, critical chance and etc.? Do
ItemDescription is created from
Item? This dependency flow, actually, can be or from one side to other or vice versa.
The main problem in first direction is GETTERS.
In second — generalization (I cannot abstract rendering and representation, only with some hacks and simplifications).
PrintableItemwhich can respond to the
with(name, data)message), and these informations may be critical chances or anything else. The Item does not need to know what kind of object will receive these informations
Well, this can be good for generic engines like serialization: serializer doesn't care about anything and can work with property-value pairs. But more specific engines cannot.
So the problem with
with( name, data ) is that as RENDERER how do I know, which kinds of names are available and which one is related to durability, damage and etc.? Even if I know, how can I be sure that contract is not changed? Oh, I mentioned word contract because, as you can see, this will be just another way to implement... getters!
It seems like the whole problem to render an item leads us to some kind of getters in one way or another.
@JoshuaLight You don't need
ItemType. Just have interfaces such as
Bag, etc. If you need properties like "durability" for rendering, ask yourself - why? If it's to determine whether it's broken or not, just give it a method
isBroken(). So your
Renderable could encapsulate (not decorate)
Item it's supposed to render and just ask it
Rareness may be more tricky. Perhaps your game
World should have the responsibility of tracking which items are rare and which aren't?
Itemcould have a method
InventorySpecscould have methods such as
Just have interfaces such as Weapon, Armour, Bag, etc.
So you think I should use type-casting? Because only with type-casting I can check whether
Item is weapon or not. Also, there are a lot of weapons here: swords, axes, maces etc. How can I determine which texture to use to render specified
IsAxe()? This approach conceptually is almost like getters, no encapsulation at all.
I think rareness was a bad example, because this is really a property of item, which is needed only to show player that his weapon differs from others on a quality level.
This printers idea with
InventorySpecs is a good one. As I said earlier, it looks like this is a acceptable compromise, if
InventorySpecs is driven by domain model, but related only for
InventoryRepresentation. Then I can create
Direct3DInventorySpecs and so on. We conceptually separated rendering from behaviour. This is still looks isomorphic to getters, but in more elegant and objective way, as for me. Will try it soon on my game, where I test such things.
Scene, and then the Scene might encapsulate other Objects, each of whom is told to render themselves
Drawbased on a Parent Position. The calls propagate downwards until every object in the graph (each encapsulated in a specific group or container) has been told to draw himself.