Benötige Hilfe bei der Planung eines (Karten-)Spiels

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.
Antworten
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

Hiho.
Ich hatte letztens (okay ist schon ne Weile her) im Ideen-Forum einen Thread eröffnet, in dem ich die Idee zu einem Kartenspiel erläutert habe.
Aus verschiedenen Gründen kam ich in der letzten Zeit aber nicht dazu und ich hab mir jetzt wieder ein paar Gedanken gemacht ...
Jeder kennt ja sicher sowas wie Magic, Yu-Gi-Oh oder sonstwas. Ein Kartenspiel, in dem es Monsterkarten gibt, die verschiedene Eigenschaften haben (unter anderem Angriffs und Verteidigungswert und Lebenspunkte), Zauberkarten usw.
Es wäre auch kein Problem das Spiel einfach mal "hinzukritzeln" so, dass es zwar läuft, aber ziemlich unflexibel ist.
Ich würde es aber gerne flexibel haben und später bei Änderungen auch wirklich nur den Teil ändern müssen, den es betrifft und nicht das ganze Programm. Also alles schön in einzelne möglichst unabhängige Module/Pakete verlagern.
Ich habe aber bisher noch nie ein größeres Projekt in Angriff genommen so dass es hier schon an der Planung scheitert, hab ich das Gefühl.
Zum Beispiel sollte eine Monsterkarte später beliebig mit einer Art Editor erstellt werden können, Werte wie Hitpoints usw sind ja auch kein Problem. Aber wenn ich der Einheit einen Effekt geben will, der zum Beispiel bewirkt, dass alle Einheiten auf dem Feld vergiftet werden, muss ich diesen Effekt auch noch implementieren. Aber all das will ich auch, ohne direkt in das Programm eingreifen zu müssen. Eher sowas wie:

Code: Alles auswählen

effect= Effect(blabla) # effect ist jetzt ein Effekt und in dieser Instanz wurden alle nötigen Informationen übergeben, 
#damit bei einer Attacke eines Monsters mit diesem Effekt alle Einheiten vergiftet werden
effects.add(effect)
monster = monster(hitpoints, ...,  effects(effects[bla], effects[blubb]) ...)
monsters.add(monster) 
Und schon ist eine neue Karte mit neuen Fähigkeiten, die es vorher nicht gab da.
Aber wie gesagt ich hab bisher noch kein großes Projekt in Angriff genommen und ich glaube, wenn ich hiermit anfange, übertreibe ich es entweder und schreibe den Code unnötig viel zu komplex oder ich schreib einfach nur Bullshit und am Ende kann man den Code gar nicht richtig benutzen weil ich a) nicht mehr durchblicke oder b) mir irgendwo Fehler unterlaufen sind, die das ganze Konstrukt sinnlos machen.
Vielleicht könnten mir ja ein paar von euch irgendwelche hilfreichen Tipps geben.
Ich würde die Kartenklassen (für jeden Kartentyp eine Klasse) als unabhängiges Modul auslagern, die Effekte, die Grafikengine (vorerst nur Konsole) und das Kampfsystem bzw die Game-Engine, die alles zusammensetzt.
Aber jetzt weiß ich schonmal nicht, wie ich diese ganzen Module aufbauen soll, damit das ganze danach auch wirklich mehr oder weniger reibungslos funktioniert.
Es entsteht ja erstmal ein ziemlicher Overhead aber dann wenn ich das zusammensetzen will, sollte das alles ganz einfach klappen und genauso, wenn ich was daran ändern will, da ja alles im Prinzip unabhängig voneinander ist.
Naja danke schommal für's durchlesen :D
Zuletzt geändert von Nocta am Sonntag 24. August 2008, 14:44, insgesamt 2-mal geändert.
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Das Problem kenne ich zu genüge :?

Einige Tipps, die mir oft helfen:

1. Erstmal auf nem Blatt Papier alles Mögliche niederschreiben, was man irgendwie als Objekt ansehen könnte. Also zb einen Effekt, eine Karte, den Stapel, aber auch ein bestimmter Befehl (ist nen wenig schwierig anhand eines Kartenspiels zu erklären, aber irgendwo hier wurde das schonmal ähnlich anhand eines Hauses erklärt: Das Haus ist ein Objekt, der Bauauftrag für ein Haus könnte man aber auch als eines ansehen)

Danach Versuch mal, die Objekte in diverse Programmkonstrukte reinzudrücken:

1. Macht es Sinn, es mit Objekten samt vielen Methoden zu implementieren?
2. Ist es sinnvoller, ereignisgesteuert daran zu gehen?
Zb könntest du einen Zentralen "EffektHandler" bauen, der eine While True Loop besitzt, und alle paar millisekunden überprüft, ob in einem Queue (import Queue) Objekt ein neuer Effekt (ein neues Ereignis) vorliegt.
Wenn der Spieler nun eins auslößt, wird so ein EffektObjekt generiert und dann in das Queue Objekt gelegt. Der EffektHandler registriert das, und liest von dem EffektObjekt einige Grundsätzliche Eigenschaften aus, wie zb
Macht der Effekt Schaden? Ist es ein Spezial Effekt? und so weiter.
Je nach Effekttyp benutzt der EffektHandler dann seine eigenen Methoden, um etwas bestimmtes zu realisieren, er besitzt alle Möglichkeiten, etwas zu tun, und das EffektObjekt sagt nur, wie genau er etwas tun soll.

