我使用Python已有大约3个月的时间,并决定制作一个简单的文字冒险游戏,以娱乐并运用我一直在学习的很多想法。我最近才了解有关类和OOP以及模块的信息,因此这是我最不确定的两个功能。它主要是一个基础,并设置了两个房间,但是我以它的可读性和良好的风格而感到骄傲(尽管我承认没有什么可比拟的。)到目前为止,我有四个模块我之所以彼此区分,主要是出于可读性。我对类的使用是肤浅的,请让我知道我可以对其进行改进!到目前为止,我已经设置了两个房间。

主模块:

 """ This is the main file, it contains the functions for the rooms as well as the startup sequences."""

import actions
import room_info as rooms
import character_and_items as char

"""TODO LIST:
-Implement save features(Save module?)
-Add some spunk into the descriptions, make it fun yet concise!!
"""

# output
def print_frog_title():
    print("   ____                ___     __              __              ")
    print("  / __/______  ___ _  / _ |___/ /  _____ ___  / /___ _________ ")
    print(" / _// __/ _ \/ _ `/ / __ / _  / |/ / -_) _ \/ __/ // / __/ -_)")
    print("/_/ /_/  \___/\_, / /_/ |_\_,_/|___/\__/_//_/\__/\_,_/_/  \__/ ")
    print("             /___/                                             ")

# input
def check_start():
    print_frog_title()
    print("                 A game by Mopi Productions ")
    print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
    print("For a list of commands type 'h', 'help', or '?'")


def load_room(room):
    char.current_room = room
    room_dict = {
        "burrow": burrow,
        "burrow_basement": burrow_basement,
        "front_of_house": front_of_house
    }
    func = room_dict.get(room, lambda: "ERROR")  # To be quite frank I don't really understand lambda: ERROR yet
    func()


def burrow():
    print("You are in your burrow. The front door is to the north.")
    while True:
        action = actions.get_action(rooms.burrow)
        if action[0] == "mopi":
            load_room(action[1])
        if action == "down":
            if rooms.burrow.variables["trapdoor_opened"] and "lantern" in char.character_inventory:
                load_room("burrow_basement")
                break
            elif not rooms.burrow.variables["rug_moved"]:
                print("You cant go that way!")
            elif rooms.burrow.variables["rug_moved"] and not rooms.burrow.variables["trapdoor_opened"]:
                print("The trapdoor is shut.")
            elif "lantern" not in char.character_inventory:
                print("It's far too dark down there, you should stay up here until you find a light source.")
        elif action == "north":
            if rooms.burrow.variables["door_unlocked"]:
                load_room("front_of_house")
            else:
                print("The front door is locked!")
        elif action in rooms.directions:
            print("You cant go that way!")
        elif action[0] == "examine":
            if action[1] in ("rug", "carpet", "lump"):
                if not rooms.burrow.variables["rug_moved"]:
                    print("Upon further examination, the 'lump' appears to be handle shaped. You should try moving "
                          "the rug.")
                else:
                    print("Your beloved family heirloom has been rudely shoved against a wall. What would Aunt Frogatha think?")
            elif action[1] == "door":
                print("Your door is locked. You'd unlock it, but you've lost the key.")
            elif action[1] == "cabinet":
                if rooms.burrow.variables["cabinet_opened"]:
                    if rooms.burrow.variables["jar_taken"]:
                        print("It's an open cabinet with barren shelves.")
                    else:
                        print("It's an open cabinet with barren shelves excepting a single empty jar.")
                else:
                    print("It's a closed cabinet where you keep your dishware.")
        elif action[0] == "move":
            if action[1] in ("rug", "carpet"):
                if not rooms.burrow.variables["rug_moved"]:
                    print("You moved the rug, and underneath you found a trapdoor! This isn't a new discovery.")
                    rooms.burrow.variables["rug_moved"] = True
                else:
                    print("You've already kicked the rug into the corner! Better to not do any more damage.")
        elif action[0] == "use":
            if action[1] == "trapdoor" and rooms.burrow.variables["rug_moved"]:
                print("You opened the trapdoor.")
                rooms.burrow.variables["trapdoor_opened"] = True
            elif action[1] == "door":
                if not rooms.burrow.variables["door_unlocked"] and "key" not in char.character_inventory:
                    print("The door is locked, and you seem to have misplaced your key.")
                elif not rooms.burrow.variables["door_unlocked"] and "key" in char.character_inventory:
                    print("The door is locked, you should using your key.")
                else:
                    load_room("burrow_basement")
                    break
        elif action[0] == "open":
            if action[1] == "trapdoor" and rooms.burrow.variables["rug_moved"]:
                print("You opened the trapdoor.")
                rooms.burrow.variables["trapdoor_opened"] = True
            elif action[1] == "door":
                if not rooms.burrow.variables["door_unlocked"] and "key" in char.character_inventory:
                    print("You unlocked the front door! Welcome to the outside ")
                elif "key" not in char.character_inventory:
                    print("The door is locked, and you seem to have misplaced your key.")
                else:
                    print("The door is already open!")
            elif action[1] == "cabinet":
                if not rooms.burrow.variables["jar_taken"]:
                    print("You opened the cabinet, there is an empty jar inside.")
                    rooms.burrow.room_contents.append("jar")
                else:
                    print("You opened the cabinet, it is empty")
        elif action[0] == "close":
            if action[1] == "trapdoor" and rooms.burrow.variables["rug_moved"]:
                print("You closed the trapdoor.")
                rooms.burrow.variables["trapdoor_opened"] = False
            elif action[1] == "door":
                print("The door is already closed, you like it that way.")
        else:
            continue

