Ходил бродил по просторам интернета и случайно наткнулся на статью о создании мини rpg игры текстового типа на python. И так как я очень люблю всяческие Hello world-ы, то не смог пройти мимо.
Ознакомившись со статьёй и комментариями к ней я решил тряхнуть стариной и повторить опыт автора в написании простенькой игры, конечно же модернизировав код и проверив его работоспособность.
Получилось у меня что-то типа этого:
https://gist.github.com/basimka/2a54ae0b256ecf057e2ebc839c718a66
Конечно же этого было мало и я начал писать дальше. В результате
-
Теперь у меня есть несколько комнат
-
По комнатам можно передвигаться
-
Можно взаимодействовать с предметами (поднимать, надевать)
-
Можно нападать на монстров и драться с ними
-
В планах прикрутить взлом замков… и прочие плюшки
Но статья моя будет конечно же сосредоточена на том что бы описать весь тот ужос который я напрограммировал и подтолкнуло меня к этому два факта:
-
Факт 1. В интернете не так много уроков или примеров текстовых игр на python. В основном всё концентрируется на игровом движке, картинках и конечном результате. В текстовой игре ты заморачиваешься над логикой игры, над механиками. Ни что не стоит потратить пару часов и накидать на python прототип какой либо игры. Ну а что может помешать потом прикрутить графику?…
-
Факт 2. Это статья как раз сможет показать мне интерес к данной теме. У одного меня и пары моих друзей(всего у одного) так горят руки сделать что нибудь этакое не прибегая к дизайну и художеству, а реализуя логику игры с помощью текста, спецсимволов, ну и естественно.
Собственно Игра
Начинается всё с того что мы добавляем в игру библиотеку randomizer и будущую библиотеку с картинками:
# Для начала импортируем рандомайзер from random import randint # Добавляем библиотеку с картинками from pictures import pic_Start
Создаём в этой же директории файл с именем pictures.py и создаём в нем функцию с нашим лого:
def pic_Start(): print(''' ############################################################################################ ############################################################################################ # ## ## ###### ## ## ## ## ######## ######## ## ###### # # ### ### ## ## ## ## ## ## ## ## ## ## ## ## ## ## # # ## ## ## ######## ## ## ### ### ## ## ###### ## ## ## # # ## ## ## ## ## ## ## ## ######## ## ## ######## ###### # ############################################################################################ ############################################################################################ ''' )
Теперь если мы где-то вызовем pic_Start() то вызовем печать нашего лого.
Вернёмся к нашему основному файлу. Реализация состояния «в битве» не «в битве» я решил реализовать с помощью глобальной переменной agressive, если agressive > 0 значит на вас кто-то напал, если нет то всё ОК :
#Объявление глобальной переменной агрессия #Если агрессия есть то значит и по шапке получить можно global agressive agressive = 0
Далее мы выводим наш logo и описываем Class Player
###Приветственный экран pic_Start() # Это класс Персонажа, так как версия игры сейчас однопользовательская # то экземпляр класса Игрока только один class Player: inventar = [] inventar_str = [] def __init__(self, hp, damage, mana, haco): self.hp = hp self.damage = damage self.mana = mana self.haco = haco lvl = 1 exp = 0 if exp >= 256000: lvl = 10 elif exp >= 128000: lvl = 9 elif exp >= 64000: lvl = 8 elif exp >= 32000: lvl = 7 elif exp >= 16000: lvl = 6 elif exp >= 8000: lvl = 5 elif exp >= 4000: lvl = 4 elif exp >= 2000: lvl = 3 elif exp >= 1000: lvl = 2 def __str__(self): pass #Так как экземпляр класса Игрока у нас должен быть доступен отовсюду, # то для начала мы делаем его глобальным, а потом уже создаем сам # экземпляр класса global p p = Player(100,10,0,20)
Class Player создаёт класс у которого есть inventar = [] — сюда помещаются всяческие мечи доспехи, которые игрок надел. И так как мне не удалось нормально выводить названия этих предметов то их названия хранятся в отдельном списке inventar_str = []. Через def _init_ задаём разные параметры персонажа, а с помощью p = Player(100,10,0,20), создаём экземпляр класс Player с параметрами hp = 100, damage = 10, mana = 0, haco = 20.
Класс противника делаем по тому же образу и подобию
#Экземпляр класса противника, во многом схож с игроком, но экземпляров класса будет куча class Enemy: def __init__(self,name,hp,damage,mana,haco,exp): self.hp = hp self.damage = damage self.mana = mana self.name = name self.haco = haco self.exp = exp def __str__(self): return str(self.name) e = Enemy('мышь',80,10,0,20,10) Rabbit = Enemy('кролик',100,15,0,20,20)
Так же реализуем класс оружия:
############################## Оружие ########################### class Weapon: def __init__(self,name,damage,stability): self.name = name self.damage = damage self.stability = stability def __str__(self): return str(self.name) woodstick = Weapon('Палка',10,5) clows = Weapon('Когти',20,20) knife = Weapon('Нож',20,10) sword = Weapon('Меч',25,15) staff = Weapon('Посох',15,15)
Ну а дальше становится всё интереснее и интереснее, так как в любой RPG необходимо передвигаться по пещерам и полям, то мы вводим в игру такое понятие как комната(Room) и собственно описываем класс комната:
####################### Комнаты ################################## class Room: name = 'Комната' vihody = ['ю','з'] orujie = sword vragy = e opisanie =('\n' + '\ ###################\n' + f'\ Вы попали в {name}\n'+'\ ###################\n'+'\ Выходы есть только:\n'+ f'\ {vihody}\n') r0 = Room()
У комнаты есть название — name. В комнате могут быть выходы — vihody, оружие может валяться на полу — orujie и собственно в комнате могут находится враги — vragy.
Описание комнаты у нас выполнен с применением спецсимволов \n — переход на другую строчку f — позволяет использовать в тексте ссылки на переменные {name} и \ — перенос кода на новую строчку. В конце мы конечно же вызываем экземпляр класса.
Инвентарь мы тоже реализовали с помощью класса, в принципе здесь нет ни чего интересного разве что кроме things = [] и str_things = []. Как и в прошлом примере в things мы помещаем класс предмета а в str_things его название.
# Инвентарь. Было принято решение вынести инвентарь в отдельный класс. class inventar(): golds = 0 things = [] str_things = [] potions = [] scrolls = [] limit = 10 inv = inventar()
Играя в игру мы будем вызывать разного рода информативные меню (посмотреть, инвентарь, помощь и т.д.). Эти меню должны отображать информацию о вещах и параметрах за которые отвечают:
######################### Меню Посмотреть########################### def do_look(): print(maplocation.opisanie) if maplocation.orujie != 0: print (f'Валяется {maplocation.orujie}') if maplocation.vragy != 0: print (f'В углу скалится {maplocation.vragy}') ######################### меню Инвентарь ########################### def menu_inventory(): print ('Ваше золото = ' , inv.golds) print ('Ваши вещи = ' , inv.str_things) print ('Ваши свитки = ' , inv.scrolls) print ('Ваши бутылочки = ' , inv.potions) print ('Свобдных слотов =' , inv.limit) input("Нажмите Enter для продолжения.") ########################## Меню статистика ######################### def menu_stats(): print('Статистика игрок') print('****************') print (f'hp = {p.hp}') print (f'damage = {p.damage}') print (f'mana = {p.mana}') print (f'exp = {p.exp}') print (f'На вас надеты = {p.inventar_str}') input("Нажмите Enter для продолжения.") ########################## Меню Битва ######################### ### Пока не задействовано def menu_prefight(): print (f''' (1) Сражаться (2) Посмотреть статистику (3) Вызвать меню помощи (4) Выход из игры ''') ########################## Основное меню ######################### def start_menu(): print (f''' Введите и нажмите Enter см (смотреть) - Осмотреться хр (характеристики) - Характеристики инв (инвентарь) - Инвентарь ? (Помощь) - Вызвать меню помощи выход (прочь) - Выход из игры взять - Поднять или взять что есть в комнате надеть - Надеть что-то из инвентаря напасть - Напасть на кого нибудь ''') ############################ Меню Помощи ######################### def menu_help(): print('####################################') print('Помочь ты сможешь только себе сам!!!') print('####################################')
Вызывая ту или иную функцию мы будем видеть необходимую информацию, например если мы вызовем:
start_menu()
то мы увидим:

Из неизвестного у нас здесь появляется переменная maplocation
Далее станет известно что в зависимости от комнаты в которой мы находимся maplocation принимает значение этой комнаты, например:
maplocation = r0
И если мы сменим комнату то и значение maplocation тоже поменяется.
И так, продолжим. Далее у нас следует гигантский блок под названием «Действие»
############## Основная функция действия ######################### def deystvie(n): global x global maplocation if n == 'см': do_look() elif n == 'смотреть': do_look() elif n == 'хр': menu_stats() elif n == 'характеристики': menu_stats() elif n == 'инв': menu_inventory() elif n == 'инвентарь': menu_inventory() elif n == '?': start_menu() elif n == 'помощь': start_menu() elif n == 'выход': quit() elif n == 'прочь': quit() elif n == 'надеть': print ('Что вы хотите надеть?') print (inv.str_things) fg = input('Введите название предмета: ') i = 0 while i < len(inv.things): if str(fg) == str(inv.things[i]): print (f'Вы надели {inv.things[i]}') p.inventar.append(inv.things[i]) p.inventar_str.append(str(inv.things[i])) p.damage = p.damage + inv.things[i].damage del inv.things[i] del inv.str_things[i] i+=1 elif n == 'напасть': if maplocation.vragy != 0: print ('На кого вы хотите напасть? \n') print (maplocation.vragy) fg = input('Введите название врага: ') if str(fg) == str(maplocation.vragy): print (f'Вы напали на {maplocation.vragy}') global agressive agressive = agressive + 1 fight() elif n == 'ю': if maplocation.name == 'Комната': print('\n Вы перешли на юг') maplocation = r3 elif maplocation.name == 'Комната1': print('\n Тут стена, идти не куда') elif maplocation.name == 'Комната3': print('\n Тут стена, идти не куда') elif n == 'з': if maplocation.name == 'Комната': print('\n Вы перешли на запад') maplocation = r1 elif maplocation.name == 'Комната1': print('\n Тут стена, идти не куда') elif maplocation.name == 'Комната3': print('\n Тут стена, идти не куда') elif n == 'в': if maplocation.name == 'Комната': print('\n Тут стена, идти не куда') elif maplocation.name == 'Комната1': print('\n Вы перешли на восток') maplocation = r0 elif maplocation.name == 'Комната3': print('\n Тут стена, идти не куда') elif n == 'с': if maplocation.name == 'Комната': print('\n Тут стена, идти не куда') elif maplocation.name == 'Комната1': print('\n Тут стена, идти не куда') elif maplocation.name == 'Комната3': print('\n Вы перешли на север') maplocation = r0 elif n == 'взять': if maplocation.orujie != 0: print ('\n Что вы хотите взять? \n') print (maplocation.orujie) vz = input('Введите название предмета: ') if str(vz) == str(maplocation.orujie): print (f'Вы взяли {maplocation.orujie}') inv.things.append(maplocation.orujie) inv.str_things.append(str(maplocation.orujie)) maplocation.orujie = 0 else: print ('Ни чего не произошло')
В функцию действие мы передаём значение n, ну а n у нас равно тому что пользователь введёт в строчку ввода. Если мы введём «см» или «смотреть» то запустим функцию do_look(), если введём хр или характеристики то запустим функцию menu_stats(). Если же ввод не будет удовлетворять ни одному условию то else нам выдаст «Ни чего не произошло».
Из наиболее интересных вещей у нас здесь есть «надеть», «напасть»,»взять». Попробуйте самостоятельно разобраться как они работают.
def fight(): global agressive while agressive != 0: print('Вы hp:',p.hp) print('Вы damage: ',p.damage) print("**********************") print('Враг hp:',e.hp) print('Враг damage: ',e.damage) print("**********************") print("**********************") print("1)Ударить") print("2)Хил 0-5") n = input("Введите число: ") if n == '1': # Здоровье врага отнимает от вашего дамага. e.hp -= p.damage print('Вы ударили противника, у него осталось', e.hp) # Здоровье игрока отнимает от дамага врага. p.hp -= e.damage print('Противник ударил вас, у вас осталось',p.hp) print("*********************") if p.hp < 0: print("Вы проиграли") agressive = agressive - 1 quit() elif e.hp < 0: print("Вы победили") agressive = agressive - 1 p.exp = p.exp + maplocation.vragy.exp maplocation.vragy = 0 elif n == '2': # Рандомно от 0 до 5 добавляет хп. p.hp += randint(0,5) # Если здоровье игрока больше, то хп игрока будет равна 100. if p.hp > 100: p.hp = 100 #print('Ваши хп',p.hp) else: print("Чего ждем?")
И так, функция битвы, собственно для чего всё и задумывалось. Правда битва пока получилась не очень заурядная, при каждом раунде мы выбираем что делать, ударить или «отхилится», если выбираем ударить, то обмениваемся с врагом ударами, если у кого-то здоровье меньше ноля, то тот проиграл.
Остается дело за малым, выводим справку:
start_menu()
Объявляем и обнуляем агрессию, и запускаем основной цикл игры.
global maplocation maplocation = r0 global agressiv agressiv = False ############################## Основной игровой цикл ########################### while True: # Предлагаем выбрать действие n = input('Введите что нибудь: ') # Обрабатываем выбранное действие deystvie(n) # Проверяем не напал ли на нас кто-то # Пока не работает proverka_enimy()
Весь код игры ниже:
# Для начала импортируем рандомайзер from random import randint # Добавляем библиотеку с картинками from pictures import pic_Start #Объявление глобальной переменной агрессия #Если агрессия есть то значит и по шапке получить можно global agressive agressive = 0 ###Приветственный экран pic_Start() # Это класс Персонажа, так как версия игры сейчас однопользовательская # то экземпляр класса Игрока только один class Player: inventar = [] inventar_str = [] def __init__(self, hp, damage, mana, haco): self.hp = hp self.damage = damage self.mana = mana self.haco = haco lvl = 1 exp = 0 if exp >= 256000: lvl = 10 elif exp >= 128000: lvl = 9 elif exp >= 64000: lvl = 8 elif exp >= 32000: lvl = 7 elif exp >= 16000: lvl = 6 elif exp >= 8000: lvl = 5 elif exp >= 4000: lvl = 4 elif exp >= 2000: lvl = 3 elif exp >= 1000: lvl = 2 def __str__(self): pass #Так как экземпляр класса Игрока у нас должен быть доступен отовсюду, # то для начала мы делаем его глобальным, а потом уже создаем сам # экземпляр класса global p p = Player(100,10,0,20) #Экземпляр класса противника, во многом схож с игроком, но экземпляров класса будет куча class Enemy: def __init__(self,name,hp,damage,mana,haco,exp): self.hp = hp self.damage = damage self.mana = mana self.name = name self.haco = haco self.exp = exp def __str__(self): return str(self.name) e = Enemy('мышь',80,10,0,20,10) Rabbit = Enemy('кролик',100,15,0,20,20) ############################## Оружие ########################### class Weapon: def __init__(self,name,damage,stability): self.name = name self.damage = damage self.stability = stability def __str__(self): return str(self.name) woodstick = Weapon('Палка',10,5) clows = Weapon('Когти',20,20) knife = Weapon('Нож',20,10) sword = Weapon('Меч',25,15) staff = Weapon('Посох',15,15) ####################### ЗамкИ #################################### ####################### Комнаты ################################## class Room: name = 'Комната' vihody = ['ю','з'] orujie = sword vragy = e opisanie =('\n' + '\ ###################\n' + f'\ Вы попали в {name}\n'+'\ ###################\n'+'\ Выходы есть только:\n'+ f'\ {vihody}\n') class Room1: name = 'Комната1' vihody = ['в'] orujie = knife vragy = 0 opisanie =('\n' + '\ ###################\n' + f'\ Вы попали в {name}\n'+'\ ###################\n'+'\ Выходы есть только:\n'+f'\ {vihody}\n') class Room2: name = 'Комната2' vihody = ['в','ю',''] orujie = sword vragy = 0 opisanie =('###################\n' + f'\ Вы попали в {name}\n'+'\ ###################\n'+'\ Здесь ни чего нет\n'+'\ ###################\n'+'\ Выходы есть только:\n'+f'\ {vihody}\n') class Room3: name = 'Комната3' vihody = ['с',] orujie = staff vragy = 0 opisanie =('\n' + '\ ###################\n' + f'\ Вы попали в {name}\n'+'\ ###################\n'+'\ Выходы есть только:\n'+f'\ {vihody}\n') class Room4: name = 'Комната4' vihody = ['в','ю','с','з'] orujie = sword vragy = [] opisanie =('###################\n' + f'\ Вы попали в {name}\n'+'\ ###################\n'+'\ Здесь ни чего нет\n'+'\ ###################\n'+'\ Выходы есть только:\n'+f'\ {vihody}\n') class Room5: name = 'Комната5' vihody = ['в','ю'] orujie = sword vragy = [] opisanie =('###################\n' + f'\ Вы попали в {name}\n'+'\ ###################\n'+'\ Здесь ни чего нет\n'+'\ ###################\n'+'\ Выходы есть только:\n'+f'\ {vihody}\n') class Room6: name = 'Комната6' vihody = ['с','з'] orujie = sword vragy = [] opisanie =('###################\n' + f'\ Вы попали в {name}\n'+'\ ###################\n'+'\ Здесь ни чего нет\n'+'\ ###################\n'+'\ Выходы есть только:\n'+f'\ {vihody}\n') class Room7: name = 'Комната7' vihody = ['в','з','с'] orujie = sword vragy = [] opisanie =('###################\n' + f'\ Вы попали в {name}\n'+'\ ###################\n'+'\ Здесь ни чего нет\n'+'\ ###################\n'+'\ Выходы есть только:\n'+f'\ {vihody}\n') class Room8: name = 'Комната8' vihody = ['в','с'] orujie = sword vragy = [] opisanie =('###################\n' + f'\ Вы попали в {name}\n'+'\ ###################\n'+'\ Здесь ни чего нет\n'+'\ ###################\n'+'\ Выходы есть только:\n'+f'\ {vihody}\n') r0 = Room() r1 = Room1() r2 = Room2() r3 = Room3() r4 = Room4() r5 = Room5() r6 = Room6() r7 = Room7() # Инвентарь. Было принято решение вынести инвентарь в отдельный класс. class inventar(): golds = 0 things = [] str_things = [] potions = [] scrolls = [] limit = 10 inv = inventar() ######################### Меню Посмотреть########################### def do_look(): print(maplocation.opisanie) if maplocation.orujie != 0: print (f'Валяется {maplocation.orujie}') if maplocation.vragy != 0: print (f'В углу скалится {maplocation.vragy}') ######################### меню Инвентарь ########################### def menu_inventory(): print ('Ваше золото = ' , inv.golds) print ('Ваши вещи = ' , inv.str_things) print ('Ваши свитки = ' , inv.scrolls) print ('Ваши бутылочки = ' , inv.potions) print ('Свобдных слотов =' , inv.limit) input("Нажмите Enter для продолжения.") ########################## Меню статистика ######################### def menu_stats(): print('Статистика игрок') print('****************') print (f'hp = {p.hp}') print (f'damage = {p.damage}') print (f'mana = {p.mana}') print (f'exp = {p.exp}') print (f'На вас надеты = {p.inventar_str}') input("Нажмите Enter для продолжения.") ########################## Меню Битва ######################### ### Пока не задействовано def menu_prefight(): print (f''' (1) Сражаться (2) Посмотреть статистику (3) Вызвать меню помощи (4) Выход из игры ''') ########################## Основное меню ######################### def start_menu(): print (f''' Введите и нажмите Enter см (смотреть) - Осмотреться хр (характеристики) - Характеристики инв (инвентарь) - Инвентарь ? (Помощь) - Вызвать меню помощи выход (прочь) - Выход из игры взять - Поднять или взять что есть в комнате надеть - Надеть что-то из инвентаря напасть - Напасть на кого нибудь ''') ############################ Меню Помощи ######################### def menu_help(): print('####################################') print('Помочь ты сможешь только себе сам!!!') print('####################################') ############## Основная функция действия ######################### def deystvie(n): global x global maplocation if n == 'см': do_look() elif n == 'смотреть': do_look() elif n == 'хр': menu_stats() elif n == 'характеристики': menu_stats() elif n == 'инв': menu_inventory() elif n == 'инвентарь': menu_inventory() elif n == '?': start_menu() elif n == 'помощь': start_menu() elif n == 'выход': quit() elif n == 'прочь': quit() elif n == 'надеть': print ('Что вы хотите надеть?') print (inv.str_things) fg = input('Введите название предмета: ') i = 0 while i < len(inv.things): if str(fg) == str(inv.things[i]): print (f'Вы надели {inv.things[i]}') p.inventar.append(inv.things[i]) p.inventar_str.append(str(inv.things[i])) p.damage = p.damage + inv.things[i].damage del inv.things[i] del inv.str_things[i] i+=1 elif n == 'напасть': if maplocation.vragy != 0: print ('На кого вы хотите напасть? \n') print (maplocation.vragy) fg = input('Введите название врага: ') if str(fg) == str(maplocation.vragy): print (f'Вы напали на {maplocation.vragy}') global agressive agressive = agressive + 1 fight() elif n == 'ю': if maplocation.name == 'Комната': print('\n Вы перешли на юг') maplocation = r3 elif maplocation.name == 'Комната1': print('\n Тут стена, идти не куда') elif maplocation.name == 'Комната3': print('\n Тут стена, идти не куда') elif n == 'з': if maplocation.name == 'Комната': print('\n Вы перешли на запад') maplocation = r1 elif maplocation.name == 'Комната1': print('\n Тут стена, идти не куда') elif maplocation.name == 'Комната3': print('\n Тут стена, идти не куда') elif n == 'в': if maplocation.name == 'Комната': print('\n Тут стена, идти не куда') elif maplocation.name == 'Комната1': print('\n Вы перешли на восток') maplocation = r0 elif maplocation.name == 'Комната3': print('\n Тут стена, идти не куда') elif n == 'с': if maplocation.name == 'Комната': print('\n Тут стена, идти не куда') elif maplocation.name == 'Комната1': print('\n Тут стена, идти не куда') elif maplocation.name == 'Комната3': print('\n Вы перешли на север') maplocation = r0 elif n == 'взять': if maplocation.orujie != 0: print ('\n Что вы хотите взять? \n') print (maplocation.orujie) vz = input('Введите название предмета: ') if str(vz) == str(maplocation.orujie): print (f'Вы взяли {maplocation.orujie}') inv.things.append(maplocation.orujie) inv.str_things.append(str(maplocation.orujie)) maplocation.orujie = 0 else: print ('Ни чего не произошло') def proverka_enimy(): pass def fight(): global agressive while agressive != 0: print('Вы hp:',p.hp) print('Вы damage: ',p.damage) print("**********************") print('Враг hp:',e.hp) print('Враг damage: ',e.damage) print("**********************") print("**********************") print("1)Ударить") print("2)Хил 0-5") n = input("Введите число: ") if n == '1': # Здоровье врага отнимает от вашего дамага. e.hp -= p.damage print('Вы ударили противника, у него осталось', e.hp) # Здоровье игрока отнимает от дамага врага. p.hp -= e.damage print('Противник ударил вас, у вас осталось',p.hp) print("*********************") if p.hp < 0: print("Вы проиграли") agressive = agressive - 1 quit() elif e.hp < 0: print("Вы победили") agressive = agressive - 1 p.exp = p.exp + maplocation.vragy.exp maplocation.vragy = 0 elif n == '2': # Рандомно от 0 до 5 добавляет хп. p.hp += randint(0,5) # Если здоровье игрока больше, то хп игрока будет равна 100. if p.hp > 100: p.hp = 100 #print('Ваши хп',p.hp) else: print("Чего ждем?") ### Основноe меню start_menu() ############################## Глобальные переменные ########################### #global x #x = 1 global maplocation maplocation = r0 global agressiv agressiv = False ############################## Основной игровой цикл ########################### while True: # Предлагаем выбрать действие n = input('Введите что нибудь: ') # Обрабатываем выбранное действие deystvie(n) # Проверяем не напал ли на нас кто-то # Пока не работает proverka_enimy()
Игра постоянно дорабатывается и по ссылкам в Git будет обновляться. Надеюсь данная статься поможет кому нибудь воплотить свои задумки в жизнь.
ссылка на оригинал статьи https://habr.com/ru/articles/904624/
Добавить комментарий