Public Group

# Dealing with Multiple Characters with Different Attributes

This topic is 512 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I'm trying to make a game where the characters are randomly generated and retain individual attributes over time. Right now, I'm working on the combat system. I've made it so the roles of "Attacker" and "Defender" will switch between the player character and the NPC they are fighting. Problem is, I'm unsure of how to organize it in an elegant way. All I can think of is doing a bunch of if & else statements every time I need to check. Could you suggest ways of doing this in an elegant way? If there is anything in my code that could be significantly simplified don't be afraid to point that out either.

Here is an example of one of the methods I could use help with. In it, I am taking the int type variable, "overall action score", or OAS, from a tuple, which then helps to determine the force of any attacks that land. On if and else statements, I am checking who is attacking, and calling one of their respective physical attributes.

    def forceFinder(self):
"""
Determines force of strike from
OAS and alacrity.
"""
#subtract attacker OAS from defender OAS
force = self._oasTuple[0] - self._oasTuple[1]
#exponentially adds to force according to alacrity and
#margin between attacker, and defender OAS.
for i in range(0, force, 10):
force *= 1.10
if Combat._attacker == "pc":
force += Combat._pcAttr["alacrity"] * 3
else:
force += Combat._npcAttr["alacrity"] * 3
return int(force)

##### Share on other sites

Python is not my strong suit so I apologize if this is vague, but...

What you want to do is store a reference to the PC (or NPC) in a variable. Then instead of having an if check, you just ask the variable for its alacrity stat directly. When the turn switches, you can point that variable to the "other" character instead, and off you go.

This way the code uses the same exact checks for everyone, but it can be "configured" to point to one character or another on the fly.

Hope that made some semblance of sense :-)

##### Share on other sites

The typical approach is to have data that gets swapped out.

You might pass an index to a table for the source or target, you might pass an object for the source and the source for the target, or something else.

For example, adding that information to the object itself and accessing it generically:

force += Combat._attacker.Attr["alacrity"];

or perhaps:

force += Combat._attacker.CurrentAlacrity(Combat._defender);

or accessing it through another table:

force += CombatAttribs[Combat._attacker].["alacrity"];

I prefer the function version above, since it more easily allows you to add modifications based on the source and the target, such as a bonus versus dragons or penalty versus shopkeepers or whatever fits your game.

##### Share on other sites
1 hour ago, ApochPiQ said:

Python is not my strong suit so I apologize if this is vague, but...

What you want to do is store a reference to the PC (or NPC) in a variable. Then instead of having an if check, you just ask the variable for its alacrity stat directly. When the turn switches, you can point that variable to the "other" character instead, and off you go.

This way the code uses the same exact checks for everyone, but it can be "configured" to point to one character or another on the fly.

Hope that made some semblance of sense :-)

So basically, you have an array for each character and switch the identifiers of the arrays based on who fills each role? If that's what you're saying I get it. It seems fairly simple, and would work. I'd like to examine other possibilities still.

22 minutes ago, frob said:

The typical approach is to have data that gets swapped out.

You might pass an index to a table for the source or target, you might pass an object for the source and the source for the target, or something else.

For example, adding that information to the object itself and accessing it generically:

force += Combat._attacker.Attr["alacrity"];

or perhaps:

force += Combat._attacker.CurrentAlacrity(Combat._defender);

or accessing it through another table:

force += CombatAttribs[Combat._attacker].["alacrity"];

I prefer the function version above, since it more easily allows you to add modifications based on the source and the target, such as a bonus versus dragons or penalty versus shopkeepers or whatever fits your game.

Thank you for the quick, and in-depth response. I'm sorry, but I don't understand Python 2. I'm guessing that's what these examples are since we never seem to end lines in Python 3.6 with semi-colons. I'm not sure how to make these examples work since I don't understand their formatting. I've never seen class-level variables called in that way, with two periods, to reach specific data. Could you please explain it or link to a website/video that can help me understand how to do the same thing in Python 3? It seems like some of your ways might be better than how I've interpreted ApochiPiQ's suggestion.

##### Share on other sites
8 hours ago, RidiculousName said:

So basically, you have an array for each character and switch the identifiers of the arrays based on who fills each role? If that's what you're saying I get it. It seems fairly simple, and would work. I'd like to examine other possibilities still.

You can wrap the access code in a function

def get_property(combat, property):
if combat._attacker == "pc":
return combat._pcAttr[property]
else:
return combat._npcAttr[property]

which then gives

force += get_property(Combat, "alacrity") * 3

Frob folds the selection into the Combat object (his Pythoneese has some C++ influences, just ignore the semi-colons and the dots that look weird )

Instead of making "Combat.attacker" a string, make it the object you point to:

# Inside Combat

def assignAttacker(self, attacker_type):
if attacker_type == "pc":
self._attackerAttr = self._pcAttr
self._defenderAttr = self._npcAttr
else:
self._attackerAttr = self._npcAttr
self._defenderAttr = self._pcAttr

And now you can access Combat._attackerAttr[...]

As a note, the "_" prefix denotes a private variable (by convention) in Python, which basically means you should not access those variables from outside the methods of the class (like you do with Combat._pcAttr for example). Other Python programmers will get confused about it.

Unlike eg Java and C++, in Python an object variable is always prefixed by the containing object, that is, you cannot write "_pcAttr" to access the variable in Combat, you must always write something like "Combat._pcAttr" or "self._pcAttr". As such, there is no real need to differentiate between normal variables and object member variables, the "Combat." or "self." prefixes in front of the latter already do this.

Edited by Alberth
fixed code example

##### Share on other sites

Again, Alberth!? Every time I post a question you're there with amazingly well-reasoned and detailed answers. Thank you!

Quote

As a note, the "_" prefix denotes a private variable (by convention) in Python, which basically means you should not access those variables from outside the methods of the class (like you do with Combat._pcAttr for example). Other Python programmers will get confused about it.

The method I gave as an example is held within the Combat class. Have I misunderstood you?

##### Share on other sites
8 hours ago, RidiculousName said:

Again, Alberth!? Every time I post a question you're there with amazingly well-reasoned and detailed answers. Thank you!

Hmm, yeah, sorry about that. Likely that will continue to happen until you start asking questions about complicated component systems, data-oriented-design, and pretty much anything about GPUs or detailed performance stuff.

9 hours ago, RidiculousName said:

The method I gave as an example is held within the Combat class. Have I misunderstood you?

Good point, missed that. It would be fine then I guess, since it's only a convention anyway.

1. 1
2. 2
Rutin
21
3. 3
A4L
15
4. 4
5. 5
khawk
14

• 13
• 26
• 10
• 11
• 44
• ### Forum Statistics

• Total Topics
633741
• Total Posts
3013624
×