def burrow_basement():
    print("You are in your basement. There is a trapdoor above you.")
    while True:
        action = actions.get_action(rooms.burrow_basement)
        if action == "up":
            if rooms.burrow.variables["trapdoor_opened"]:
                load_room("burrow")
                break
            else:
                print("The trapdoor is shut.")
        elif action in rooms.directions:
            print("You can't go that way!")
        elif action[0] == "examine":
            if action[1] == "key_hook":
                if "key" in rooms.burrow_basement.room_contents:
                    print("It is a handmade key hook your Uncle Frogert made. Its single hook remains unoccupied.")
                else:
                    print("It is handmade key hook your Uncle Frogert made. It holds an old key.")
            elif action[1] == "icebox":
                print("It is an icebox where you store your cold foods, but it hasn't been filled in months.")
        elif action[0] == "move":
            if action[1] == "icebox" and not rooms.burrow_basement.variables["icebox_moved"]:
                pass
            elif action[1] == "icebox":
                pass
        elif action[0] == "use":
            if action[1] == "icebox" and not rooms.burrow_basement.variables["icebox_opened"]:
                rooms.burrow_basement.variables["icebox_opened"] = True
                if not rooms.burrow_basement.variables["fish_sticks_taken"]:
                    print("You opened the icebox, there's a lonely box of fish sticks inside with colorful writing on it.")
                    rooms.burrow_basement.room_contents.append("fish_sticks")
                else:
                    print("You opened the icebox, it's empty devoid of a few lonely ice cubes. ")
            elif action[1] == "icebox":
                print("You closed the icebox like a good roommate.")
                rooms.burrow_basement.variables["icebox_opened"] = False
                if "fish_sticks" in rooms.burrow_basement.room_contents and not rooms.burrow.variables["fish_sticks_taken"]:
                    rooms.burrow_basement.room_contents.remove("fish_sticks")
        elif action[0] == "open":
            if action[1] == "trapdoor" and not rooms.burrow.variables["trapdoor_opened"]:
                print("You opened the trapdoor.")
                rooms.burrow.variables["trapdoor_opened"] = True
            elif action[1] == "trapdoor":
                print("The trapdoor is already opened.")
            elif action[1] == "icebox" and not rooms.burrow_basement.variables["icebox_opened"]:
                rooms.burrow_basement.variables["icebox_opened"] = True
                if not rooms.burrow_basement.variables["fish_sticks_taken"]:
                    print("You opened the icebox, there's a lonely box of fish sticks inside with colorful writing on it.")
                    rooms.burrow_basement.room_contents.append("fish_sticks")
                else:
                    print("You opened the icebox, it's empty devoid of a few lonely ice cubes. ")
        elif action[0] == "close":
            if action[1] == "trapdoor" and rooms.burrow.variables["rug_moved"]:
                print("You closed the trapdoor.")
                rooms.burrow.variables["trapdoor_opened"] = False
            elif action[1] == "icebox" and rooms.burrow_basement.variables["icebox_opened"]:
                print("You closed the icebox like a good roommate.")
                rooms.burrow_basement.variables["icebox_opened"] = False
                if "fish_sticks" in rooms.burrow_basement.room_contents and not rooms.burrow.variables["fish_sticks_taken"]:
                    rooms.burrow_basement.room_contents.remove("fish_sticks")
        else:
            continue

def front_of_house():
    print("You are in front of your burrow")
    while True:
        break

"""
def room_template():
    print("ROOM. EXITS")
    while True:
        action = actions.get_action(rooms.ROOM)
        if action[0] == "mopi":
            load_room(action[1])
        if action == DIRECTION:

        elif action in rooms.directions:
            print("You cant go that way!")
        elif action[0] == "examine":

        elif action[0] == "move":

        elif action[0] == "use":

        elif action[0] == "open":

        elif action[0] == "close":

        else:
            continue
"""

def main():
    check_start()
    print(
        "You are in a burrow, but not just any burrow. The burrow you reside in is in fact"
        "\nthe estate of Von Frogerick III, who just so happens to be your great great grandfather."
        "\nThe immense and fascinating history of your lineage matters not though, for you are hungry."
        "\nYou should find a fly to eat.")
    load_room("burrow")


main()


动作模块:

  """This is the actions module, it contains functions required to process user input and
    processes minor actions itself"""

import random
import room_info as rooms
import character_and_items as char

snarky_remark_list = ["And how exactly are you going to do that?", "Fat chance", "In your dreams", "Inconceivable!",
                      "Aunt Frogatha would be ashamed.."]

# Commands to add, - eat - anything else?

