Sinnvolle Aufteilung in Klassen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
heal.p
User
Beiträge: 30
Registriert: Freitag 3. Dezember 2010, 12:28

Hab mich nun ins Thema eingelesen und würde das gerne auch gleich ausprobieren. Wäre es nun sinnvoll wenn ich für jeweil eine eigene Klasse für
- Meine Charakter
- Den Gegner
mache und dann die Aktionen wie Angreifen global definiere? Oder Sollte ich diese Sachen jeweil in die Charakter / Gegner Klasse einfügen :?: :?
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Dann solltest du nochmal genau nachlesen :D
Wenn du eine Klasse Character schreibst, dann kannst du davon mehrere Instanzen anlegen. Ob du von der Klassen dann nochmal ableitest, also spezialisierst, liegt daran wie unterschiedlich die Eigenschaften des Gegners und die deines Heros sind.

"global" definieren, sollte man nach Möglichkeit gar nichts.
Die Schlacht-/Kampfberechnung könnte man in einer Funktion machen, wie komplex diese ist musst du abwägen.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
heal.p
User
Beiträge: 30
Registriert: Freitag 3. Dezember 2010, 12:28

Xynon1 hat geschrieben:Dann solltest du nochmal genau nachlesen :D
Wenn du eine Klasse Character schreibst, dann kannst du davon mehrere Instanzen anlegen, ob du davon dann Ableitest, also spezialisierst, liegt daran wie unterschiedlich die Eigenschaften des Gegners und die deines Heros sind.
:shock: fühl mich bisschen erschlagen. :( Heisst das ich habe dann nur eine Klasse? Jedoch versteh ich au ned ganz was es mit diesen Instanzen auf sich hat, hab nun http://tutorial.pocoo.org/classes.html#instanzobjekte schon 2x durchgelesen, und bin immer noch ned weiter. Auch das Beispiel hilft mir nicht gerade zu verstehen, was Sie mir mitteilchen wollen.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ich denke auch man sollte auf jeden Fall einmal genau durchdenken, inwiefern sich denn SCs von NSCs unterscheiden, evtl. benötigt man gar nur eine Klasse, mit der sich alle denkbaren Charaktere abbilden lassen.

Aktionen wie Kämpfe usw. sollten imho nicht direkt in die Charakterklassen integriert werden. Schließlich finden diese ja in einer "Umwelt" statt, die ggf. auch Einfluss auf das Geschehen hat, aber vor allem steuert und die Kontrolle über die Aktionen besitzt. All das müßte man ja sonst irgend wie einem Charakter zuweisen... imho keine gute Idee.

Bei meinem DSA-Kampfsimulator habe ich das ganze mit mehreren Funktionen gelöst. Ein Charakter hatte da eher eine passive Rolle und lieferte nur simple Werte und ggf. mal einen kumulierten Wert. Willst Du da so was wie eine KI draufstülpen, so dass die Chars Entscheidungen treffen können, so wären das wohl schon Kandidaten für Methoden, die mit von außen übergebenen Daten Charakter bezogene Entscheidungen treffen können.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Hier mal ein kleines Beispiel damit du ein wenig Überblick bekommst.

Code: Alles auswählen

# Klassenobjekt
class Character(object):

    # Konstrucktor
    def __init__(self, name="Nameless"):
        # Attribute
        self.name = name
        self.hp = 10
        self.max_hp = 100

    # Methode
    def sleep(self):
        self.hp = self.max_hp


if __name__ == "__main__":
    # Instanzen player und mob1
    player = Character("Ich")
    mob1 = Character("Ratte")

    print(player.hp)
    
    # Methodenaufruf
    player.sleep()

    print(player.hp)
    print(mob1.hp)
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
heal.p
User
Beiträge: 30
Registriert: Freitag 3. Dezember 2010, 12:28

Hyperion hat geschrieben:Ich denke auch man sollte auf jeden Fall einmal genau durchdenken, inwiefern sich denn SCs von NSCs unterscheiden, evtl. benötigt man gar nur eine Klasse, mit der sich alle denkbaren Charaktere abbilden lassen.

Aktionen wie Kämpfe usw. sollten imho nicht direkt in die Charakterklassen integriert werden. Schließlich finden diese ja in einer "Umwelt" statt, die ggf. auch Einfluss auf das Geschehen hat, aber vor allem steuert und die Kontrolle über die Aktionen besitzt. All das müßte man ja sonst irgend wie einem Charakter zuweisen... imho keine gute Idee.

Bei meinem DSA-Kampfsimulator habe ich das ganze mit mehreren Funktionen gelöst. Ein Charakter hatte da eher eine passive Rolle und lieferte nur simple Werte und ggf. mal einen kumulierten Wert. Willst Du da so was wie eine KI draufstülpen, so dass die Chars Entscheidungen treffen können, so wären das wohl schon Kandidaten für Methoden, die mit von außen übergebenen Daten Charakter bezogene Entscheidungen treffen können.
Denke soweit bin ich noch ned das ich da ne KI einstülpen werde. Auch das die Umwelt bereits einfluss in den Kampf haben wird, denke ich nicht das ich das schon tun werde. Ich habe mir mehr gedacht, das man 3 Aktionen zur Auswahl hat:
- physischer Angriff (wird von Stärke beeinflusst)
- Abwehren (wird von Beweglichkeit beeinflusst)
- magischer Angriff (wird von Intelligenz beeinflusst)
Den Gegner hätte ich einfach über Zufallszahl gesteurt.
Xynon1 hat geschrieben:Hier mal ein kleines Beispiel damit du ein wenig Überblick bekommst.

Code: Alles auswählen

# Klassenobjekt
class Character(object):

    # Konstrucktor
    def __init__(self, name="Nameless"):
        # Attribute
        self.name = name
        self.hp = 10
        self.max_hp = 100

    # Methode
    def sleep(self):
        self.hp = self.max_hp


if __name__ == "__main__":
    # Instanzen player und mob1
    player = Character("Ich")
    mob1 = Character("Ratte")

    print(player.hp)
    
    # Methodenaufruf
    player.sleep()

    print(player.hp)
    print(mob1.hp)
Danke dir Xynon1. Was macht genau das self? Unten rufst du ja dann die hp des Spieler mit player.hp auf und oben definierst du player soll der Character sein der Ich heisst, richtig?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

heal.p hat geschrieben: Danke dir Xynon1. Was macht genau das self?
Dazu solltest Du Dir noch einmal Kapitel 9 im Tutorial gründlich angucken :-) Kurz gesagt ist der Name reine Konvention und dahinter verbirgt sich immer das aufrufende Objekt, welches implizit an die Methode weitergegeben wird. Hier mal ein kurzes Beispiel zum Nachdenken:

