Python - баг в системе инвентаря для текстовой РПГ
Помогите найти баг. Думаю, это как-то связано с глобальными переменными или лупом while.
Такое ощущение, что когда item_for_put_on_1.name меняет значение - все переменные в коде, которые ранее присваивали эту переменную - тоже меняют наименование на новое, что как-то странно. И не знаю, как это баг вычистить.
А если пытаюсь после надевания очищать значение item_for_put_on_1.name, то оно очищается и в надетых вещах, т.е. придмет теряется.
Python 3.7.0
IDLE 3.6. (64-bit)
Sublime Text 3.1.1.(3176)
#сначала я создал классы для предметов и слотов для предметов, все тут перечислять не буду, но вот один из тестовых слотов (в него помещается вещь, которую собирается надеть игрок):
class item_for_put_on:
    def __init__(self):
    self.name = ''
    self.body_part = '' #тут указывается для какой части тела вещь
#тут вычеркнул много неважного сейчас кода, оставил только объявление некоторых переменных:
right_hand_item_1 = right_hand_item() 
on_head_item_1 = on_head_item() 
item_for_put_on_1 = item_for_put_on() 
item_check_on = item_check_on_class() 
right_hand_item_1.name = ''
right_hand_item_1.body_part = ''
on_head_item_1.name = ''
on_head_item_1.body_part = ''
item_for_put_on_1.name = ''
item_check_on.name = ''
i_stick = ['Stick', 'in_hands']
i_helmet = ['Helmet', 'on_head']
all_item_names = {'Stick' : i_stick, 'Helmet' : i_helmet}

def item_put_on():
    global item_for_put_on_1, right_hand_item_1, on_head_item_1
    if item_for_put_on_1.body_part == 'on_head' and on_head_item_1.name == '':
        on_head_item_1.name = item_for_put_on_1.name
        #возврат к функции главного меню
    if item_for_put_on_1.body_part == 'in_hands'and right_hand_item_1.name == '':
        right_hand_item_1.name = item_for_put_on_1.name
        #возврат к функции главного меню

#def inventory_menu(): ---эту и многие другие функции не буду описывать, нет смысла

def inventory_bag():
    #сюда игрок переходит из главного меню инвентаря, чтобы посмотреть, что есть в сумке
    #global item_check_on, item_for_put_on_1 ---- должны ли тут быть глобальные переменные?
    #здесь был код, описывающий содержимое сумки, тут все работает нормально
    #теперь игрок решает, какую вещь выбрать для чтения информации о ней, а затем будет решать надеть её или нет!!
    #command4 - это список команд, построенный из названий вещей в сумке, с ним всё ок. 
    com4 = input ("> ")
    while com4 not in commands4 and com4.lower() != 'back':
        print ("Unknown command, try again.\n")
        com4 = input ("> ")
    if com4 in commands4: 
        ppp = com4
        for i in all_item_names: #i - str!!!
            if ppp == all_item_names[i][0]: 
                item_check_on.name = all_item_names[i][0]
                item_check_on.body_part = all_item_names[i][1]
                # remember ---- i_stick = ['Stick', 'in_hands']
                # remember ---- i_helmet = ['Helmet', 'on_head']
                # remember ---- all_item_names = {'Stick' : i_stick, 'Helmet' : i_helmet}
                print("You are looking to the item " + item_check_on.name) #это отображает инфу о предмете для игрока
                print("item body part: " + item_check_on.body_part) #это отображает инфу о предмете для игрока
                ppp = ''
                com4=''
                print ("Would you like to 'equip'('eq') it or 'back'?\n")
                com5 = input ("> ")
                commands5 = ['back', 'equip', 'eq']
                while com5.lower() not in commands5:
                    print ("Unknown command, try again.\n")
                    com5 = input ("> ") 
                if com5.lower() == 'back':
                    inventory_bag()
                    break
                elif com5.lower() in ['equip', 'eq']:
                    item_for_put_on_1.name = all_item_names[i][0]
                    item_for_put_on_1.body_part = all_item_names[i][1]
                    item_put_on()
                    break
                break
            else: 
                print('test looping') #while возвращается сюда снова и снова, чтобы перебирать имена в словаре
                if ppp == '' and action4 == '':
                    break
    elif action4.lower() == 'back':
        #inventory_menu()

def inventory_eq():
    #сюда попадаем из главного меню инвентаря, когда хотим посмотреть, что надето на героя
    #global right_hand_item_1, on_head_item_1 ---- глобалс тут надо использовать?
    print("right arm - " + str(right_hand_item_1.name) + "\n")
    print("head - " + str(on_head_item_1.name) + "\n")
    #И вот здесь выдаётся неправильная инфа --- если до этого меню надеваешь одну вещь, то все ок, но если следом вторую - то обе вещи получают одинаковое имя, как у второй вещи - будет либо две палки (одна на голове, одна в руке) или два шлем (один в руке, другой на голове)