# output
def print_help():
    print("--HELP--\n-'l' or 'look' - Provides description of room\n-'north' or 'n' - goes in specified direction"
          "\n-'examine' + object to examine it more closely\n-'move' + object to move an object"
          "\n-'use' + object to use an object\n-'down' or 'd' - move up or down"
          "\n-'inventory' or 'i' - displays inventory\n-'open' or 'close' - opens or closes an object"
          "\n-'read' - reads an object\n-'use __ on __' - uses one object on another")


# this checks if the complex action is able to be performed on the object given
def actions_match(complex_u_in, room):
    if (complex_u_in[0] == "take" and complex_u_in[1] in rooms.take_ob(room)) \
            or (complex_u_in[0] == "use" and complex_u_in[1] in rooms.use_ob(room)) \
            or (complex_u_in[0] == "examine" and complex_u_in[1] in rooms.exam_ob(room)) \
            or (complex_u_in[0] == "move" and complex_u_in[1] in rooms.mov_ob(room)) \
            or (complex_u_in[0] in ("open", "close") and complex_u_in[1] in rooms.open_ob(room)):
        return True
    else:
        return False

# Consider moving this into the items module?
def use_on(obj1, obj2):
    if obj1 == "key" and char.current_room == "burrow" and "key" in char.character_inventory and obj2 == "door":
        rooms.burrow.variables["door_unlocked"] = True
        print("You unlocked the door!")

# Sort objects under the world class into an array.
def get_room_contents(room):
    return rooms.exam_ob(room) + rooms.use_ob(room) + rooms.mov_ob(room) + rooms.take_ob(room) + rooms.open_ob(room)


# Every action that doesn't return an input should be ended with return False
# a complex action is an action containing more than one word.
def check_complex_actions(room, complex_u_in):
    room_contents_list = get_room_contents(room)

    # relabeled for readability
    action = complex_u_in[0]
    item = complex_u_in[1]

    try:
        # Dev command to load rooms for testing
        if action == "mopi" and item in rooms.all:
            return ["mopi", item]
        # Dropping items is a character based action, and not a room based. Therefore it is separated.
        if len(complex_u_in) == 4 and (action == "use" and complex_u_in[2] == "on") \
                and (char.use_on_items[item] == complex_u_in[3]):
            use_on(item, complex_u_in[3])
            return False
        elif len(complex_u_in) == 3 and (item + "_" + complex_u_in[2]) in char.double_word_list:
            item = item + "_" + complex_u_in[2]
            complex_u_in.pop()

        if action == "drop" and item in char.character_inventory:
            rooms.append_to_room(room, item)
            char.character_inventory.remove(item)
            print("You dropped the " + item)
            return False
        elif action == "take" and item in rooms.take_ob(room):
            if item in rooms.contents(room):
                char.character_inventory.append(item)
                rooms.remove_from_room(room, item)
                # This removes the underscore in two-word objects
                if "_" in item:
                    item = item.replace("_", " ")
                print("You took the " + item)
                return False
            else:
                print("You see no such thing!")
                return False
        elif action == "read" and (item in room_contents_list or item in char.character_inventory):
            item_description = char.get_description(item, "read")
            if item_description != "":
                if "_" in item:
                    item = item.replace("_", " ")
                print("The " + item + " reads: " + item_description)
            else:
                print("You can't read that!")
            return False
        elif action == "examine" and (item in char.character_inventory or
                            (item in rooms.contents(room) and item not in rooms.exam_ob(room))):
            item_description = char.get_description(item, "examine")
            if "_" in item:
                item = item.replace("_", " ")
            print(item_description)
            return False
        elif item in room_contents_list:
            if actions_match(complex_u_in, room):
                return complex_u_in
            elif action[0] == "examine":
                print("There's nothing to see of importance.")
            else:
                print(random.choice(snarky_remark_list))
                return False
        else:
            print("You see no such thing!")
            return False
    except IndexError:
        # In case user inputs half of a command
        print(action + " what?")
        return False

def get_action(room):
    complex_actions = ["move", "use", "examine", "take", "drop", "open", "close", "read", "mopi"]
    while True:
        # u_in stands for user input
        u_in = input("-> ").lower().strip()
        print()
        complex_u_in = u_in.split(" ")
        if complex_u_in[0] in complex_actions:
            u_in = check_complex_actions(room, complex_u_in)
            if u_in != False:  # Consider editing this bit? little sloppy
                return u_in
            else:
                # This loops if an action is not returned.
                continue
        if u_in in ("h", "?", "help"):
            print_help()
        elif u_in in ("look", "l"):
            rooms.get_description(room)
        elif u_in in ("inventory", "i"):
            char.print_inventory()
        elif u_in in ("north", "n"):
            return "north"
        elif u_in in ("south", "s"):
            return "south"
        elif u_in in ("west", "w"):
            return "west"
        elif u_in in ("east", "e"):
            return "east"
        elif u_in in ("northwest", "nw"):
            return "northwest"
        elif u_in in ("northeast", "ne"):
            return "northeast"
        elif u_in in ("southwest", "sw"):
            return "southwest"
        elif u_in in ("southeast", "se"):
            return "southeast"
        elif u_in in ("down", "d"):
            return "down"
        elif u_in in ("up", "u"):
            return "up"
        elif u_in in ("ribbit", "r"):
            print("you let out a cute ribbit")
        elif u_in in ("fuck", "shit", "damn"):
            print("That was awfully rude of you :(")
        elif u_in == "heck":
            print("No swearing!!!! >:(")
        elif u_in in ("mopi", "mopi productions"):
            print("Mopi says: 'eat hot pant,, lie.'")
        else:
            print("That command was not recognized")