Und so weiter, denke, du weißt, wie "diverse Programmkonstrukte" jetzt gemeint sind ;)

Dann solltest du vielleicht First Test Programming anwenden, spätestens da bist du gezwungen, dir die richtigen Fragen rechtzeitig zu stellen. Ist aber auch etwas streßig/nervig.

Viele empfehlen, schnellstens einen Prototyp zu schreiben: Finde ich grenzwertig, da ein Programm immer extremen Veränderungen unterliegt und man am Anfang selbst mit der Einstellung dann doch irgendwo hängen bleibt, und das Endprodukt vermutlich ziemlich starr ist.

mfg
Nocta
User
Beiträge: 290
Registriert: Freitag 22. Juni 2007, 14:13

str1442 hat geschrieben:Das Problem kenne ich zu genüge :?

Einige Tipps, die mir oft helfen:

1. Erstmal auf nem Blatt Papier alles Mögliche niederschreiben, was man irgendwie als Objekt ansehen könnte. Also zb einen Effekt, eine Karte, den Stapel, aber auch ein bestimmter Befehl (ist nen wenig schwierig anhand eines Kartenspiels zu erklären, aber irgendwo hier wurde das schonmal ähnlich anhand eines Hauses erklärt: Das Haus ist ein Objekt, der Bauauftrag für ein Haus könnte man aber auch als eines ansehen)
Karten, Kartenstapel, Effekte, Spieler, Spielbrett, Spielbrettslots (in die man die Karten reinlegen kann, falls ich das irgendwie einbauen will), Eventuell kann man sogar den Angriffs/Verteidigungstyp (nach dem Schere-Stein-Papier-Prinzip) als Objekte realisieren, usw usw. Da gibt's jedenfalls viel was man als Objekt ansehen könnte ;)
str1442 hat geschrieben: Danach Versuch mal, die Objekte in diverse Programmkonstrukte reinzudrücken:

1. Macht es Sinn, es mit Objekten samt vielen Methoden zu implementieren?
2. Ist es sinnvoller, ereignisgesteuert daran zu gehen?
Zb könntest du einen Zentralen "EffektHandler" bauen, der eine While True Loop besitzt, und alle paar millisekunden überprüft, ob in einem Queue (import Queue) Objekt ein neuer Effekt (ein neues Ereignis) vorliegt.
Wenn der Spieler nun eins auslößt, wird so ein EffektObjekt generiert und dann in das Queue Objekt gelegt. Der EffektHandler registriert das, und liest von dem EffektObjekt einige Grundsätzliche Eigenschaften aus, wie zb
Macht der Effekt Schaden? Ist es ein Spezial Effekt? und so weiter.
Je nach Effekttyp benutzt der EffektHandler dann seine eigenen Methoden, um etwas bestimmtes zu realisieren, er besitzt alle Möglichkeiten, etwas zu tun, und das EffektObjekt sagt nur, wie genau er etwas tun soll.

Und so weiter, denke, du weißt, wie "diverse Programmkonstrukte" jetzt gemeint sind ;)
zu 1. Keine Ahnung :p
2. Sowas wie einen EffectHandler hatte ich auch schon überlegt.
Da das Spiel rundenbasiert ist, reicht es, wenn ich zu jedem möglichem Ereignis das Teil abfrage. Beim Angriff, bei der Verteidigung, beim Rundenende, Rundenanfang usw.
Dort hatte ich eben vor alle diese Effekte die zum Beispiel eine Monsterkarte oder Zauberkarte haben kann zu "registrieren" und dann zu dem/den jeweiligen Ereignis/sen auszulösen.
Das wäre dann Teil des Kampfsystems, also dem Kernstück des ganzen, weil dort auch alles zusammengeführt wird (so wie ich mir das jetzt vorstelle)
Das ganze Effekt-Zeug riecht mir auch ziemlich nach Arbeit. Wenn ich neue Effekte ohne Veränderung des Spielcodes hinzufügen will werd ich mir wohl ne kleine Scriptsprache basteln müssen.

str1442 hat geschrieben:Dann solltest du vielleicht First Test Programming anwenden, spätestens da bist du gezwungen, dir die richtigen Fragen rechtzeitig zu stellen. Ist aber auch etwas streßig/nervig.
Mh das hab ich noch nie gemacht ich weiß nichtmal wirklich was das ist :o
str1442 hat geschrieben:Viele empfehlen, schnellstens einen Prototyp zu schreiben: Finde ich grenzwertig, da ein Programm immer extremen Veränderungen unterliegt und man am Anfang selbst mit der Einstellung dann doch irgendwo hängen bleibt, und das Endprodukt vermutlich ziemlich starr ist.

