0

I'm fairly new to coding in python (3) as somewhat of a hobby, but having fun playing around with some game mechanics without worrying about GUI. I'm currently working on a civilization-type text based game whose foundations lie in an old excel document. It's fairly centred on math and logic, which I think made for a pretty easy but in-depth set of mechanics.

Anyway, the game allows for researching tech, producing buildings, growing citizens, gathering culture etc. One thing I'm struggling with is the military system.

I have a number of different units for the player to produce. Let's say each unit has a name, strength and resilience (eg. 'Archer', '10', '80'). Wars are based on total player strength (I can calculate this). After each war, the unit's strength decreases by it's resilience ie. this Archer would decrease to 80% of its original strength after a war to strength 8.

However, I'm having trouble working out how the user can create units in a fashion that allows this mechanic. I originally used a Unit() class (with different units eg. archer, spearman as objects) with a 'quantity' argument alongside name/strength/resilience for amount of units built, but every time I ran the function to calculate the effect of resilience I realised I was affecting not only currently produced units but all future versions of the unit too. I was running something like the following:

class Unit():
  def __init__(self, name, quantity, strength, resilience)
  self.name = name
  self.quantity = quantity
  self.strength = strength
  self.resilience = resilience

archer = Unit('archer', 0, 10, 80)

etc...

Each time the user built a unit, the 'quantity' would increase. However I've come to understand that it's probably this method of coding is probably what is limiting me. Reading other threads tells me I should be aiming to not store object data in such a way, right?

I've been playing around and researching and I can't seem to get my head around the solution (which I'm sure is there). I'm having trouble finding the right way of storing each unit's basic data (name, strength, resilience) while allowing the user to produce multiple, unique copies of each unit. Each unit should be a class? A sub class? It should be stored in a dictionary? A list?

I apologise for the lack of code in this post, but I don't exactly have erroneous code - I'm just lacking the logic and python knowledge to find the right systems to make this work properly. Been playing with dictionaries, lists, loops, inherited classes, but I just can't get it right.

How would one create multiple archers who each take damage, without affecting future archers that might be produced?

Thanks if anyone can suggest something. Other than this I'm having a lot of fun coding in python!

  • You should show more code. Defining strength etc like you have done there means that they would apply only to that specific unit, and *not* to all units of that type; the usual mistake that people make is defining these values at class level, but you have not done that. – Daniel Roseman Aug 20 '16 at 16:16
  • Thanks for the feedback. I wasn't sure which code would really be relevant because it's not so much I have erroneous code, it's just I'm playing around with python's logic and can't quite figure out the right structure. Rawing's answer below is close, I just have further issues creating unique ID's for objects when the user chooses to produce them. – Jammydude44 Aug 21 '16 at 06:54

2 Answers2

1

The point of a class is that it lets you create many instances of that class. You don't need to (and can't/shouldn't) subclass Unit for each unit. You simply need to instantiate the Unit class:

 archer1= Unit('archer', 0, 10, 80)
 archer2= Unit('archer', 0, 10, 80)

Now you have two separate archer units with separate stats. If one of them fights in a war and its attributes change, the other won't be affected:

 archer1.strength= 0
 print(archer2.strength) # prints 10

Of course, this means you don't need the quantity attribute and you need to store all units in some kind of data structure like a list:

 all_my_archers= [archer1, archer2]
 #create a 3rd archer
 all_my_archers.append(Unit('archer', 0, 10, 80))

This is less important, but you should also consider subclassing Unit to create an Archer class:

class Unit:
    def fight_war(self):
         self.strength= self.strength * self.resilience / 100.0

class Archer(Unit):
    name= 'archer'
    strength= 10
    resilience= 80

Since all archer units start with the same stats (I assume), this will eliminate the need to specify the strength and resilience every time you create a new archer unit (you can just do archer4= Archer() now), and you can still change a unit's stats without affecting other units.

Aran-Fey
  • 39,665
  • 11
  • 104
  • 149
  • Thanks. This is close to what I was looking for, at least it show I was on the right track. The part I'm struggling with is generating the unique objects on the fly when a user chooses them from the production menu. Could you recommend how a user input of 'archer' or 'spearman' could get me to a point where I'm creating the object 'archer3' or 'spearman4'? I can't seem to figure out how to create unique ID's for object at runtime. – Jammydude44 Aug 21 '16 at 06:50
  • @Jammydude44 I suspect you're misunderstanding. You can create a new, unique, independent unit/archer simply by calling the constructor `Archer()` or `Unit()`. There is no need to dynamically create variables, i.e. `archer386 = Archer()`. You simply need to store the new `Unit` instance in the list with all the other units: `all_my_archers.append(Archer())`. If you really need a unique ID for each unit, you can use the built-in `id` function: `id(archer1)`. – Aran-Fey Aug 21 '16 at 07:00
  • Yes, thank you, I was misunderstanding. I thought as print(all_my_archers.name) was returning 'archer, archer, archer' that they were the same instance and I was making the same mistake I made in my question. But having tested it further I can see that they are unique instances. I'm now understanding the magic of lists in regards to objects. Time to tidy up the rest of my code! Thanks, answered perfectly. – Jammydude44 Aug 21 '16 at 07:13
0

For me, especially when you are creating a game, sub-classing is a really good way of writing good code. Mostly because you can implement independent features on your subclasses. For example every Unit may have the same movement mechanism, but an Archer Unit might defer in the attack process. To talk code:

class Unit(object):

    def __init__(self, movement_speed=10, health=100):
        self.movement_speed = movement_speed
        self.health = health
        self.position = 0

    def move(self):
        self.position += movement_speed

    def get_hit(self, damage=0):
        self.health -= damage

    #etc

class Archer(Unit):

    def __init__(self, arrows=10):
        super(self.__class__, self).init()
        self.arrows = 10

    # Archer has all the Unit methods

    def attack(self, other_unit_instance):
        # Here you can check if he is in range, etc
        other_unit_instance.get_hit(damage=1)
        self.arrows -= 1
Kostas Pelelis
  • 1,322
  • 9
  • 11
  • Thanks Kostas Pelelis, while this isn't exactly what I was looking for (although we'll blame that on the vagueness of my post) this is something I'll definitely keep handy for when I add more depth to the system. – Jammydude44 Aug 21 '16 at 06:53