字符和项目模块:

"""This is the character module, it stores information on the character and items."""

double_word_list = ["fish_sticks", "key_hook", "front_door", "bedroom_door"]

character_inventory = []
current_room = None

def print_inventory():
    if len(character_inventory) < 1:
        print("Your pockets are empty! Wait, how do frogs have pockets?")
    else:
        print("--INVENTORY--")
        for item in character_inventory:
            print("-" + item)

# This could get tedious for every item in the game, look for an alternative solution?
def get_description(item, form):
    item_dict = {
        "pamphlet": pamphlet,
        "fish_sticks": fish_sticks,
        "key": key,
        "lantern": lantern,
        "photo": photo,
        "jar": jar
    }

    ob = item_dict.get(item, lambda: "ERROR")

    try:
        if form == "read":
            return ob.read_description
        elif form == "examine":
            return ob.exam_description
    except AttributeError:
        return "There's nothing to see of importance."

use_on_items ={
    "key": "door"
}


class Items:
    def __init__(self, read_desc, exam_desc):
        self.read_description = read_desc
        self.exam_description = exam_desc

pamphlet = Items("The flies future is YOUR Future. Donate today!",
                 "This is an annoying pamphlet, it came in the mail")
fish_sticks = Items("MOPI Brand Fish Sticks! Unethically sourced, deep fried fun!",
                    "These fish sticks are LONG expired, and unethically sourced at that. Better leave them be.")
key = Items("34TH BURROW STREET",
            "It's an old cast iron key, it's been in your family for generations.")
lantern = Items("",
                "It's a trusty oil lamp. It provides plenty of light, and was just recently topped off.")
photo = Items("Forever yours and always :) Jan. 10, 1993",
              "It's a wedding photo of your Aunt Frogatha and Uncle Frogert. They're posing in front of the pond, "
              "many flies can be seen buzzing in the background. There's something written on the back.")
jar = Items("",
            "It is an empty glass jar.")


房间信息模块:

"""This module contains information on every room as well as the room class"""

directions = ["north", "n", "south", "s", "east", "e", "west", "w", "up", "u", "down", "d"]
all = ["burrow", "burrow_basement"]

# This is a workaround for the from room_info import * method.
# Ideally this would all be one function, with a room parameter and an info parameter
def exam_ob(room):
    return room.examinable_objects
def use_ob(room):
    return room.usable_objects
def mov_ob(room):
    return room.movable_objects
def take_ob(room):
    return room.takeable_objects
def open_ob(room):
    return room.open_ob
def contents(room):
    return room.room_contents
def append_to_room(room, item):
    room.room_contents.append(item)
def remove_from_room(room, item):
    try:
        room.room_contents.remove(item)
    except ValueError:
        print("You see no such thing!")


def get_description(room):
    print(room.description)
    if room == burrow:
        if not burrow.variables["rug_moved"]:
            print("There is a handwoven rug lying in the center of your room, with a bothersome lump in the middle.")
        elif burrow.variables["rug_moved"] and not burrow.variables["trapdoor_opened"]:
            print("There is a handwoven rug rudely shoved in to the corner. In the center of your room, there is a "
                  "shut trapdoor.")
        else:
            print("There is a handwoven rug rudely shoved in to the corner. In the center of your room is an open "
                  "trapdoor. Talk about a safety hazard!")

        if "lantern" in burrow.room_contents:
            print("A lit lantern hangs loosely on the wall.")
        if "pamphlet" in burrow.room_contents:
            print("An annoying informational pamphlet lies on the floor.")
        if "photo" in burrow.room_contents:
            print("A framed photo rests cheerily on the mantle.")
        if burrow.variables["cabinet_opened"]:
            print("There is an open cabinet on the far wall where you store dishware.")
        else:
            print("There is a shut cabinet on the far wall.")

        for item in burrow.room_contents:
            if item not in ("lantern", "pamphlet", "cabinet", "photo", "jar"):
                print("You've left a " + item + " here.")
    if room == burrow_basement:
        if not burrow_basement.variables["icebox_moved"]:
            if not burrow_basement.variables["icebox_opened"]:
                print("A securely shut ice box sits near the ladder.")
            else:
                print("An open ice box sits near the ladder")
        elif burrow_basement.variables["icebox_moved"]:
            if not burrow_basement.variables["icebox_opened"]:
                print("A knocked over ice box lies miserably near the ladder, luckily its still latched shut.")
            else:
                print("A knocked over ice box lies miserably near the ladder, spilling its contents everywhere."
                      "\nIf only someone hadn't knocked it over...")
        if "fish sticks" in burrow_basement.room_contents:
            if burrow_basement.variables["icebox_moved"] and burrow_basement.variables["icebox_opened"]:
                print("A box of fish sticks is rapidly defrosting on the floor.")