Code: Alles auswählen

In [1]: class Foo(object):
   ...:     
   ...:     def bar(self):
   ...:         print self
   ...:         
   ...:         

In [2]: f = Foo()

In [3]: f.bar()
<__main__.Foo object at 0x9f1a60c>

In [4]: f
Out[4]: <__main__.Foo object at 0x9f1a60c>
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
heal.p
User
Beiträge: 30
Registriert: Freitag 3. Dezember 2010, 12:28

Hyperion hat geschrieben: Dazu solltest Du Dir noch einmal Kapitel 9 im Tutorial gründlich angucken :-) Kurz gesagt ist der Name reine Konvention und dahinter verbirgt sich immer das aufrufende Objekt, welches implizit an die Methode weitergegeben wird. Hier mal ein kurzes Beispiel zum Nachdenken:

Code: Alles auswählen

In [1]: class Foo(object):
   ...:     
   ...:     def bar(self):
   ...:         print self
   ...:         
   ...:         

In [2]: f = Foo()

In [3]: f.bar()
<__main__.Foo object at 0x9f1a60c>

In [4]: f
Out[4]: <__main__.Foo object at 0x9f1a60c>
Les das Kapitel ja immer und immer wieder :) aber weiss nicht, begreif es immer noch nicht so ganz. Und dein Beispiel verwirrt mich mehr als das es mir etwas hilft.
das In [2] heisst das, das dein zweiter Input (in die Shell) f = Foo() ist? Oder wie muss ich das verstehen?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

heal.p hat geschrieben: das In [2] heisst das, das dein zweiter Input (in die Shell) f = Foo() ist? Oder wie muss ich das verstehen?
Jupp. Öffne doch mal ne Shell und probiere das aus ;-) Ich verwende ipython als Shell; daher die Nummerierung und so.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
heal.p
User
Beiträge: 30
Registriert: Freitag 3. Dezember 2010, 12:28

Ich benutz die normale Python Shell. :| Mhh glaube solange kapier ichs. Aber wirklich nur langsam.

Danke dir/euch für die Hilfe.

Edit: Kumpel hat mir das nun nochmal erklärt. Ich glaube jetzt den grössten Teil verstanden zu haben. Werd mich nun nächste Woche dran versuchen, ob was gescheites raus kommt wen ich es umsetze. :) Denke ich werde Mittwochs meinen nächsten Codeansatz veröffentlichen.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Vielleicht kann dies http://www.python-forum.de/viewtopic.ph ... 30#p112630 noch eine Anregung sein.

Stefan
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

sma hat geschrieben:Vielleicht kann dies http://www.python-forum.de/viewtopic.ph ... 30#p112630 noch eine Anregung sein.

Stefan
Interessanter Thread, danke fürs Gedächtnis auffrischen :-)

Speziell über die attack-Methode ließe sich imho streiten. Bei Deinem simplen Ansatz wie bei Dir ist es bestimmt eine gute Wahl, das in die Helden-Klasse zu packen und nicht als externe Funktion zu implementieren. Kommen jedoch Dinge wie mehrere Gegner, verschiedene Anzahlen an Aktionen, usw. hinzu, so würde ich da ggf. eben doch eine externe Berechnung einer Kampfaktion bevorzugen.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Bei einem Versuch, ein komplexeres Kampfsystem zu implementieren kam ich ganz schnell bei dem Wunsch an, Multimethoden zu haben, denn wenn an einem Angriff der Angreifer, der Gegner, eine Waffe, vielleicht noch eine Rüstung, Talente und aktive Zauber beteiligt sind, dann ist eigentlich keines dieser Objekte jetzt ein geeigneter Platz, um da den Kampf-Algorithmus zu implementieren.

