2019-04-22 01:59:13

Hi. So, I'm pretty sure I know the answer, but here we go.
Whenever we pick up an item in a game, we can't do so again unless the game restarts. I'm not talking about arcade games where the items respawn, I'm talking about game like Paladin of the Sky where if you pick up the money it'd be gone forever. My question is this: How?
Here's what I know:
1: When I write items, I typically have a central list that stores those items.
2: The items have a flag that dictates if they're picked up or not.
3: Here's where things become less clear. If the item is picked up, do I force the loop that iterates through the items to skip over the item in question effectively causing the game to not detect it?
4: I'm assuming that I need to export those items to a file of some sort. Trouble is, when would I do it? When the user saves? When they pick the item up? When they close the game? Do I open the file and rewrite all the items into it, or do I bother and find at which point exactly my item's text is?
5: When dealing with maps, would it be better to store items and the map data inside that map file, or is it better to have 2 files containing map data and items separately?

2019-04-22 05:39:45

Are using a 2D map array, or a free roaming map with just x, y, z, coordinates? If your using coordinates, you could pop items from the list that are picked up and put them into a separate "picked up" list, this way your not needlessly iterating through a large list of items that both are and aren't picked up. But if on the other hand your using a 2D map array, then you could store the items in the specific sector, as classes for example, and just purge them from the map when their picked up.

If your also exporting the files, why? If you have a save on quit function that would probably be on exit, or otherwise when players save.

-BrushTone v1.3.3: Accessible Paint Tool
-AudiMesh3D v1.0.0: Accessible 3D Model Viewer

2019-04-22 16:54:02

I'm using the independent maps and item list. My problem comes with having large amounts of items.
Say I have 2 maps, one for a cabin, and another one for a forest. The cabin holds a penknife and allows for a player to save his or her game. Here's my issue: After saving, I would need to loop through all maps and save all the items, just in case a player picked one up. This won't be a problem if I have 2 or so maps, but it will be a problem when I have numbers that go into hundreds range.

2019-04-22 23:44:11

Sorry for the double post, but I am still considering items.
@2:
If your using coordinates, you could pop items from the list that are picked up and put them into a separate "picked up" list...
So you're suggesting to have a master list of items? A list from which we can remove items as the player collects them? How would we load it into the map? Will we have a smaller item list pertaining to the map itself and then pop items from both of them after a player picks up an object? Won't that cause more memory consumption? I just wana double check that I'm understanding this correctly.

2019-04-23 03:48:56 (edited by magurp244 2019-04-23 04:02:44)

Well, some examples might help illustrate this better:

class _map(object):
    def __init__(self):
        self.items = ['','juice','herring','moose']

        self.map = [[0,0,0,0,0],
                [0,0,0,0,0],
                [0,0,0,2,0],
                [0,1,0,0,0],
                [0,0,0,0,0]]

class _user(object):
    def __init__(self):
        self.items = []
        self.xy = [0,0]

m = _map()
u = _user()

#if player is in sector with item
if m.map[u.xy[1]][u.xy[0]] > 0:
    #pick up that item into inventory
    u.items.append(m.items[m.map[u.xy[1]][u.xy[0]]])
    #remove item from map square
    m.map[u.xy[1]][u.xy[0]] = 0

This uses a tile grid map with a list index of items as a reference. This is fairly efficient as you only really need to check the current square the player occupies or adjacent squares if you like. When you pick up an item, you just set the number in the map data to something else to remove it, no need for combing through lengthly lists. You can have two 2D arrays of the same size if you like, one for map topography like walls and doors, and the other for items, or have them occupy the same array space if you like.

class _map(object):
    def __init__(self):
        self.items = [['juice',0,0],['herring',23,89],['moose',54,32]]

class _user(object):
    def __init__(self):
        self.items = []
        self.xy = [0,0]

m = _map()
u = _user()

removed = 0
for a in range(0,len(m.items),1):
    #if player is in same coordinates as item
    if u.xy[0] == m.items[a-removed][1] and u.xy[1] == m.items[a-removed][2]:
        #pick up item from map
        u.items.append(m.items.pop(a-removed))
        removed += 1

This uses a loose coordinate based system, if a player occupies the same coordinates, it removes the item from the map and loads it into the players inventory. This still isn't quite as efficient as it could be, since you could break it into localized sectors for local area collision detection to cut down on the number of items to check each cycle.

-BrushTone v1.3.3: Accessible Paint Tool
-AudiMesh3D v1.0.0: Accessible 3D Model Viewer

2019-04-23 20:30:31