class World:
    def __init__(self, exam_ob, mov_ob, use_ob, take_ob, open_ob):
        self.examinable_objects = exam_ob
        self.movable_objects = mov_ob
        self.usable_objects = use_ob
        self.takeable_objects = take_ob
        self.open_ob = open_ob

burrow = World(["rug", "door", "lump"], ["rug"], ["door", "trapdoor", "cabinet"], ["lantern", "pamphlet", "photo", "jar"],
               ["front_door", "trapdoor", "bedroom_door", "cabinet"])
burrow.room_contents = ["lantern", "pamphlet", "photo", "cabinet"]
burrow.description = "You're in a cozy burrow, and a well furnished one at that. The room is lit by an assortment of " \
                     "\nwarm candles and lanterns. Your front door is to the north, and the door to your Aunt and " \
                     "Uncle's bedroom lies to the South West"
burrow.variables = {
    "rug_moved": False,
    "trapdoor_opened": False,
    "door_unlocked": False,
    "cabinet_opened": False,
    "jar_taken": False
}

burrow_basement = World(["key_hook", "key", "icebox", "fish_sticks"], ["icebox"], ["icebox"], ["fish_sticks", "key"], ["trapdoor", "icebox"])
burrow_basement.room_contents = ["key", "icebox"]
burrow_basement.description = "You're in a muddy basement that serves as more of a storage room than any sort of " \
                              "living quarters.\nThere is a key hook on the far wall." \
                              " A ladder leads out of the basement."
burrow_basement.variables = {
    "icebox_moved": False,
    "icebox_opened": False,
    "fish_sticks_taken": False
}


评论

如果您这样做是为了学习编程和Python,请继续进行游戏,这是一个很好的实验。如果您实际上是在尝试制作文字冒险游戏,我建议您考虑使用TADS 3,它是为此目的而精心设计的系统。

正如@xxbbcc正确指出的那样,这是学习Python的好方法,但是如果您的目标是编写交互式小说,请查看Inform7。这是构建此类游戏的惊人复杂系统。

构造事物的另一种方法是LambdaMOO,其中所有事物都是一个对象,而播放器类型的命令则作为这些对象上的方法实现。对象具有继承性,并且具有一些内置属性,例如所有者和位置,但是几乎所有的东西,包括人,房间,容器,门,甚至是文本编辑器,都通过最终用户编写的方法来实现,并且将属性添加到最低限度中对象。

#1 楼

游戏的有趣开始。我想看看结果如何。


文本冒险游戏通常是数据驱动的。这意味着您将拥有一个游戏引擎(程序),该程序可以读取游戏描述文件(数据),并对游戏中每个位置的每个动作执行相同的指令,从而根据游戏数据产生不同的结果。

您写的不是数据驱动的。您在burrow()中具有处理操作的功能,对于burrow_basement()具有另一个功能,对于front_of_house()具有另一个功能。这些功能的代码看起来非常相似,而且非常重复,这就是为什么我们只编写一次并根据数据更改结果的原因。
游戏编写方式存在问题是递归。如果您从洞穴开始,则可以下到地下室或北到房子的前面。这些操作中的每一个都调用永不返回的load_room(location),并调用其自己的函数来处理该新房间位置。例如,如果您下到地下室,则会调用load_room("burrow_basement"),并调用burrow_basement(),作为对“ up”动作的响应,它将调用load_room("burrow"),后者将调用burrow()。我们越来越深入到调用堆栈中。如果玩家继续探索,最终他们将遇到Python的堆栈限制。您可以通过增加堆栈大小来解决此问题,但这只是一个麻烦。正确的解决方案是摆脱递归。


对象模型

地点

您应该先定义一些东西。喜欢房间。房间是玩家可以进入的位置。房间名称应简短(“厨房”,“地下室”)和较长的描述。玩家之前可能没有来过房间。它将具有到其他位置的连接(出口)。房间里可能有物品。

class Room:
    def __init__(self, name, description):
        self.name = name
        self.description = description
        self.visited = False
        self.exits = { }
        self.contents = []


事物

除了房间,世界上到处都是物体。事物将具有名称,也许还有描述。可以携带某些东西(照片,小册子,罐子……),而其他东西必须保留在原处(炉子,水槽)。可以穿一些东西,例如大衣或帽子。它可能是隐藏的:

class Thing:
    def __init__(self, name, description):
        self.name = name
        self.description = description
        self.fixed = False
        self.moved = False
        self.wearable = False
        self.concealed = False


容器

有些东西可以放在其他东西里面。在冰盒中可以找到鱼条。冰盒通常是关闭的,但偶尔会打开。某些容器可能被锁定,例如柜子。可能会看到一些容器,例如瓷器柜。您可以爬进一些容器,例如衣柜或汽车,但大多数都不能。

