How to make a simple adventure game inventory

Dear friends.

I have changed it with the help of: https://blenderartists.org/forum/showthread.php?366780-BGE-HELP-Set-object-name-via-python&p=2843323&viewfull=1#post2843323 post#6 / youle, thank you.

In Part 1 we will use bge.logic to save the pointer of the “added object”, in Part 2 we will use a dictionary for it. The later is saver.
The result of both is the same, and the explanations signed with GENERAL 1 to 3 in Part 1 are valid for both parts. The explanations in this chapter only valid for Part 1 are signed with PARTICULAR 1 to 3.

GENERAL 1 :
Now the “objects to get” on the second layer don’t need Logic bricks, and the Player is the owner of the functions to put the items to the inventory instead of them.

### Changing the Logic bricks ###
We open the SimpleInventory_Demo_05.blend and delete all Logic bricks from the Apple object (of layer 2), and add to the Player object a Mouse Left button sensor, connected to a now added Python controller. In its Module name field we put SInv.get_apple. We connect also to the controller the near sensor NearAny_01 and the Mouse sensor MOverAny_01 .

### Changing the module functions ###NOTE : I put in the header of the module file bl = bge.logic
.
### get_apple(cont) ###
We change next the Logic bricks and the if statements of get_apple(cont) :

    ...
    mLeft = cont.sensors["MLeft"]
    mOverAny = cont.sensors["MOverAny_01"] # this is changed
    nearAny = cont.sensors["NearAny_01"] # this is changed
    hitObjMouse = mOverAny.hitObject # this is new
    hitObjNear = nearAny.hitObject # this is changed

    if mOverAny.positive and mLeft.positive and nearAny.positive: # this is changed
        hitObjMouse = hitObjMouse.name # this is new
        hitNameNear = hitObjNear.name # this is changed
        if hitObjMouse == "Apple" and hitNameNear == "Near_apple_01": # this is changed
<b>PARTICULAR 1 :</b>
            bl.appleCopyList_01[0].endObject() # we substitute 'own' with 'bl.appleCopyList_01[0]'
            Empty_apple_01['apple_01'] = False
            ...
        if hitObjMouse == "Apple" and hitNameNear == "Near_apple_02": # this is changed
            bl.appleCopyList_02[0].endObject() # we substitute 'own' with 'bl.appleCopyList_02[0]'
            ...

Now the Player uses his Mouse over any and Near sensors to detect the added Apple object respectively Near_apple . If he detects them together,

bge.logic.appleCopyList_01[0].endObject()

ends that Apple object. We use here a list which contains the pointer to the added object to call the endObject() function. Beneath in ### apple_add(cont) ### we will write this pointer to the list and the list to the logic.

GENERAL 2 :
Our problem is that the added object is a copy of the object on the 2. layer (in this case Apple ), and we have to get this copy to manipulate it (to end it). The copy is each time when added to the scene another pointer, so we need to get each individual copy.NOTE : If we would use Apple instead of the pointer to its copy, i.e. Apple.endObject() (and the other code adapted to this), we could delete the copy too, but there are two copies in the scene, and we couldn’t know which one the player would click on (first) to get it … If he click on an Apple it could be deleted in that place where he have clicked, or in the other, and in the later case the Apple clicked on stays in scene, till he would click another time on it. Furthermore he could drop the Apple only to the place where he have clicked on the Apple , because only there the relevant property to indicate if Apple is in the scene or not, would be changed to its actual/real status. And we would get an KeyError: “CList[key]: ‘‘Apple’’ key not in list” in the console when all Apples are deleted from the scene.

### apple_add(cont) ### Then we change the apple_add(cont) function. It will look like this:

PARTICULAR 2 :

    ...
    if own['apple_01'] == True: 
        Apple_copy_01 = scene.addObject("Apple", "Empty_apple_01", 0)
        bl.appleCopyList_01 = []
        bl.appleCopyList_01.append(Apple_copy_01)

And to the apple_add_02(cont) function, we add in the same way Apple_copy_02 = , bl.appleCopyList_02 = and bl.appleCopyList_02.append(Apple_copy_02) .

GENERAL 3 :
Apple_copy_01 = scene.addObject(“Apple”, “Empty_apple_01”, 0)
The next paragraph is taken from: https://blenderartists.org/forum/showthread.php?222769-EndObject-in-python&p=1888036&viewfull=1#post1888036 post#7 / Solarlune, thank you.
The addObject function of the scene returns a pointer to the newly created object, which you can then use to manipulate that object.
We write this pointer to Apple_copy_01 .

PARTICULAR 3 :
bge.logic.appleCopyList_01 = and bge.logic.appleCopyList_01.append(Apple_copy_01)
We create an empty list in the bge.logic and append to it Apple_copy_01 , which is the value of the pointer.
The next paragraph is taken from: https://blenderartists.org/forum/showthread.php?123797-GameLogic-properties&p=1109690&viewfull=1#post1109690 post#4 / C-106 Delta, thank you.NOTE : Just be careful when using this method. If you don’t delete the variable it will stay in memory forever !!! (or until you close the game. GameLogic isn’t cleared when you switch scenes.). If you use this method often, make sure you plan ahead and know what you are doing. If you don’t plan ahead, you may get unwanted glitches. You have been warned.

### drop_apple(cont) ### We add to drop_apple(cont) :
                ...
    if item_03.positive and open_inv.positive and Empty_apple_01['apple_01'] == False\
    and nearAny.positive:
        ...
            # we add 'Apple_copy_03 = ' in front of the line beneath
            Apple_copy_03 = own.scene.addObject("Apple", "Empty_apple_01", 0)
            bl.appleCopyList_01 = [] # we add it
            bl.appleCopyList_01.append(Apple_copy_03) # we add it
            Empty_apple_01['apple_01'] = True
            ...