I believe you misunderstand my question.
I understand how to create items. I also understand how to make the player pick them up. However, what I do not understand is saving. If I was to create a save function within your code, the player would be able to pick up hundreds of juices and other items by simply reloading the game. My question is how can I make so the items disappear when they're picked up and stay that way unless the game has been restarted? I have considered a master list, a dictionary of sorts that stores items and their locations, but then comes a problem of me having to modify the dict so it won't always load the items. The problem with that approach is the user having to redownload the game to play it again, since we do not have an original list of items because we modify our master list when a player picks something up.

2019-04-23 21:31:48 (edited by magurp244 2019-04-23 22:14:02)

Ah, saving usually consists of much more than just the players state, it also has to consist of the overall games state and the players position in it. So any change in the maps state, change in items location or existence, event trigger states, or NPC positions should all be stored to return the game to its current state at the point of saving. In the case of my first example, you would have to save the players inventory and position, and the maps array, since it stores the items positions and existence. You wouldn't have to save the list of items because its a static reference list of what items can exist, not what does exist in the map data. The second example is quite similar in that you'd need to save the players position and inventory, along with the maps item list, then restore those values when reloading to keep the games state consistent across saves.

Good points to save this data are either on exit or manually saving, although there can also be periodic auto saving in some games. You shouldn't do it every time the player picks something up, as it becomes overly redundant and process intensive.

Here's a few changes to the second example with a save and load system:

import pickle

def save():
    f = open('save.txt','w')
    #create a new list for all our data to save
    data = [u.items,u.xy,m.items]
    f.write(pickle.dumps(data))
    f.close()

def load():
    f = open('save.txt', 'r')
    box = pickle.loads(f.read())
    #load state from save file
    u.items = box[0]
    u.xy = box[1]
    m.items = box[2]
    f.close()

class _map(object):
    def __init__(self):
        self.items = [['juice',0,0],['herring',23,89],['moose',54,32]]

class _user(object):
    def __init__(self):
        self.items = []
        self.xy = [23,89]

m = _map()
u = _user()

load()
##save()

removed = 0
for a in range(0,len(m.items),1):
    #if player is in same coordinates as item
    if u.xy[0] == m.items[a-removed][1] and u.xy[1] == m.items[a-removed][2]:
        #pick up item from map
        u.items.append(m.items.pop(a-removed))
        removed += 1
-BrushTone v1.3.3: Accessible Paint Tool
-AudiMesh3D v1.0.0: Accessible 3D Model Viewer

2019-04-24 20:43:55

@7, thanks. I just have a few questions:
1: If I have 2 maps, would I apply the same logic to both of them but on a larger scale? The way I pictured it was having a dictionary with the map names being pared with their item lists. When we save, we export that dictionary and load it upon the load of the map. When we switch maps, we check if a key with the map name is present within the dictionary and if so, load the item list from the dictionary overwriting the default one. Would that be efficient? What issues can it cause?
2: The only problem I see with your example is restarting the game. Would I have to have a file that stores all of the default item lists in order to pull that off? The way I have my maps right now is them being read from a text file. Can I use a tuple instead since the default item lists will never be changed? How big can the tuple get before I should start being worried about memory usage and such?

2019-04-25 04:35:51

The example actually does address resetting, you'll notice that both the map and player classes load with a default set of items and starting positions baked in, but when the save file is loaded it changes those default settings to the currently saved state. If you wanted to start a new game, you just wouldn't overwrite those default settings. In your case, you have map and item files that you load to start new games, your baseline if you will. Those maps should be read only, any changes to them should only exist in the save game files, otherwise you won't be able to reset the games state back to its original settings. I mean, that could be an interesting mechanic, but I get the impression thats not what your going for.

Alternatively you could use procedural generation to randomize maps and item data, in which case you wouldn't need to have map files as each new game could exist only in save game data. Anyway, if you have two maps, and elements of those maps can change and stay consistent between them, then yes you need to preserve both maps state information. If your only saving dictionary keys for maps that have been changed from their default, then there isn't likely to be an issue with your suggested approach. You can help efficiency by only saving specific changes to that state data to save files, but any changes to the original map and item lists should only be in the save files.

The amount of memory usage is also hard to tell without benchmarking, but unless your making maps that are rediculously huge it shouldn't be much of an issue. But, if it is, try setting a specific maximum size of each map, and then when moving from one map to another, save the current maps state to either a temporary file or a save game file and load the new map into memory overwriting and replacing the current map.

-BrushTone v1.3.3: Accessible Paint Tool
-AudiMesh3D v1.0.0: Accessible 3D Model Viewer