class Container(Thing):
    def __init__(self, name, description):
        super().__init__(name, description)
        self.contents = []
        self.open = False
        self.locked = False
        self.key = None
        self.transparent = False
        self.enterable = False


房间是容器吗?房间有名称,描述和内容。它们是可输入的。

支持者

有些东西可以放在其他东西上。您可以在桌子上放一个罐子。您可以将钥匙挂在钩子上。因此,也许应该将某些容器视为支持者。您甚至可以输入一些支持者,例如爬上床。

动画

有些东西可以四处走动,并且有行为。您可以与其中的一些人交谈,例如店主,他们会与您交谈。

其他店员可能不会说话,例如猫。

店主(有生命的东西)可能穿着带口袋的裤子(一个容器),里面可能装有怀表(可打开)。

玩家是动画容器吗???他们可以存放东西(清单),四处走动(动画),拿东西(容器),拿东西,穿东西。门可以打开或关闭。如果关闭,则它可能被锁定,也可能未被锁定。

class Door(Thing):
    def __init__(self, name, description, key=None)
        self.name = name
        self.description = description
        self.open = False
        self.lockable = key is not None
        self.locked = True if key else False
        self.key = key
        self.connects = []


living_room = Room("Living Room", "A place for the family to hang out")
dining_room = Room("Dining Room", "Many meals were had here")
basement = Room("Basement", "A dark and dingy hole in the ground")

trap_door = Door("Trap door", "A piece of wood, with a basic hinge and a ring handle")
trap_door.concealed = True
trap_door.connects = [living_room, basement]

dining_room.exits["south"] = living_room
living_room.exits["north"] = dining_room
living_room.exits["down"] = trap_door
basement.exits["up"] = trap_door


在这里,我们有两个从客厅出来的出口,直接向北到饭厅(无门),一直到trap_doortrap_door处于隐藏状态,因此,如果玩家在客厅里并且尝试“下沉”,则最初他们应该得到“您不能那样走”。移动地毯应露出活板门(标记为未隐藏),允许通过活板门到达其连接的其他位置。也许:

rug = Thing("A rug", "A thick heavy rug, passed down through the ages")
rug.fixed = True
def rug_move():
    print("You pull back the corner of the rug, revealing a trap door")
    rug.description = "One corner of the rug has been lifted to reveal a trap door"
    trap_door.concealed = False
rug.on_move = run_move


现在,如果您的游戏逻辑允许您键入“ lift rug”或“ move rug”,则可以解析单词“ rug”,找到对象在location.contents中使用该名称,并调用该对象的.on_move()函数,该函数可以告诉您发生了什么,更改地毯的描述,并从活板门中删除隐蔽的属性。 />
可以帮助您入门。灯笼只是一个Thingrug实际上是Rug(特殊的Thing),具有在frog.py游戏文件中定义的操作。

请注意,冒险游戏框架可用于许多不同的游戏。 />这是您以前使用的一种“更好”的方法,但是我不会说这是一个好方法。该框架有很多细节需要刷新,并进行了重新设计以包括更好的可见性和可触摸性。项目应该有一个.has_light属性(可选)。如果房间.has_light本身的属性设置为True,或者房间中的某个项目具有该属性,除非该项目位于封闭的容器中(除非该容器是透明的)。

如果继续沿着这条路,最终您将重新发明Inform 7交互式小说框架。祝你好运。

冒险.py

COMMANDS = { 'go', 'move', 'use', 'examine', 'open', 'close', 'inventory' }

DIRECTIONS = set()
REVERSE_DIRECTION = {}

for fwd, rev in (('n', 's'), ('e', 'w'), ('u', 'd')):
    DIRECTIONS.add(fwd)
    DIRECTIONS.add(rev)
    REVERSE_DIRECTION[fwd] = rev
    REVERSE_DIRECTION[rev] = fwd

class CantSee(Exception):
    pass

class Thing:
    def __init__(self, short_description, **kwargs):
        self.short_description = short_description
        self.long_description = None
        self.concealed = False
        self.scenery = False
        self.fixed = False
        self.openable = False

        for key, value in kwargs.items():
            if not key in self.__dict__:
                raise ValueError("Unrecognized argument: "+key)
            self.__dict__[key] = value

    def description(self):
        return self.short_description

    def examine(self):
        if self.long_description:
            print(self.long_description)
        else:
            print("There is nothing special about it")

    def move(self):
        if self.fixed:
            print("You can't move it")
        else:
            print("You move it a bit.")


class Container(Thing):
    def __init__(self, short_description, **kwargs):
        self.contents = {}
        self.openable = True
        self.open = False
        self.transparent = False

        super().__init__(short_description, **kwargs)

    def containing():
        if self.contents:
            return ", ".join(item.description() for item in self.contents())
        return "nothing"


    def description(self):
        text = self.short_description
        if self.openable:
            if self.open:
                text += " (which is closed)"
            else:
                text += " (which is open)"

        if self.open or self.transparent:
            if self.contents:
                text += "(containing " + self.containing() + ")"

        return description


