If I store an instance of a class in a global dictionary is it storing all the attributes of the original class or just the things which are changed for the instance?
For example if I have a magic sword which is different from regular swords only in that it has a +1 to damage, I can just take the “sword” class and create a magic sword:
So sword item has has a lot of attributes but my magic sword only changed one of them.
If I store my magic sword in a a dictionary, is it going to store all the extra stuff, or is it going to use the original class in the code to find those things? From what I read Python checks for data in the instance and if it is missing it will go to the class or subclass that created the instance to find the data.
My dictionary of unique game items is likely to get pretty big. If I’m storing all the data about the whole class every time I create and store an item it’s going to get pretty big in a hurry.
I’d like to be sure this is the case before I invest heavily in using classes rather than dictionaries (which I’m already happy using).
A python class is essentially just a dictionary, which is used for instance attributes and some class functions. Functions are usually created once and the instance parameter is passed to simulate a bound function. In cpython (which blender currently uses) you can define a slots attribute on the class which prevents a whole dictionary from being created and saves space
The size of a python class is not going to be large enough to cause memory concerns. You would need millions of objects to start seeing memory usage in that manner
I’m assuming sword_item is always attached to a KX_GameObject. IMHO, in your case, I’d do something like:
(-> means subclass)
KX_GameObject -> Sword -> MagicSword, ABCSword, XYZSword, etc.
Other examples:
KX_GameObject -> Shield -> MagicShield, ABCShield, XYZShield, etc.
KX_GameObject -> Axe -> MagicAxe, ABCAxe, XYZAxe, etc.
You could go further depending on the data structure:
KX_GameObject -> Weapon
Weapon -> Sword…
Weapon -> Axe…
Also, if the MagicSword has only +1 damage, then I’d assign a damage attribute to the class so you’d do:
magic_sword.damage += magic_sword.hitdmg
Actually, it’d be better to create a take_damage method of the MagicSword (Sword/Weapon/etc.) class and call that instead of the above expression. So in the future if you decided to change the damage value, you don’t need to find all those expressions in each instance and you can just change the attribute in the class instead.
About instancing:
class sword_item(object):
all_swords = 0
def __init__(self):
self.damage = 5
magic_sword_1 = sword_item()
magic_sword_1.damage +=1
magic_sword_1.all_swords += 1
magic_sword_2 = sword_item()
magic_sword_2.damage +=1
magic_sword_2.all_swords += 1
# Modifying "magic_sword_1.all_swords" will modify "magic_sword_2.all_swords"
# So "after magic_sword_2.all_swords += 1", it'll equal 2 and so will "magic_sword_1.all_swords"
#
# damage, etc. applies to individual instances which is why it's in __init__ and assigned to self
Python doesn’t have public, private, protected keywords like C++ for example, for various reasons.
Yes, it is. When creating a new instance of a class it gets all attributes from the class. This includes any attribute the class inherits from it’s super classes.
To be more specific, this code does not create a “magic sword” as you did not define what a magic sword is. It creates an instance of sword_item and modify the instance after creation. This is like buying an ordinary sword and writing “excalibur” on it. This is indeed a way to individualize objects.
(BTW. I recommend to start a class name with upper case to distinguish it the class from variables and instantiation from function calling -> class Sword)
To create a real "magic sword you can create a different class:
Sword
Sword describes the common behavior and common states of all swords. It is the super class of all other swords.
class Sword():
def __init__(self):
self.damage = 5
self.weight = 3
self.range = 0
self.speed = 2
self.animation = "slashing"
#Display some states on print
def __str__(self):
return "<{} damage:{}>".format(
self.__class__.__name__,
self.damage )
Magic Sword
A Magic Sword extends swords with special behavior
it is stronger and
it needs a name.
class MagicSword(Sword):
def __init__(self, name):
super().__init__()
self.name = name
self.damage += 1
# Display the name too
def __str__(self):
return "<{} '{}' damage:{}>".format(
self.__class__.__name__,
self.name, self.damage )
Excalibur
This is a very special magic sword
it gets a fixed name
it can be created only once - so do not loose it!
class Excalibur(MagicSword):
alreadyCreated = False
def __init__(self):
super().__init__("Excalibur")
if Excalibur.alreadyCreated:
raise Excalibur.UniqueError(self)
Excalibur.alreadyCreated = True
class UniqueError(Exception):
def __init__(self, item):
self.item = item
def __str__(self):
return "Unique item {0} was build already. No more builds are possible.".format(self.item)
Creating Swords
Lets create some swords!
Look at the console … there will be errors
Thanks monster, I’ve avoided using upper case letters until now because it usually confuses me, but this would be a case where it could make things less confusing.
I like the bit about only creating once, that could be useful.
I’m worried about a dictionary becoming very large so that it slows logic when I access it. I’m also worried that a single large list of items could be confusing or cluttered.
I have three possible ways of dealing with items in the game:
A single dictionary of items, each with a unique key generated when spawned. This has the benefit that every item is a member of the item class, when adding items to an inventory or equipping items for combat I can call from just one dictionary and have very predictable behavior. Items exist in that dictionary but representations of that item can be anywhere in the game, for example in the main scene carried in the player’s hand or in the inventory of a monster or in an overlay scene in the inventory of the player, or attached to the mouse pointer as I transfer it from the main display in to the overlay scene.
Having a different dictionary for each level of the dungeon, plus one dictionary for items carried by the player. This would give smaller dictionaries, but would require more maintenance because I’d have to remove items from one dictionary before adding to another. It would make it easier to do checks to see if any of the players are carrying a key or a particular quest item, like ten otter skins or whatever, or for checking if a certain item has been spawned or not, but I can do that by just keeping track of the player’s inventories or keeping a list of keys of items on each level anyway.
Having different classes for each item type (swords/ armor/ potions etc…) and storing each in a separate dictionary. That’s going to be less cluttered than the other options because each item type will only have attributes useful to that type, like for example a crossbow could have an .ammo attribute, while swords wouldn’t need it. Food has a .nutritional_value attribute but scrolls don’t. But it’s going to be a nightmare to code the inventory or player equipment functions. I could use subclasses to make it easier but then there’s always a chance of raising an attribute error if I’m not very careful about what attributes are shared by which items.
Which do you think is the best?
Could accessing the dictionary cause slow logic if it is very large?
You do not need to worry about slow or fast containers unless you have thousands of entries and you search it very often. Usually you choose the container type dependent what fits best into your design and what the most common operations are (e.g. searching, or writing).
As usually there is no “perfect” solution. But lets look at your requirements:
you want items
you want items with different behavior (ammunition eating, ammunition free, shooting, melee, tracking, area damage, multi hit , containing items, destroying, eating, integrating, collecting …)
you want items with different attributes (weight, damage, damage type, costs, size, required skills, slots, …)
you want to keep track of all existing items?
you want to keep track of all possible items?
you want to keep track items belonging to a single character?
you want to keep track items placed somewhere in the environment?
you want to keep track items of item generation?
You see this points into several directions:
requirements for items
requirements for item management
My recommendation:
classify the items you are aiming for. E.g. melee, ranged, munition eating, reloading etc.
describe in detail the behavior of each type (class)
identify shared behavior/attributes
identify unique behavior/attributes
With that information you should be able to create a few concrete implementations. You do not necessarily need Python classes. Behavior is also described in logic bricks. So do not forget that ;). Attributes can be stored in a data container such as dictionaries, lists, game object properties - they do not demand a class either, but it might be a good option. Be aware a list is an instance of an class too;).
Well, the game is all about loot and to make it more interesting there is not going to be any vanilla loot.
You won’t find a sword, but you will find a rusty, old sword or a wickedly sharp sword, or a broken, heroic sword or a rather ordinary-looking sword.
All the attributes custom attributes will be generated when the loot is spawned, this could be when you open a chest, or when a monster is created (with attendant equipment). The items will have a dynamic name string which will be changed depending on the custom attributes and each attribute affects the stats of the item too.
There will be certain combinations of attributes which are forbidden, like you won’t find any “rotten, extremely delicious, worm-ridden apples”. Also some attributes are limited to certain equipment types, like you can’t have a razor sharp banana, or a quick-firing bedroll.
I may clear out old loot that has been picked up and dropped, when you leave the level it will be popped from the dictionary. But anything in a chest or not yet picked up should still be in the dictionary. You may run out of food later and have to back track to look for stuff that was missed the first time.
I think I’m going to start with a single item class and see how it goes.
One thing I want to know how to do with classes is how to run class functions from a list.
With dictionaries and lists I can create a list of function calls:
And then select them randomly, or do them in order, or add to the list or reduce the list or whatever. This can give nice pseudo random behavior for agents in the game.
When I try to make class functions work the same way the dictionary raises an error because the… well actually I don’t know why.
This sounds like a good idea. The way I’ve been thinking of handling items is similar in idea to yours. Basically, before the game begins, I create classes for each individual type of item (i.e. one for a sword, one for a potion, one for a greatsword, one for a hammer, etc). When an item is spawned, it creates an instance of that class and modifies it randomly. That way you have a nice base, but can still have randomness.
Each item can also be based on a base item class that contains things that all items might have (weight, size, whether it’s bound to you (whatever that means), if you can unequip or sell it, etc).
As for your class function question, you can use the name of the function without any parentheses to store a reference to the function, which you can then call later. Although you shouldn’t get errors outright from that example if you just substitute the class functions in…? What’s the error you get with an example of the code?
Yes, that’s pretty much what I want to do with items. There will be a static dictionary definition of a greatsword, but that’s a kind of idealized greatsword. Every greatsword in the game will be a randomized variation of that base. I’m also going to include wear and tear for items, so I have to keep track of how damaged the items are, and if they are likely to break.
It looks like I didn’t save the test file where I was trying that out. I usually put together a quick prototype of any code before it goes in to my game, so I see what kind of good or bad things it’s going to do before it gets all complex by being integrated with the rest of my messy code.
In the demo I got the function call list to work within a dictionary, but when I tried switching out a general function with a class function in the dictionary it said error in line (the line where the dictionary was stored), global name “some_function()” is not defined, even though it was, but within a class. At that point I quit, went to go and eat dinner and forgot to save the test file.
I think you should differentiate between attributes (status, weight, strength) which is pure data and behavior (carrying, using, holding, loading) which is logic that manipulates states.
Additional there are several different concerns that have interactions with each other.
From what I read you need following things:
several types of Swords with attributes and behavior
[LIST]
there are rules (behavior) that can change the attributes of the sword (damaging, repairing, loading).
there is behavior to interact with other objects (holding, carrying, selling, fighting, using) [do not confuse this with the behavior of the other objects, they have their on behavior. E.g. the player swings the sword = player swings + sword swings (synchronized behavior).
Several types of sword factories
there is behavior to create a sword of a certain kind. I guess there are rules how to generate swords too ;).
PEP8 advocates CamelCase for class names, whilst name_with_underscores for functions, variables and attributes.
In this case you shouldn’t need a function - set and get functions are an example of programmers who are used for Java or C++. However, they’re sometimes necessary. Properties are useful when you need to do something with a value before setting it, and are preferable to explicit set_var and get_var methods. Don’t specify types in names, unless you have to.
Well, one of the things I want to do with item generation is to encapsulate the process of generating perks or attributes in a dictionary.
I’m still working on that, I want to be able to call functions straight from a dictionary entry.
I thought I had got it to work, but after some testing I now see that a function call is executed as soon as it is defined, whether that’s as part of a list or as part of a dictionary or whatever.
Meaning that:
I only realized this when I tried not picking the functions from the list, and confirmed it by having multiple functions and then calling just one.
In the end I found that as SolarLune said, storing a reference to the function without adding () did the trick.
So you can do something like this this (untested):
function_list = [open_door,drink_potion,Put_on_armor]
for function in function_list:
function()
here’s an ugly example of what I’m trying to do (tested and works as intended):
my_item = {"type":"weapon",
"damage_type":"slashing",
"damage":5,
"weight":2,
"name":"sword"}
def set_attribute(item,attribute,value):
try:
item[attribute] += value
return True
except:
return False
def check_attribute(item,attribute,target):
if item[attribute] == target:
return True
else:
return False
def add_perks(item,perk_list):
perks = {"sharp":[[[check_attribute,[item,"type","weapon"]],[check_attribute,[item,"damage_type","slashing"]]],[[set_attribute,[item,"damage",2]],[set_attribute,[item,"name","_sharp"]]]],
"heavy":[[[check_attribute,[item,"type","weapon"]]],[[set_attribute,[item,"weight",2]],[set_attribute,[item,"name","_heavy"]]]],
"strong":[[[check_attribute,[item,"type","potion"]]],[[set_attribute,[item,"effect_value",20]]]]}
for perk in perk_list:
checks = []
action_results = []
for check in perks[perk][0]:
check_result = check[0](check[1][0],check[1][1],check[1][2])
checks.append(check_result)
if False not in checks:
for action in perks[perk][1]:
action_result = action[0](action[1][0],action[1][1],action[1][2])
action_results.append(action_result)
if False not in action_results:
return item
else:
return None
perked_item = add_perks(my_item.copy(),["sharp","heavy","strong"])
print(perked_item)
In this case I want to have a flexible system that can perform checks using different functions, such as checking an attribute, or checking if a perk has already been added, or if an opposing perk is present, or seeing if a unique item has already been created etc… I also want to allow the possibility of doing AND/OR/NOR checks too for example when it only requires that a weapon not be blunt. I want to handle that from the dictionary, so people who want to modify the game (like me in future) can just change the dictionary to add new perks or modify existing ones.
The same with setting attributes, I might want to set an attribute, or remove it or replace it, or even create a false attribute to show in game (for example a magic sword which has not been identified yet will seem just like a regular sword, but will have better in game performance, or a cursed sword would do the opposite, but the player shouldn’t know). I need different functions to do that and I don’t want to write a long if/else statement to try to cover every eventuality as I’ll need to re-write the statement every time I change the dictionary of perks or whenever I introduce a new function for the perk system.
I want to make the game easy to modify for people other than me, it seems like the best way to do that is to expose some of the code to external files.
This all seems much easier with dictionaries rather than classes, so I think I may stick with dictionaries for handling items.
I’m also thinking of extending the perk/quirk system to monsters so you might have a “strong” giant rat, or a “weak” goblin.
Anyway, I’m tired now so maybe this whole post makes sense or maybe not.
I’m a bit confused why you place functions into a dictionary. This seems a bit counter productive.
Usually you collect objects (class instances) in a container. If they share an interface you can deal each of them the same way:
items = [sword, bag, shield, boot, blue_ring, red_ring]
...
totalValue = valueOf(items)
...
def valueOf(items):
value = 0
for item in item:
value += item.value
return value
usually you just want one of the items:
showWeaponsForSelection( findWeapons(items) )
...
def findWeapons(items):
return [item for item in items if isInstance(item, Weapon)] # assuming Weapon is a class
def showWeaponsForSelection(weapons):
for weapon in weapons:
weapon.show() # weapon presents itself or
viewer.show(weapon) # another object presents the provided weapon
It does not matter what a weapon can do as long as it is recognizable as Weapon and can show itself (show()) or can be shown viewer.show(weapon).
import bge
#OK
class MouseCenter:
""" this class manage stuff about the center of the screen"""
def __init__(self):
w = bge.render.getWindowWidth()
h = bge.render.getWindowHeight()
self.screen_size = w, h
self.screen_center = w//2, h//2
@property
def pixel(self):
px, py = [((a*b)-c) for a,b,c in zip(bge.logic.mouse.position, self.screen_size, self.screen_center)]
return int(px), int(py)
def reset(self):
bge.render.setMousePosition(*self.screen_center)
and, also in this case the instance must be lower_case ?
mouse_center = MouseCenter() #?
@Smoking_mirror , post some blend if you do something with class, i’m very intersting at this theme
ummm… my last post was getting a bit off topic I think so it’s getting difficult to explain why I’m wanting to do what I want to do. Anyway, thank you, I think I’m getting closer to understanding classes and class functions and how they could be used or not in this case.
The basic problem is that I want a flexible way of representing items in the code so that if you pick up an item, it will be in your inventory and if you equip it it will be shown in the player’s hand, and when you drop it it will be on the floor and if a monster or NPC picks it up they can also equip it. I also want to make the weapons very diverse, with special attributes which can change the way they look, or act in game.
Think of the sword “sting” from the Lord Of The Rings.
Sting is a short sword which glows when goblins or orcs are near. It is very sharp, especially the point. It is possibly made of Mithril rather than everyday steel, and it can cut giant spiderwebs.
In game terms such a sword would need a unique name (overwriting any other name attributes such as sharp). It would need to be sharp and it would need to have a “lamp” value to make it shed light when equipped (glowing in the presence of certain enemies would need a whole lot more coding, but I guess it could be added as a “detect monster” spell effect). The material would be changed so that it is no longer affected by spells of natural effects such as rust which affect iron or steel weapons. I guess sting would have the “magical” flag meaning that it could wound monsters or damage things which can only be harmed by magical weapons.
I want to have a lot of possible perks or quirks which can modify the way items work. I also want to include a quirk editor, which will be part of a editing suite which will allow people to add more content to the game later. With the editor you’ll be able to design new quirks using a visual UI.
My aim is to expand the game over time, with the first version being a simple dungeon craw and later incorporating a randomly generated world map, and randomly generated quests, NPCs etc… So I need a system that is open from the start to being upgraded and expanded.
I could write a if/else expression or function for each quirk like:
if item.type == "sword":
if "sharp" in item.quirks:
item.damage +=2
item.name = "sharp sword"
elif "heavy" in item.quirks:
item.weight +=5
item.name = "heavy sword"
elif "long" in item.quirks:
item.reach +=1
item.weight +=1
item.name = "long sword"
elif ...
elif item.type == "axe":
if "sharp" in item.quirks:
item.damage +=2
item.name = "sharp axe"
elif "heavy" in item.quirks:
item.weight +=5
item.name = "heavy axe"
elif "two_headed" in item.quirks:
item.damage +=2
item.name = "two headed axe"
elif ...
elif item.type == potion:
if "strong" in item.quirks:
if item.spell_effect == "healing":
item.healing +=2
item.name = "strong healing potion"
elif item.spell_effect =="poison":
item.damage +=5
item.name = "strong poison potion"
elif...
elif...
but such a function is going to get really long and will be really inflexible. How can I add multiple quirks at the same time? How can I do multiple checks, “or” checks, unique item checks?
In the past I often wrote like that and had trouble with code that was difficult to write and even worse to check for errors. These days I prefer to have a list or dictionary which can be iterated through to get the required result.
For example instead of going through line by line to define the neighbors of a cell I can define a seach array:
search_array = [[0,1],[1,0],[0,-1],[-1,0]]
I also found it useful for setting conditions for example:
transitions = [-1,0,1,2,3,4,5,6,10,11,12,15]
no_join = [13,14,16,21]
if tile in transitions:
add_transition()
elif tile not in no_join:
add_wall()
else:
add_blank()
rather than writing if else for every possible transition/ not_transition variation.
I want to be able to make each quirk like a mechanism which contains all it needs to make the modifications to the item without changing anything in the main body of the code. I’m not going to put function calls in the dictionary, as that didn’t work, but I will put in the things needed such as function name and required arguments so that a function can be generated from the data in the dictionary.
Maybe I should rename this thread “Questions about representing items in code”…
What you’re trying to do is to generalise the effects code so effects can be added dynamically. This is one example to achieve this, in Python 2 http://www.pasteall.org/49918/python
However, in this example we create some dependencies - the weapon must know the format of the effect, and how it stores its data. In reality, the effect should be the holder of this information, as it is applied to the weapon. Hence, delegating the control of effect application to the effect is a good first step. Secondly, you’ll notice that the damage property is looking at a main effect and adding it to the base damage. This is all ‘static’ as we modify the main effect only when we add or remove an effect, so it is relatively pointless. In all, it is best to allow the weapon to forget the fact that it could have e’ll notice that the damage property is looking at a main effect and adding it to the base damage. This is all ‘static’ as we modify the main effect only when we add or remove an effect, so it is relatively pointless. In all, it is best to allow the weapon to forget the fact that it could have effects applied. After all, if an effect was controlled by the weapon, it wouldn’t be an effect, more so a feature