我正在创建基于文本的RPG,目的是在Python中学习更多关于OOP的知识。现在事情进展顺利,但我面临一个问题,我不能找到一个好的答案:技能实施。我也认为我将面临与物品类似的问题。
目前我有3个班级(专业):Fighter
,Rogue
和Mage
。这些类中的每一个都应该有自己的技能,但是技能有类似的东西(名称,描述,MP用法),所以我创建了一个BasicSkill
类和3个子类:PassiveSkill
,{{1} }和ActiveSkill
。
解释:ChanelledSkill
是不需要MP使用的技能,总是活跃的,并且在大多数情况下,给予玩家增益,如双持,更多阻力等。{{1}是需要使用MP的技能,并且在大多数情况下会造成伤害或瞬间增益。最后,PassiveSkill
是需要使用超过一个回合的技能,比其他回合花费更多的MP,并且可以被中断
但是,当谈到技能创造时,我只能想到这样的事情:
ActiveSkill
我认为这并不是我的目标,因为我每次使用时都要实例化它,或者是同一行中的东西。
我希望以一种需要较少实例化的方式创建技能,并且还可以更多地投射。此外,所有角色(玩家,npc和敌人)都可以施放技能。
这个项目中有很多文件,所以我会在这里发布我认为更相关的文件,如果你愿意,你可以查看项目here。
这是我的ChanelledSkill
课程:
def hack_and_slash(self):
"""This is a Fighter skill, it's melee and has no cool down."""
from skills import ActiveSkill
hack_and_slash = ActiveSkill("Hack n' Slash", "A powerful double attack that has a chance of causing bleeding.",
8, 3)
self.mp -= hack_and_slash.
# more about the skill goes here, like what it does in terms of damaging, buffing, etc.
这是我的Player
课程:
from character import Character
# TODO implementation of player basic attacks and abilities
# TODO implementation of a D&D style skill system(diplomacy, stealth, streetwise, etc)
class Player(Character):
LEVEL_UP = 100 # initial XP to lvl up
COMMANDS = {'attack': 'a', 'character': 'c', 'inventory': 'i'} # commands available for the player
# in future this skills will be used inside and outside combat situations, for like take out an enemy in stealth,
# or convince a guard to let you in a closed door
SKILLS = {'persuasion': 0, 'intimidation': 0, 'stealth': 0, 'perception': 0}
DAILY_SELF_HEALS = 4 # each ingame day player can use 4 self heals, it resets after getting the rested status
ATTRIBUTES = {'strenght': 0, 'constitution': 0, 'dexterity': 0, 'intelligence': 0, 'wisdom': 0, 'charisma': 0}
def __init__(self, armor_class):
super().__init__(input("Tell us your name, hero:\n>"), 20, 10, {'gold': 10, 'torch': 1}, armor_class, 1)
self.exp = 0
self.max_hp = self.hp # max HP of the player
self.max_mp = self.mp # max MP of the player
self._strength = 0 # should I change it to dictionary with the attributes instead?
self._constitution = 0
self._dexterity = 0
self._intelligence = 0
self._wisdom = 0
self._charisma = 0
def level_up(self):
if self.exp >= self.LEVEL_UP:
self.lvl += 1
self.LEVEL_UP *= 1.25
self.LEVEL_UP = int(self.LEVEL_UP)
self.exp = 0
stat_choice = input(
"You have 2 points to spend in your attributes!\nType which attributes you want to raise up: ")
stat_choice = stat_choice.split(',')
self.ATTRIBUTES[stat_choice[0]] += 1
self.ATTRIBUTES[stat_choice[1]] += 1
self.max_hp = int(self.max_hp * 1.1)
self.max_mp = int(self.max_mp * 1.1)
return True
else:
return False
def gain_exp(self, exp):
self.exp += exp
print("You gained %d XP" % exp)
if self.level_up():
print("Congratulations, you gained a level!\nYour current level is %d\n" % self.lvl)
else:
print("Your current XP is %d/%d\n" % (self.exp, self.LEVEL_UP))
def get_loot(self, enemy):
# buggy right now, problem with remove inventory from dead enemy
for item in enemy.inventory:
while True:
get_item = input("You found %s! do you want to get it?(Y=yes/N=no/A=all items)" % item)
if get_item.lower() == "a":
self.inventory.update(enemy.inventory)
enemy.inventory = {}
return
elif get_item.lower() == "y":
self.inventory[item] = enemy.inventory[item]
enemy.inventory.pop(item, None)
break
elif get_item.lower() == "n":
break
else:
print("Unfortunately, you don't have this choice hero, take a look again...")
def combat(self, enemy):
"""
the combat between two entities(player and enemy)
:param enemy: the enemy of current character
:return:
"""
if super().combat(enemy):
self.gain_exp(10)
self.get_loot(enemy)
else:
print("\t\t[GAME OVER...]\t\t")
def self_heal(self):
if self.DAILY_SELF_HEALS > 0:
self.DAILY_SELF_HEALS -= 1
self.hp += int(self.max_hp / 4)
def rest(self):
rest_time = input("\tHow much time would you like to rest? ")
if rest_time >= 6:
self.STATUS['rested'] = True
def __str__(self):
str_info = "\tName: [%s]\tLEVEL: %d\n\tHP: %2d\t\tMP: %2d" % (self.name, self.lvl, self.hp, self.mp)
str_stats = "\t\tSTR: %2d\n\t\tCON: %2d\n\t\tDEX: %2d\n\t\tINT: %2d\n\t\tWIS: %2d\n\t\tCHA: %2d\n" % (
self._strength, self._constitution, self._dexterity, self._intelligence, self._wisdom,
self._charisma)
return "|%s|\n%s" % (str_info, str_stats)
Character
类:
# all character, being Player, NPC, or Enemy content should be implemented here
from utils import Dice
class Character:
"""
Main character class, all living entities derivate from it
"""
# a dictionary of possible status of player, the idea is that this status change gameplay/combat in the future.
# By default all characters are rested.
STATUS = {'rested': True, 'hunger': False, 'poisoned': False, 'bleeding': False, 'blind': False, 'frozen': False,
'paralyzed': False, 'dead': False}
# Right now there are only four equipment slot, which one should receive an armor object, not yet implemented
EQUIPMENT_SLOTS = {'head': None, 'chest': None, 'legs': None, 'boots': None}
def __init__(self, name, hp, mp, inventory, armor_class, lvl):
"""
Constructor for a character
:param name: name for the character
:type name: str
:param hp: hit points(health) for the character
:type hp: int
:param mp: magic points(mana) for the character
:type mp: int
:param inventory: inventory of character(gold, items, equips)
:type inventory: dict
:param armor_class: main defense
:type armor_class: int
:param lvl: level of character
:type lvl: int
:return: Character object
"""
self.name = name
self.hp = hp
self.mp = mp
self.inventory = inventory
self.armor_class = armor_class
self.lvl = lvl
self.atk_bonus = 1
self.atk_dmg = 4
self.movement_speed = 6
def take_dmg(self, dmg):
self.hp -= dmg
if self.hp <= 0:
print("\n[%s has died!]" % self.name)
self.STATUS['dead'] = True
else:
print("\n[%s has %d health left" % (self.name, self.hp))
def attack(self, enemy):
"""
All characters can attack, so this is the main attack(physical) method
:param enemy: Enemy that is in combat with character
:return:
"""
d20 = Dice(20)
dmg = self.atk_dmg
if d20.roll() + self.atk_bonus >= enemy.armor_class:
if d20 == 20:
print("CRITICAL HIT!")
dmg *= 2
else:
dice_dmg = Dice(self.atk_dmg)
dmg = dice_dmg.roll()
print("\n[%s hit %s for %d damage]" % (self.name, enemy.name, dmg))
enemy.take_dmg(dmg)
if enemy.STATUS['dead']:
return
else:
print("\n[%s missed]" % self.name)
def combat(self, enemy):
while True:
self.attack(enemy)
if enemy.STATUS['dead']:
return True
enemy.attack(self)
if self.STATUS['dead']:
break
return False
def equip_armor(self, armor_piece):
"""
Equip a piece of armor in the correspondent slot
:param armor_piece: armor piece to equip
:type armor_piece: object
:return:
"""
replace_equip = input(
"Would you like to replace %s with %s?(Y/N)" % (self.EQUIPMENT_SLOTS['head'], armor_piece.name))
if replace_equip.lower() == "y":
self.EQUIPMENT_SLOTS['head'] = armor_piece
return
else:
return
def list_inventory(self):
"""
list a character's inventory
:return:
"""
print("\t\t[%s] INVENTORY:\t\t\n" % self.name)
for item in self.inventory:
print("%s:\t%d" % (item, self.inventory[item]))
,例如,Skill
类,所有类/专业都以类似的方式实现:
# All basic skill implementation should be here
class BasicSkill:
SKILL_TYPE = {'passive': False, 'active': False, 'channeled': False}
def __init__(self, name, description, skill_type, skill_dmg=0, skill_range=0):
"""
Basic Skill class
:param name: skill name
:type name: string
:param description: description
:type description: string
:param skill_type: passive, active or channeled
:type skill_type: string
:param skill_dmg: default=0, meaning it's passive
:type skill_dmg: int
:param skill_range: default=0, meaning it's personal
:type skill_range: int
:return:
"""
self._name = name
self._description = description
self.SKILL_TYPE[skill_type] = True
self.skill_dmg = skill_dmg
self.skill_range = skill_range
class PassiveSkill(BasicSkill):
def __init__(self, name, description, skill_type='passive'):
super().__init__(name, description, skill_type)
class ActiveSkill(BasicSkill):
def __init__(self, name, description, skill_dmg, mp_use, cooldown=1, skill_type='active', skill_range=1):
super().__init__(name, description, skill_type, skill_dmg, skill_range)
self.mp_use = mp_use
self.cooldown = cooldown
class ChanneledSkill(BasicSkill):
def __init__(self, name, description, skill_dmg, channeling_time, cooldown=2, skill_type='chanelled',
skill_range=1):
super().__init__(name, description, skill_type, skill_dmg, skill_range)
self.channeling_time = channeling_time
self.cooldown = cooldown
欢迎任何想法,以及代码改进技巧。我试图找出一个很好的方法来制作这个技能实现系统,但我找不到一个。我努力的唯一选择是技能词典,但我不知道它会如何运作。无论如何,谢谢你的帮助。