Без ответа.


Просмотров: 485

» Лучшие комментарии


BrEd Pitt #1 - 11 месяцев назад 1
пока что не могу сказать, в чем конкретно проблема, но посоветую сделать дебаг как запись имен переменных в тхт каждый ход - если переменные действительно меняют названия, станет заметно. Пока думаю, что дело с лупом и массивом all_item_names
(у меня была похожая проблема, но со спрайтами для роглайковских крипов, жуки свиду становились скелетами при появлении первого скелета)
Возможно, while и if друг друга теснят где-то, опять же, видел что-то такое на стаковерфлоу, пока свою проблему исправлял (не на пайтоне, но все же), мб стоит это дело переосмыслить чутка синтаксически
nvc123 #2 - 11 месяцев назад 3
если что, то . это оператор обращения к содержимому объекта
т.е. меняя item_for_put_on_1.name ты меняешь поле name у объекта записанного в item_for_put_on_1
все объекты хранятся по ссылкам а не по значениям
т.е. в следующем коде все переменные (v1, v2, v3, v4) указывают на 1 и тот же объект
v1 = item_for_put_on()
v2 = v1
v3 = v1
v4 = v2
vasex #3 - 11 месяцев назад (отредактировано ) 0
nvc123, звучит хорошо... Но я попробовал заменить таким образом:
Чтобы избавиться от сторонних проверочных классов типа item_for_put_on_1, я решил переносить в функцию item_put_on() не это, а сохранить нужную i !!!
Для этого добавил переменную qqq, которая присвает значение i (это строка - название из словаря, которые перебираются лупом while при поиске вещи, которую игрок хочет надеть), сделал qqq глобальной в обеих функциях.
А затем присваиваю теперь к слоту левой руки или головы не item_for_put_on_1, а уже напрямую значение через словарь (т.е. если бы ты был прав, ошибки быть уже не должно):
left_hand_item_1.name = all_item_names[qqq][0]
left_hand_item_1.body_part = all_item_names[qqq][1]
или
on_head_item_1.name = all_item_names[qqq][0]
on_head_item_1.body_part = all_item_names[qqq][1]
Соответственно подкорректировал все проверки, всё работает, как и раньше, первая вещь без проблем помещается в нужный слот.
Но со второй вещью происходит ровно то же самое, как и раньше, она заменяет имя и в on_head_item_1.name и в left_hand_item_1.name, т.е. опять два шлема в разных частях тела.
Тут в чем-то другом проблема. Такое ощущение, что не вижу чего-то до глупости очевидного.
vasex #5 - 11 месяцев назад (отредактировано ) 0
хм, помогла замена все этих объектов-классов на простые переменные (которые я объявил везде глобалами):
xx = all_item_names[i][0]
xxx = all_item_names[i][1]
или
zz = all_item_names[i][0]
zzz = all_item_names[i][1]
Теперь код работает, как надо. в руке (хх) - палка, в голове (zz) - шлем, как не ворочай, всё получается.
Только я, наверное, всё равно слишком тупой, чтобы понять, почему не работает это:
  1. один объект присваивает значение словаря при одном условии...
  2. совершенно другой объект, никак не связанный с предыдущим (кроме слова name и одного и того же словаря, но с разными i в зависимости от условий), присваивает совершенно другое значение словаря при совершенно другом условии...
  3. но почему-то в итоге в обоих объектах в итоге записано одно и то же свежее значение из словаря... и проблема, как теперь известно, не в i, которое корректно в зависимости от условий меняет значение словаря...
name ведь не общее у двух разных объектов двух разных классов, а как бы характеризует своё уникальное значение, ну как у одного героя имя одно, а у другого имя другое, я даже классы их разделил (right_hand_item_1 = right_hand_item() и on_head_item_1 = on_head_item()), а не делал общий, хотя и так по логике вроде не должно было быть одинаково...ну и не вижу других примеров в коде, когда из-за общего написания слов "name" у каких-то разных объектов что-либо совпадало (а объектов много разных с name).
Мне бы хотелось в этом разобраться.
Т.е. если в твоём примере ситуация и понятна, ок, то у меня была один пример назад несколько иная ситуация всё же!
v1 = right_hand_item()
v1.name = "блабла"
&
v2 = on_head_item()
v2.name = "блублу"
и почему же тогда v1.name = v2.name = блублу ?
nvc123 #6 - 11 месяцев назад 0
vasex, скорее всего потому что v1 == v2
либо гдето перемудрил с присваиваниями либо right_hand_item() и on_head_item() возвращают один и тотже объект