Andererseits muss man's auch nicht komplizierter machen als nötig.

Ich wollte mal ein Programm schreiben, dass mir folgenden Dialog erlaubt:

Code: Alles auswählen

Scene: At the border of the Qua'atl jungle [4]

Description:
  The dense forest opens to a small clearing.
  In the north, a mountain range is visible, but the path that you've
  been followed for days outs over a narrow suspension bridge,
  their moorings looking all but trustworthy.

Exits:
  1. Back to the jungle [3]
  2. Over the suspension bridge [5]

Random encounters: Jungle. Triggered.

Your startle a Jaguar on search for prey.
He seems to be hungry and attacks.

Opponents:
  1. Jaguar (Health 4/4)

Party (in order of initiative):
  1. Thomu (Health 5/5, Bow, behind)
  2. Greog (Health 3/3, Sword, front)
  3. Adali (Health 2/4, Quarterstaff, behind)

[ask player for actions, then sumarize]

Actions:
  - Adali casts "Protection" on Greog
    and casts "Strength" on Greog
  - Thomu attacks the jaguar with his bow
  - Greog does a wild attack on the jaguar with his sword

Combat:
  Thomu shoots and misses the jaguar.
  The jaguar attacks Greog and inflicts 1 wound
  and it attacks Thomu and inflicts 2 wounds.
  Greog swings and hits the jaguar, inflicting 2 wounds
  and he swings again and misses the jaguar.
  Adali casts "Protection" on Greog
  and she casts "Strength" on Greog.

Summary:
  
Opponents:
  1. Jaguar (Health 2/4)

Party (in order of initiative):
  1. Thomu (Health 3/5, Bow, behind)
  2. Greog (Health 2/3, Sword, front)
  3. Adali (Health 2/4, Quarterstaff, behind)

Actions:
  - Thomu draws his dagger
    and he attacks the jaguar
  - Greog attacks the jaguar
  - Adali casts "Healing" on Thomu

Combat:
  Thomu stabs and misses the jaguar.
  The jaguar attacks Andali and inflicts 3 wounds.
  Adali is deadly wounded and does down.
  Greog interrupts his action (automatic action)
  and uses a healing potion on Andali (+1 health)

and so on
Als ich das auf deutsch versucht habe, bin ich an den verschiedenen Fällen und Pronomen gestorben. Auf englisch ist es einfacher. Dennoch, abhängig von den hier nur implizit erwähnten Regeln ist es relativ kompliziert, eine Kampfrunde durchzuführen. Ich hatte dafür eine Klasse `Battle` vorgesehen, die sich um alles kümmert:

Code: Alles auswählen

battle = Battle(location=jungle_border, party=[thomu, greog, adali], opponents=[jaguar])
battle.perform()

class Battle:
    def perform(self):
        self.determine_initiatives()
        self.sort_combatants_by_initiative()
        for combatant in self.combatants:
            self.perform_actions(combatant)
        self.print_combat()
        self.print_summary()

    def perform_actions(self, combatant):
        for action in combatant.actions:
            action.perform(self)

class AttackAction:
    def __init__(self, actor, target, weapon):
        self.actor, self.target, self.weapon = actor, target, weapon

    def perform(self, battle):
        battle.attack(self.actor, self.target, self.weapon)

class CastAction:
    def __init__(self, actor, target, spell):
        self.actor, self.target, self.spell = actor, target, spell

    def perform(self, battle):
        battle.cast(self.actor, self.target, self.spell)

class Battle...
    def attack(self, actor, target, weapon):
        attack_bonus = actor.attack_bonus_against(target) + weapon.attack_bonus_against(target)
        defense_bonus = target.defense_bonus_against(weapon)
        damage_bonus = weapon.damage_bonus_against(target)
        if roll(actor.attack_skill + attack_bonus) > roll(target.defense_skill + defense_bonus):
            wounds = roll(weapon.damage + damage_bonus)
            self.report.report_attack_hit(actor, target, weapon, wounds)
            self.apply_wounds(target, wounds)
       else:
           self.report.report_attack_miss(actor, target, weapon)

    def apply_wounds(target, wounds):
        target.health -= wounds
        if target.health < 0:
            self.report.report_deadly_wound(target)
            self.change_action_to_help(target)

and so on
Stefan
heal.p
User
Beiträge: 30
Registriert: Freitag 3. Dezember 2010, 12:28

Danke dir Stefan fürs posten.
Mein Script soll jedoch lange nicht so komplex werden. Vll realisiere ich soetwas einmal später.

Bei meinem Script soll es im Moment sowieso nur beschränkte Möglichkeiten geben.
- Skillpunkte verteilen
- Gegner Angreifen und kämpfen
- Zusätzliche Skillpunkte erlangen und verteilen.
Antworten