And to the if statement beneath, we add in the same way Apple_copy_04 = , bl.appleCopyList_02 = and bl.appleCopyList_02.append(Apple_copy_04) .
It’s similar to what we have done in ### apple_add(cont) ### (see above).

Greetings,
achisp

Revision history:
2016-12-28.: SimpleInventory_Demo_061.blend

  • (1.) The “added object” is saved in a dictionary instead in bge.logic, and (2.) the printed inventories are sorted by key. For .blend and details see post#21 -> 3134355

Attachments

SimpleInventory_Demo_06.blend (615 KB)

Dear friends.
The last time we have used bge.logic to save a list with the pointer to the “added object”, this time we will use a dictionary for saving the pointer. It’s saver.
The result of both is the same, and the explanations signed with GENERAL 1 to 3 in Part 1 are valid for both parts.
To use the dictionary instead of bge.logic ,we have to substitute the relevant code (shown in the paragraphs signed with PARTICULAR 1 to 3 in Part 1) with the code shown in the this chapter. The commentaries in the code tags of this chapter are referred to this process of substitution.

The basic code for this chapter is taken from: https://blenderartists.org/forum/showthread.php?366780-BGE-HELP-Set-object-name-via-python&p=2843323&viewfull=1#post2843323 post#6 / youle, thank you.

myDict = {} # we add it

We initialize an empty dictionary named myDict on indent level zero (to make it global) in the module file header.

def apple_add(cont):
    ...
        Apple_copy_01 = scene.addObject("Apple", "Empty_apple_01", 0) # it's the same code
        myDict['Apple_copy_01'] = Apple_copy_01

We write the pointer of the “added object” to Apple_copy_01 and to myDict .

def get_apple(cont):
        ...
            Apple_copy_01 = myDict["Apple_copy_01"]
            Apple_copy_01.endObject()
            ...

We write the pointer which we got in apple_add(cont) to Apple_copy_01 and use it to end the Apple , in this case the one of Empty_apple_01 , for Empty_apple_02 we make the same with that “added Apple”.

def drop_apple(cont):
        ...
            Apple_copy_01 = scene.addObject("Apple", "Empty_apple_01", 0) # it's nearly the same
            myDict['Apple_copy_01'] = Apple_copy_01
            ...

When we drop the Apple to Empty_apple_01 , the code is the same as in apple_add(cont) before.
When the player takes that Apple the next time, he will use the get_apple(cont) function, implicitly using the pointer saved here. Every time the player drops the Apple here, the actual pointer will be saved to be used there (and the anterior pointer saved to Apple_copy_01 will be overwritten).

### How to sort a dictionary by key or value ###
If we use sorted() on a dictionary, it returns a list of its sorted keys, but we want a sorted dictionary with keys and values.

The next code is taken from: https://docs.python.org/3.5/library/collections.html#ordereddict-examples-and-recipes #8.3.6.1 / Python documentation team, thank you.

sorted(Invent_01.items(), key=lambda t: t[0])

To achieve it, we use sorted() and at the same time we employ the items() method on the dictionary Invent_01 .
The next paragraph is taken from: http://www.python-course.eu/python3_dictionaries.php #Lists from dictionaries / Bernd Klein, thank you
items() can be used to create a list consisting of 2-tuples of (key,value)-pairs.

key=lambda t: t[0]
Then we use a lambda function * to select the first or second element of these (key,value) pairs. [0] ** is the first, [1] the second element.
The result is that we can sort the dictionary Invent_01 by key with sorted(Invent_01.items(), key=lambda t: t[0]) and by value with sorted(Invent_01.items(), key=lambda t: t[1]) .
NOTE * : The next three paragraphs are taken from: http://www.python-course.eu/lambda.php #lambda operator / Bernd Klein, thank you
The lambda operator or lambda function is a way to create small anonymous functions, i.e. functions without a name. These functions are throw-away functions, i.e. they are just needed where they have been created. The general syntax of a lambda function is quite simple:

lambda argument_list: expression

The argument list consists of a comma separated list of arguments and the expression is an arithmetic expression using these arguments. You can assign the function to a variable to give it a name.

NOTE ** : The next two paragraphs are taken from: https://en.wikibooks.org/wiki/Python_Programming/Sequences#Strings /Wikibooks team, thank you
In Python the elements in arrays and the characters in strings can be accessed with the square brackets, or subscript operator.
Indexes are numbered from 0 to n-1 where n is the number of items (or characters).

Greetings
achisp

Attachments

SimpleInventory_Demo_061.blend (616 KB)

a very late reaction, so i guess you already know this, but to answer your question.

I don’t understand, can you please post an example ? Maybe with Empty_homekey ? Or I take a look with google, later.
Ahh, I think I understand.
Code:
if Empty_home[‘homekey’]:

if not Empty_homekey[‘homekey’]:

I have to initialize the property before ?

you have a property that is boolean, or you want to check if a property is filled/set.

you do:


if property == True:
        #do stuff
    
    if property == False:
        #return or error handling or anything else

what you can do with above is get rid of a double check.
so you get this:

    if property:
        #do stuff
        #inhere the return of the property is true or the property is set that also results in true
    
    if not property:
        #return or error handling or anything else
        #inhere the property is false or not set

Hello Cotaks.

Thank you for your answer.
I don’t already knew it and right now I don’t understand.
What is the advantage of the second method (get rid of the double check) ?
There you check also two times, only the indentation is different.

I lack also knowledge about “return” and “error handling”. I have seen it in your scripts, and I have read a bit about “return”, but my knowledge isn’t deep.

But don’t worry to much about it.

achisp