class Door(Thing):
    def __init__(self, short_description, **kwargs):

        self.lockable = False
        self.locked = False
        self.key = None
        self.connects = {}

        super().__init__(short_description, **kwargs)

        self.fixed = True
        self.closed = True

class Room(Thing):

    def __init__(self, name, **kwargs):
        self.exits = {}
        self.visited = False
        self.contents = set()

        super().__init__(name, **kwargs)

    def exit_to(self, direction, destination, door=None):
        reverse = REVERSE_DIRECTION[direction]

        if door:
            door.connects[direction] = destination
            door.connects[reverse] = self
            self.exits[direction] = door
            destination.exits[reverse] = door
        else:
            self.exits[direction] = destination
            destination.exits[reverse] = self

    def enter(self):
        print("Location:", self.short_description)
        if not self.visited:
            self.describe()
            self.visited = True

    def visible_things(self):
        return [item for item in self.contents if not item.concealed]

    def describe(self):
        if self.long_description:
            print(self.long_description)
            print()

        items = [item for item in self.visible_things()  if not item.scenery]

        for item in items:
            if item.concealed or item.scenery:
                continue

        if items:
            print("You see:")
            for item in items:
                print("   ", item.description())

class Player(Container):
    def __init__(self):
        super().__init__("yourself")
        self.long_description = "As good looking as ever."

        self.openable = False
        self.location = None
        self.alive = True

    def inventory(self):
        if self.contents:
            print("You are carring:")
            for item in self.contents:
                print("   ", item.description)
        else:
            print("You have nothing.")

    def go(self, direction):
        destination = self.location.exits.get(direction, None)
        if isinstance(destination, Door):
            door = destination
            destination = door.connects[direction]
            if door.concealed:
                destination = None
            elif door.closed:
                if door.locked:
                    print("You'd need to unlock the door first")
                    return
                print("First opening the", door.short_description)

        if destination:
            self.location = destination
            destination.enter()
        else:
            print("You can't go that way")

class Game:
    def __init__(self, protagonist):
        self.player = protagonist
        self.game_over = False
        self.turns = 0

    def welcome(self):
        print("A text adventure game.")

    def help(self):
        print("Examine everything.")

    def get_action(self):
        while True:
            command = input("\n> ").lower().split()

            if command:
                if len(command) == 1:
                    if command[0] in DIRECTIONS:
                        command.insert(0, 'go')
                    if command[0] == 'i':
                        command[0] = 'inventory'

                if command == ['inventory']:
                    self.player.inventory()

                elif command == ['help']:
                    self.help()

                elif command[0] == 'go':
                    if len(command) == 2 and command[1] in DIRECTIONS:
                        return command
                    else:
                        print("I'm sorry; go where?")

                elif command[0] in COMMANDS:
                    return command

                else:
                    print("I don't understand")

    def go(self, direction):
        self.player.go(direction)

    def item(self, thing):
        items = self.player.location.visible_things()
        for item in items:
            if thing in item.short_description:
                return item
        raise CantSee(thing)

    def move(self, thing):
        item = self.item(thing)
        item.move()        

    def perform_action(self, command):
        if command[0] == 'go' and len(command) == 2:
            self.go(command[1])
        elif command[0] == 'move' and len(command) == 2:
            self.move(command[1])
        else:
            print("Command not implemented")


    def play(self):
        self.welcome()

        self.player.location.enter()

        while not self.game_over:
            command = self.get_action()
            try:
                self.perform_action(command)
                self.turns += 1
            except CantSee as thing:
                print("You don't see a", thing)

        if not self.player.alive:
            print("You have died.")
        else:
            print("Game over.")


frog.py

from adventure import Thing, Room, Door, Player, Game

burrow = Room("Your Burrow")
basement = Room("Your Basement")
front_yard = Room("Your Front Yard")

front_door = Door("Front Door")
trap_door = Door("Trap Door", concealed=True)
burrow.exit_to('n', front_yard, front_door)
burrow.exit_to('d', basement, trap_door)

class Rug(Thing):
    def move(self):
        if trap_door.concealed:
            print("Moving the rug reveals a trap door to the basement.")
            trap_door.concealed = False
        else:
            super().move()

rug = Rug("a rug", fixed=True)
burrow.contents.add(rug)
lantern = Thing("a lantern")
burrow.contents.add(lantern)


player = Player()
player.location = burrow

class FrogGame(Game):
    def welcome(self):
        print("""\
You are in a burrow, but not just any burrow.  The burrow you reside in is in
fact the estate of Von Frogerick III, who just so happens to be your great
great grandfather.  The immense and fascinating history of your lineage matters
not though, for you are hungry.  You should find a fly to eat.
""")

game = FrogGame(player)

if __name__ == '__main__':

    game.play()


评论


\ $ \ begingroup \ $
嘿!首先,感谢您的答复。它非常有见地,并且确实显示了python中类的有用性。这个概念对我来说还很陌生,所以希望我介意您不要介意。根据我目前的理解,切换到对象模型基本上可以消除对房间功能的需求,而拥有一个主要功能可以通过引用类和类方法来处理动作?还会细分为多个房间吗?还是我可以通过将“移动地毯”引用到已知位于洞穴中的地毯来处理动作?如果我有重复的物品怎么办?
\ $ \ endgroup \ $
–digital_drako
20-4-10下午6:51

