简体   繁体   中英

Dictionary to Object Orientation Transition

I am currently, as part of a project, creating my own mechanics suitable for a TTRPG (table top role play game) in Python 3.8 (specifically on IDLE). Currently, important data is stored in Nested Dictionary Form . This stores several groups of variables that are easy to change and easy to call. I find this particularly easier to manage and manipulate.... but it is likely less effective, especially regarding more changing variables used. I know that the next step is classes and objects.

Now I have a relatively amateur understanding of Object Oriented Programming - I know how to make classes, subclasses, override &c. However, I'm finding it hard to make a proper transition.

My Queries

protag = {"name":"Protagonist",
          "Exp":0,
          "Nlvl":30,
          "Lvl":1,
          "Rank":1,
          "statistics":{"Str":14,
                        "Dex":18,
                        "HP":35,
                        "Ins":12,
                        "MP":35,
                        "Max_HP":35,
                        "Def":10},
          "attack":{"A":2,
                    "B":8,
                    "C":6,
                    "Desc":"attacks!",
                    "att_type":"strength",
                    "Mp_cost":0
                   }}
  1. Best to introduce my main coding. This is my Player dictionary. What would be a wise way to convert this into OOP?
HS = {"name": "Heath Scourer",
      "statistics":{"Str": 10,
                    "Dex": 16,
                    "HP": 52,
                    "Ins": 9,
                    "MP": 35,
                    "Max_HP": 52,
                    "Def": 12},
      "attack":{"A": 2,
                "B": 4,
                "C": 1,
                "Desc": "claws!",
                "att_type": "strength",
                "Mp_cost": 0}}
      
def attack(attacker,defender):
    remaining = 0
    h = 0
    # Dice Mechanism - Based of AdB + C#    
    while remaining < attacker["attack"]["A"]:
        add = random.randint(1,attacker['attack']['B'])
        h += add
        remaining += 1
        print(h)
        # simple test to see if randomiser works
    # variation based on attack type.#        
    if attacker["attack"]["att_type"] == "strength":
        A = h + (h/20* attacker["statistics"]["Str"])
    elif attacker["attack"]["att_type"] == "dexterity":
        A = h + (h/20* attacker["statistics"]["Dex"])
    elif attacker["attack"]["att_type"] == "insight":
        A = h + (h/10* attacker["statistics"]["Ins"])
    else:
        # Error check- makes sure i haven't made a value mistake#    
        print("Error, Invalid attack!")
    # alternate defense variable for magic-based attacks.#    
    if attacker['attack']["att_type"] == "insight":
        d = int(A - ((A/25)* defender["statistics"]["Ins"]))
    else:
        d = int(A-((A/50)* defender["statistics"]["Def"]))
    # Damage display.#    
    print(attacker["name"],attacker["attack"]["Desc"])
    time.sleep(1)
    print(d,"damage dealt!")
    defender["statistics"]["HP"] -= d
  1. More importantly, how exactly does one call upon, and edit, instantiated objects? In this situation, I want to test out an attack function with the player as a global variable on my dummy enemy (who is currently also a nested dictionary), dealing damage which will then be stored in the dummy's HP variable. When I've converted both into objects, how would I alter the coding to call upon, and make permanent change, to the variables of that object?

  2. Is there any way of changing which attack you use with object orientation? Say, for example, I had 3 choices: Slash, Fire I, and Ore I. How would I alter the function above to allow me to change which attack I use? And where would I store these in an ideal system?

Thanks for any support; this will help me proceed with my project.

There are various possible answers to this question. First of all, you can create an object from a dictionary, which would give you what you want.

Say you have:

d = { "name": "Heath Healer" }

You could create an object from that with:

class Character:
    pass

protag = Character()
protag.__dict__ = d
print(protag.name)          # "Heath Healer"

But I don't think that is what you want. From what you say, you could create a class that represents you character. The main point here is the __init__() special method, that initializes the object when it is created.

class Character:
    def __init__(self, name, stats):
        self._name = name
        self._stats = stats

    def get_str(self):
         return self._stats["str"]
    # more things...

You could then have you function attack() as part of the class Character :

class Character:
    # more things...
    def attack(self, other):
        remaining = 0
        h = 0

        # Dice Mechanism - Based of AdB + C#    
        while remaining < self.get_attack_a():
            add = random.randint(1,self.get_attack_b())
            h += add
            remaining += 1
        print(h)
        # more things...

Now, creating all that methods to the class could be daunting, so you can have a single special method that parses your dictionary and really returns all the stuff you need.

class Character:
    def __init__(self, chrs):
        self._chrs = chrs

    def __getattr__(self, s):
        toret = self._chrs.get(s)
        
        if not toret:
            toret = self._chrs["statistics"].get(s)
            
            if not toret:
                parts = s.split("_")
                
                if parts and len(parts) == 2 and parts[0] == "attack":
                    toret = self._chrs["attack"].get(parts[1])
            
        return toret


protag = {"name":"Protagonist",
          "Exp":0,
          "Nlvl":30,
          "Lvl":1,
          "Rank":1,
          "statistics":{"Str":14,
                        "Dex":18,
                        "HP":35,
                        "Ins":12,
                        "MP":35,
                        "Max_HP":35,
                        "Def":10},
          "attack":{"A":2,
                    "B":8,
                    "C":6,
                    "Desc":"attacks!",
                    "att_type":"strength",
                    "Mp_cost":0
                   }}
                   
                   
char = Character(protag)

print(char.name)
print(char.Str)
print(char.attack_A)

char.Str = 24
print(char.Str)

Method __getattr__ is called when an attribute is accessed but this attribute does not exist, so it is a good match in this case.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM