for items, properties stored in different fields or in a string ?

Community Forums/General Help/for items, properties stored in different fields or in a string ?

RemiD(Posted 2017) [#1]
Hello,

In the video game i am working on, there are different kinds of "items", some which are equipment (armors, shields, longrangeweapons, shortrangeweapons), some which are usable (bandages, substances), and money...
These items have different properties and different number of properties, so to store their properties i could :
->have one big list for all kinds of items, with many fields, one field for each property, some which would be used by some items, and some which would not be used
->have different lists, one for each kind of item, with one field for each property, each field would be used
->have one list for all kinds of items, but store all properties in a "properties string" with separating symbols, and have only 2 fields used by all items (pickable and renderer)

For examples :
->an armor would have a properties string like : "kind-bodypart-model-potentialprotection-weight"
->a long range weapon would have a properties string like : "kind-model-range-potentialdamage-weight"
->a short range weapon would have a properties string like : "kind-model-range-potentialdamage-weight"
->a substance would have a properties string like : "kind-model-potentialeffect-weight"
->money would have a properties string like : "kind-model-quantity"

so my "items" list (for all kinds of items and all models of items) would look like :
Global ItemsCount%
Dim Item_PropertiesStr$(100)
Dim Item_Pickable(100)
Dim Item_Renderer(100)

or
Type Item
 field PropertiesStr$
 field Pickable
 Field Renderer
end type

those would be the list of items for the map
and of course have also one list of items per container and one list of items per character.

Since it is apparently fast to split a string made of different parts separated by symbols (on my low end computer, it takes around 0.06ms to split a string made of 6 parts (6 different properties, i apparently don't need more)), and since this procedure would happen only when creating characters/containers/items or when a container/character is searched or when a property is read, i say why not, this would simplify my code a lot... (i would just have, for each kind of item, to code a procedure to get a property from a "properties string", and a procedure to set a property in a "properties string"

What do you think ?


RustyKristi(Posted 2017) [#2]
Hey Remi, there's an inventory snippet somewhere in archives which you may find useful. It looks like you're going that route..


Matty(Posted 2017) [#3]
Hi RemiD,

I typically use your first option
"->have one big list for all kinds of items, with many fields, one field for each property, some which would be used by some items, and some which would not be used"

Ie a class/struct/type called 'Item' which has many, many properties some of which are used, some of which are not used by some items and a host of boolean flags that indicate which type of item it is. One of the pluses of this method is that you can have unusual items that cross over multiple types of category which the other two types of storage are less easy to do this for.

For example you might have an armour that can be activated like a magic ring and the same item class can handle both depending on the flags set on it...whereas a specific armour class and a specific ring class would not allow this....same with a property string.


Derron(Posted 2017) [#4]
With NG you could use interfaces to create "mixtures" (consumable armor ;-)).

You could also create "groups of properties" and only access them via some generic unit methods. So the "groups" have stubs like "canConsume:int()" and "Consume:int()" which get filled by objects which actually can get consumed.

It depends on what you pay attention to:
- reusable code (so things are put into their own importable files - dependencies shouldn't become circular)
- low memory footprint (properties VS getter-methods)
- cpu usage (properties vs getter-methods)
...


Best thing is surely to use the "group"-style. Which could also be replaced with "components".

To avoid direct linking of "possibilities" you need to use "constants" (like "FUNCTIONALITY_CONSUMABLE:int=1") and define the components to what functionality they have.
Then in your item you have a "DoUse(functionality:int)" which runs all the components being available for the given functionality.

That way each item could have whatever functionality it needs.
Disadvantage: information retrieval ("return all supported functions of that item") is done on a dynamic way (asking all components and sum-ing them up). Ok,you could cache this (on each component-modification), but this increases memory usage.

Basic item information (id, GetTitle(), GetDescription(), GetSprite()...) should be stored as properties because they are often used and this saves processing power.

Next to this, I would use a different approach for certain items. Quest Items would imho not mix with other "different approach" items. In that case you could have a "TQuestItem extends TItem" and directly define some properties there.
Of course you run into trouble if you want to use "questitem properties" in another type too. If so, you extract all these properties into a new "group/component" and add them as you did with the others (dunno, the functionality could be "handOutToNPC" or so).



Extracting functionality into components also allows for easy information sharing. So all "magic rings" could share the same "use-cooldown".


Having "uber-classes" (containing properties for everything and the whole world) leads to non-maintainable code if the properties are not just "int" or "string". Like already mentioned - it will lead to "circular dependency" somewhen (a property wants to know about another item... so it must import "TItem" which it cant because it is already imported itself from "TItem"). Having these "all you can eat"-classes is dangerous for "project evolution".


bye
Ron


RemiD(Posted 2017) [#5]
After some tests, i agree that it is better to have dedicated fields (integers, floats, short strings) at least for the items which are often read/written like characters equipment (armors, shields, weapons, bullets) because splitting a string into parts many times each frame would waste too much time.

However, for items which are idle in the map or stored in containers and in characters, the approach to use a "properties string" should work well enough since the item properties would be read only when the item is analyzed...

I am going to do more tests and see how it goes...


Derron(Posted 2017) [#6]
Instead of a properties-string you could also call it "serialization" - or use a kind of "bitmask" to store things into a Long/integer.

bye
Ron


Matty(Posted 2017) [#7]
If you create a large type object with fields for every property (including some unused ones for different types of objects...eg armour may have different properties to weapons...such as damage etc) then I find the easiest way to manage creating objects on the fly is to use an approach something like this:

have a 'template' object which carries all the relevant data for the type of object
and have a 'clone' method/function which takes an existing template instance and recreates it as a new instance (or fills a destination instance) .. eg like this:

;assume template.item exists
function cloneitem(src.item,dst.item)
	;src.item = template
	;dst.item = new empty item
	dst\field1 = src\field1
	dst\field2 = src\field2
	dst\field3 = src\field3
	;etc etc
end function 



RemiD(Posted 2017) [#8]
@Matty>>I think that i will use an item list for all items (equipment (armors, shield, weapons) and "usable" (bandages, substances) and bullets and money) with many fields (some sometimes used, some sometimes not used) because this will be faster to read/write the properties and this will simplify my code, and if i use constants (integers) to store each kind, model, material, and integers and floats to store the others properties, it should not take much memory...

Additionally, my current approach to link the items which are outside any container/character or which are inside a container/character, to their item instance (to be able to get/set the properties) would be something like this :

;to store the item properties
Type Item
 field Kind%
 field Model%
 field Material%
 field Weight%
 field Range%
 field PotentialDamage%
 field PotentialProtection%
 field PotentialEffect%
end type

;items which are outside any containers/characters, visible and takable
TakablesCount% ;items count
Takable_ItemH%(1000) ;item handle
Takable_Pickable(1000)
Takable_Renderer(1000)

;items which are inside a container, not visible
Container_ItemsCount%(10) ;items count
Container_ItemH%(10,100) ;item handle

;items which are inside a character, not visible
Character_ArmorH%(10) ;item handle
Character_ShieldH%(10) ;item handle
Character_WeaponH%(10) ;item handle
Character_BulletsCount%(10) ;bullets count
Character_ItemsCount%(10) ;items count
Character_ItemH%(10,100) ;item handle
Character_MoneyCount%(10) ;money count