\ $ \ begingroup \ $
我还要补充一点,每个对象(包括动作)都应该有一个可以使用的同义词列表,因此,如果玩家选择“举地毯”,它将理解这与“移动地毯”相同。
\ $ \ endgroup \ $
–达雷尔·霍夫曼(Darrel Hoffman)
20-4-10的15:23

#2 楼

import room_info as rooms
import character_and_items as char


如果要一直以这种方式导入它们,为什么不只是分别命名模块roomschar?所有额外的输入有什么意义?顺便说一句,在文本冒险中通常会引用player;我会选择import player而不是import char,只是为了消除语法高亮显示。

您的函数print_frog_title仅在一个地方使用。您应该在此处内联它。


snarky_remark_list = ["And how exactly are you going to do that?", "Fat chance", "In your dreams", "Inconceivable!",
                      "Aunt Frogatha would be ashamed.."]


开始对源代码进行版本控制时,您会意识到缩进序列更好,这样每行只有一个元素。这使您可以添加和删除元素,而不会在历史记录中引入额外的差异。同时在每个元素上添加逗号。

snarky_remark_list = [
    "And how exactly are you going to do that?",
    "Fat chance",
    "In your dreams",
    "Inconceivable!",
    "Aunt Frogatha would be ashamed..",
]


英语语法:我注意到其中有些评论以标点符号结尾,有些则没有。另一个:您写mantle的意思是mantel。 >
character_inventory = []
current_room = None


这两个变量感觉它们应该是room_dict的数据成员。但是此模块中还有其他与播放器显然无关的东西,例如

# This could get tedious for every item in the game...
def get_description(item, form):


所以第一,我考虑将其拆分为class Playeritems模块第二,您已经知道了非繁琐的解决方案!试想一下,而不是写

pamphlet = Items("The flies future is YOUR Future. Donate today!",
                 "This is an annoying pamphlet, it came in the mail")


您写了

pamphlet = Item(
    name="pamphlet",
    read="The flies future is YOUR Future. Donate today!",
    examine="This is an annoying pamphlet, it came in the mail",
)


而不是

key = Items("34TH BURROW STREET",
            "It's an old cast iron key, it's been in your family for generations.")


你写的想像

key = Item(
    name="key",
    read="34TH BURROW STREET",
    examine="It's an old cast iron key, it's been in your family for generations.",
    use_on=["door"],
)


你能看到现在如何实现objects的构造函数吗?

编辑后:类似这样。

class Item:
    def __init__(self, name, read, examine, use_on=None):
        self.name = name
        self.read = read
        self.examine = examine
        self.use_on = use_on or []
        # self.location = burrow
        # self.inroom_description = "There is a %s here." % name


还不需要成员函数。

以及如何实施class Item? ...好吧,差不多。假设我们这样写了“游戏中所有物品”的列表!

all_items = [
    Item(
        name="pamphlet",
        read="The flies future is YOUR Future. Donate today!",
        examine="This is an annoying pamphlet, it came in the mail",
    ),
    Item(
        name="key",
        read="34TH BURROW STREET",
        examine="It's an old cast iron key, it's been in your family for generations.",
        use_on=["door"],
    ),
]


现在get_description开始是类似

def get_description(verb, noun):
    for item in all_items:
        if item.name == noun:
            if verb == "examine":
                return item.examine
            elif verb == "read":
                return item.read
    return "I don't see what you're referring to."


您可以将get_description预处理为从名称到all_items对象的字典映射,以节省该循环中的两个缩进级别。

def get_description(verb, noun):
    item = all_items_by_name.get(noun, None)
    [...]


注意我悄悄地将Item的复数形式转换为Items的单数形式,还将Item转换为form


# This is a workaround for the from room_info import * method.
# Ideally this would all be one function, with a room parameter and an info parameter
def exam_ob(room):
    return room.examinable_objects
def use_ob(room):
    return room.usable_objects


好吧,这似乎很疯狂。为什么不只用一个叫verb的地方代替,而是写一个rooms.exam_ob(room)?对消息的控制级别。 (照片在壁炉架上令人愉悦;鱼竿在地板上正在除霜;等等。)如果要增加在任意位置放置任意物体的能力,则必须找到一种处理这些消息的新方法。

您看过唐纳德·努斯的文学版冒险吗?尤其请参阅第43页的第63节。

评论


\ $ \ begingroup \ $
非常感谢您提供较小的样式指针,它确实有帮助。项目类的更好利用是超级聪明的,而且我不确定为什么我没有想到它!话虽这么说,您将如何定义类?它是一个简单的类Item:pass,还是仍然使用参数?上课肯定仍然让我感到困惑,但是我通过提问来学习得最好。谢谢你的帮助!
\ $ \ endgroup \ $
–digital_drako
20年4月10日在7:00

\ $ \ begingroup \ $
添加了对Item类的定义。
\ $ \ endgroup \ $
– Quuxplusone
20 Apr 10 '15:37