Ich hab eher vor erst die Grundlegenden Dinge zu machen, die wirklich nötig sind und dann auf dieser Basis das ganze zu erweitern. Also irgendwo schon ein Prototyp aber irgendwo auch nicht :p
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Falls ich das nicht schon im anderen Thread schrieb: Fange klein an und baue es aus. Immer nur eine Karte auf einmal. Scheue dich nicht, das Programm immer wieder zu ändern. Beginne von Anfang an, ausreichend Testfälle zu schreiben, sodass du vor Änderungen nicht zurückschreckst.

Ein Rahmenwerk "auf der grünen Wiese" zu entwerfen, ist verdammt schwer und wird dir wahrscheinlich nicht gelingen. Es zu versuchen, ist ein Fehler, den auch "Profis" immer wieder machen. Triff die besten zur Zeit möglichen Entscheidungen und versuche nicht, alles vorherzusehen.

Dein Posting wirkt, was die Features angeht, recht wirr und das ist wahrscheinlich auch dein Problem. Du brauchst eine exakte und konkrete Vorstellung der Anforderungen, um beginnen zu können. Allerdings brauchst du noch nicht alle Anforderungen. Vergiss den Editor, vergiss die Grafik.

Konzentriere dich auf das eine Feature, welches am wichtigsten scheint. Womit würdest du anfangen? Wie wäre es mit den Regeln? Schreibe sie so auf, dass sie vollständig sind und du im nächsten Schritt eine Repräsentation entwerfen kannst. Oder kennst du sie nicht? Dann beginne mit existierenden Regeln, zum Beispiel Magic: The Gathering oder World of Warcraft Trading Card Game.

Spaßeshalber picke ich mir das zweite heraus: Es gibt ein *Deck* mit *Card*s, einen *Hero* und UDEPunkte-Karten (hä?). Der Held hat 5 Eigenschaften: Fraktion, Talent, Beruf und Klasse. Fraktionen sind Horde und Allianz. Talente und Berufe sind Begriffe wie "Treffsicherheit" oder "Lederverarbeitung". Klassen sind Druide, Jäger, Magier, Paladin, Priester und so weiter.

Code: Alles auswählen

class Faction:
    name = str

class Talent:
    name = str
    
class Profession:
    name = str
    
class CharClass:
    name = str

class Hero:
    faction = Faction
    talent = Talent
    profession = Profession
    charclass = CharClass
Eine Karte hat einen Namen, Ausspielkosten, Eigenschaften, Typ(en), eine Beschreibung. Ich will jetzt die Regeln nicht alle lesen, aber ich reime mir mal ein bisschen zusammen: Auf der Webseite findet man praktischerweise eine Kartenliste und dort habe ich mir Blutklaue rausgesucht.

Alle Karten haben Kosten, die ausgegeben werden müssen, wenn man sie ausspielen will. Einige Karten liefern Punkte, die man das ausgeben kann. Einige Karten können nur von einer bestimmten Fraktion ausgespielt werden (Blutklaue ist neutral), sie machen Schaden, haben besondere Fertigkeiten usw.

Code: Alles auswählen

class Card
    name = str
    faction = Faction
    cost = int
    attack = int
    health = int
    description = str
    charclasses = [CharClass]
Schaut man sich die Regeln an, so werden die Karten offenbar nach einem bestimmten Muster abgelegt: Dies würde ich *Hand* nennen und auch mit einer Klasse realisieren. Ich hatte gelesen, dass man immer nur eine einzigartige Karte (noch eine Eigenschaft) ausspielen darf. Dies müsste dann ungefähr so implementiert werden:

Code: Alles auswählen

class Hand...
    def play(self, card):
        if card.unique and self.has_unique_card():
            throw RuleError("you cannot play another unique card")
        self.open_cards.append(card)
Eine andere Karte ist der Sturmangriff. Ihn auszuspielen kostet wohl einen Punkt und nur ein Krieger darf dies. Dann darf man eine Karte ziehen. Der Test auf die korrekte Klasse muss in die `play()`-Methode hinein:

Code: Alles auswählen

class Hand...
    def play...
        if self.hero.charclass not in card.charclasses:
            throw RuleError("your hero cannot play the card")
Das mit der Karte ziehen kann man vielleicht mit einem Zähler realisieren, der sagt, wie viele Karten man noch vom Deck ziehen darf. Ich vermute, man darf pro Runde immer eine ziehen. Dann würde die "Sturmangriff"-Karte diesen Zähler erhöhen. Hier kommt erstmalig ein Effekt in's Spiels:

Code: Alles auswählen

class SturmangriffCard(Card):
    def effect(self, game):
        game.current_player.cards_to_draw += 1
Der Rest ist Fleißarbeit :) Diese Spiele scheinen sich ja dadurch auszuzeichnen, dass es ein Wust an Sonderregeln gibt. Für Magic umfassen die Regeln mehr als 100 Seiten, sagte Wikipedia.

Eventuell kann es interessant sein, eine (forward chaining) "Rules Engine" einzusetzen. Sowas gibt es bestimmt schon für Python, falls nein, ist es eine spannende Fingerübung, den Rete-Algorithmus mal zu implementieren. Ob's wirklich hift, wage ich nicht zu beurteilen. Dazu müsste man erst Mal schauen, welcherart die ganzen Regeln sind.
Antworten