Python OOP游戏代码故障:Goblin正常,Elf的Hit功能异常
Hey Nathan, let's fix those issues with your Elf class step by step! I spotted two key problems that are causing the "hit elf" command to fail, plus another bug that would crash your game when the Elf's health drops to 1.
1. Case Mismatch in Class Name
Your Elf class sets self.class_name = "Elf" (capital E), but when you type hit elf (lowercase e), the hit function checks if "elf" exists in GameObject.objects—which it doesn't, because the dictionary key is "Elf". This is why the command falls through to the "There is no elf here." message.
2. Undefined Variable in Elf's desc Property
In the Elf class's desc property, when self.health == 1, you reference str(x) but x isn't defined in that branch. This would throw a NameError if the Elf's health ever reaches 1.
Bonus: Minor Optimization Note
Right now, GameObject.objects uses class_name as the key, which means if you ever create multiple instances of the same class, they'll overwrite each other. A better approach would be to use the instance's name or a unique identifier, but since you only have one Elf and one Goblin, this isn't breaking your game right now—just something to keep in mind for future expansion.
Here's the fixed code with comments pointing out the changes:
#importing the random module import random #creating the game object class class GameObject: class_name = "" desc = "" objects = {} def __init__(self, name): self.name = name # Changed: store class name in lowercase for case-insensitive lookups GameObject.objects[self.class_name.lower()] = self #defining the description def get_desc(self): return self.class_name + "\n" + self.desc #creating the goblin class class Goblin(GameObject): def __init__(self, name): self.class_name = "goblin" self.health = 3 self._desc = "A foul creature" super().__init__(name) @property def desc(self): if self.health >= 3: return self._desc elif self.health == 2: x = random.randint(13, 35) health_line = "You struck and dealt " + str(x) + " damage!" elif self.health == 1: y = 40 - random.randint(13, 35) health_line = "You rushed and dealt " +str(y) + " damage! \n Goblin activated effect Rage!" elif self.health <= 0: health_line = "It is dead." return self._desc + "\n" + health_line @desc.setter def desc(self, value): self._desc = value #creating the goblin object goblin = Goblin("Gobbly") #creating the elf class class Elf(GameObject): def __init__(self, name): self.class_name = "Elf" self.health = 5 self._desc = "A strong warlock" super().__init__(name) @property def desc(self): if self.health >= 5: return self._desc elif self.health == 4: x = random.randint(20, 50) health_line = " You struck and dealt " + str(x) + " damage!" elif self.health == 3: x = random.randint(20, 40) health_line = " You countered and dealt " + str(x) + " damage!" elif self.health == 2: y = 40 - random.randint(20, 50) health_line = "You rushed and dealt " +str(y) + " damage! \n Elf activated effect Sectum Sempra!!" elif self.health == 1: # Fixed: defined y variable here instead of using undefined x y = random.randint(20, 50) health_line = " You struck and dealt " + str(y) + " damage!" elif self.health <= 0: health_line = "It is dead." return self._desc + "\n" + health_line @desc.setter def desc(self, value): self._desc = value #creating an elf object elf = Elf("Elfy") #defining the hit verb def hit(noun): # Changed: convert input noun to lowercase to match stored keys noun_lower = noun.lower() if noun_lower in GameObject.objects: thing = GameObject.objects[noun_lower] if type(thing) == Goblin: thing.health -= 1 if thing.health <= 0: msg = "You killed the goblin!" else: msg = "You hit the {}".format(thing.class_name) elif type(thing) == Elf: thing.health -= 1 if thing.health <= 0: msg = "You killed the elf!" else: # Optional: lowercase for consistent message msg = "You hit the {}".format(thing.class_name.lower()) else: msg = "There is no {} here.".format(noun) else: msg = "There is no {} here.".format(noun) return msg #defining the examine verb def examine(noun): # Changed: convert input noun to lowercase for case-insensitive lookups noun_lower = noun.lower() if noun_lower in GameObject.objects: return GameObject.objects[noun_lower].get_desc() else: return "There is no {} here.".format(noun) #getting input def get_input(): command = input(": ").split() verb_word = command[0] if verb_word in verb_dict: verb = verb_dict[verb_word] else: print("Unknown verb {}".format(verb_word)) return if len(command) >= 2: noun_word = command[1] print(verb(noun_word)) else: print(verb("nothing")) #defining the say verb def say(noun): return 'You said "{}"'.format(noun) #the verbs verb_dict = { "say": say, "examine": examine, "hit": hit } while True: get_input()
Key Fixes Explained:
Case-Insensitive Lookups:
- Modified
GameObject.__init__to store objects usingself.class_name.lower()as the key, so both "elf" and "Elf" will match. - Updated the
hitandexaminefunctions to convert the input noun to lowercase before checking the dictionary, making commands case-insensitive (sohit Elfworks too!).
- Modified
Undefined Variable Fix:
- In the Elf's
descproperty, thehealth == 1branch now definesy(instead of trying to usex, which only exists in higher health branches) to avoid a NameError.
- In the Elf's
Consistent Message (Optional):
- Changed the Elf hit message to use
thing.class_name.lower()so it says "You hit the elf" instead of "You hit the Elf" for consistency with the Goblin message.
- Changed the Elf hit message to use
Now when you type hit elf, it should correctly register the hit and show the feedback message, plus the game won't crash when the Elf's health drops to 1.
内容的提问来源于stack exchange,提问作者nathan

