![]() |
OOP und RPG
hi leutz!
So... Jetzt hab ich mal wieder vor ein kleines RPG zu erstellen :D Nur diesmal eben mit OOP. Nur... wie fange ich das an? Wie zum Beispiel sollte das bei einem Charakter oder einem Gegenstand aussehen, etc.? Habt ihr damit schonmal Erfahrung gemacht oder eine Vorahnung? |
Re: OOP und RPG
Delphi-Quellcode:
Das wäre ein guter Anfang.
type
TCharacter=class; public Health, Mana, Strength, Skill, Defense, Intelligence, Fame: Byte; IsEnemy, Alive, Visible, Vulnerable: Boolean; X, Y, MapID, Angle: Word; TileSetID: Word; constructor Create; procedure Hurt(Value: Byte); procedure Kill; procedure Revive; end; |
Re: OOP und RPG
danke :-D
so, nun häufen sich die Fragen: 1. Byte == "Int" bis 256, oder? ja... gut ^^ 2. Wie stelle ich es an, wenn mein Charakter dann beispielsweise eine Statusveränderung hat? 3. gut, das Modell von dir lässt sich natürlich auch einfach auf nen Gegenstand übertragen 4. Wie speichere ich die dann ab? :gruebel: Gut, zur Zeit fällt mir grade nicht mehr ein... [ot]Warum steht eigentlich in deiner Sig, dass Borg keine Schweden sind?![/ot] |
Re: OOP und RPG
[ot]StarTrek 8 First Contact: "Borg? Klingt schwedisch!" (etwas später) "Eindeutig keine Schweden!"[/ot]
1. Klar. Kannst du auch durch irgendnen anderen Integer Typ ersetzen. 2. type TStatus=stNormal, stPoisoned, stFrozen, stBurning...; oder: Poisoned, Frozen, Burning...: Boolean; 3. Klar. 4. Da gibt es einige Möglichkeiten: INI (nicht zu empfehlen), XML, Record, SQL Datenbank (seeehr ungeeignet). Gibt bestimmt noch andere Möglichkeiten. |
Re: OOP und RPG
Hey,
OOP ist eigentlich mehr als gut geeignet für RPGs, schließlich ist die Idee dahinter, das reale Leben (was auch immer das sein soll) abzubilden. Prinzipiell ist jedes einzelne Objekt (Avatar, NPC, Item, Gebäude, ...) ein eigenes Objekt. Du solltest diese in gemeinsame Gruppen (z.B. Avatar und NPC) stecken. Wenn etwas gemeinsame Eigenschaften hat, gehört es in eine Gruppe (und die gemeinsamen Eigenschaften in eine Basisklasse von der alle Mitglieder erben). So kannst du auch später leicht neue Dinge deinem RPG hinzufügen. Was Byte vs. Integer (Cardinal) angeht, solltest du gut überlegen ob es sich lohn die Wertvollen 3 Byte einzusparen. Immerhin wird deine CPU intern eh mit 32Bit arbeiten und somit sind Integers (und Cardinals) immer das Perfomateste. Ein wichtiges Prinzip ist es, dass du dir von Anfang an auch eine Möglichkeit überlegst, wie du auf Ereignisse reagieren möchtest. Wenn sich z.B. die Stärke eines Spielers ändert, solltest du nicht direkt nur den Wert Strength (o.ä.) ändern, sondern dies über Propertys tun. Diese haben den Vorteil, dass sie mit einer Methode verknüpft werden können. Und in eben dieser kannst du auf Veränderung reagieren. An sich solltest du auch eine Art Event-Listener-Modell einplanen. Am einfachsten (schönsten) geht dass, indem du zu allen Ereignissen ein Interface oder eine abstrakte Klasse (also immer eine für Zusammengehörige) vorsiehst. In diesen werden dann zu jedem Ereignis Methoden definiert, die als Argument das eingetretene Ereignis bekommen. Nun kannst du in zentraleren Klassen, die das Ereignis auslösen Listener registrieren, die immer benachrichtigt werden, wenn ein Ereignis auftritt. Dazu müssen die Objekte, die eine Nachricht erhalten wollen, das entsprechende Interface implementieren (oder von der abst. Klasse erben) und sich bei der zentralen Klasse als Listener registrieren. Tritt nun ein Ereignis ein, kann die Klasse einfach jedem der Listener über die entsprechende Methode mitteilen, dass ein Ereignis eingetreten ist (und die Parameter übergeben). Wie du etwas speicherst, kommt ganz drauf an, was du alles speichern möchtest und was nicht. Du solltest alles was Variablen eines Objekts sind in einen großen Stream schreiben (der wahrscheinlich gar nicht so groß wird). Dann gibt es auch noch gute Komponenten, die es dir erlauben Files zu packen. Gibt auch da viele Möglichkeiten. Ich glaube das ist schon mal (ein stark vereinfachter) erster Einblick, was du alles mit OOP machen kannst. Aber (auch wenn es hier noch sehr abstrakt ist) ein RGP ist halt doch ein sehr umfangreiches Projekt! Also nicht zu groß planen, Qualität sollte immer Vorzug haben und dann ist etwas kleines auch leichter zu erweitern und macht auch viel mehr Spaß! Den wünsch ich dir auch, Gruß Der Unwissende |
Re: OOP und RPG
Ich hab mal ein paar Ideen dazu gesammelt, hab das Projekt aber dann gestoppt (nach ein paar Überlegungen), da mir Kenntnisse und Grafiken fehlen.
So Kleinigkeiten hab ich mir schon überlegt, z.B. wie man aus einer Zielkoordinate und der momentanen Position des Spielers einen Winkel herauskriegt. Noch ne Frage: 3D oder 2D? |
Re: OOP und RPG
(Für "Non-RPGler": Avatar == Charakter ;) )
2D per DelphiX (nein, kein openGL, ich versuchs erstmal mit DelphiX!) Also natürlich 2D mit rumlaufen ;) @Unwissender: Im Grunde kenn ich das Prinzip ja schon :) Immerhin mach ich den lieben langen Tag nur RPGs ^^ (Wer mein Browsergame-RPG sehen will, soll mir ne PN schicken :P ) Weitere Fragen: Zitat:
Zu 4.: Für mich kommen derzeit 2 (3) Sachen in Frage: XML => nur wie funktioniert das dann mit diesem OOP? Record => Hö? Records sind doch aber nicht OOP! Stream => weiß ich auch nicht wies funzt ^^' Dann gibt es ja noch "Vererbung". Also ich habs mir so gedacht: Ich erstelle einen Grundcharakter (oder eben gegenstand). Dann gibt es meinetwegen Charaktere, eben von diesem Grundcharakter, die aber die Eigenschaft "Ützlebrütz" haben. So... wie mache ich da, bzw. wie finde ich heraus, ob der /es die Eigenschaft bereits hat, etc.? [ot]Achja, stimmt ;D[/ot] |
Re: OOP und RPG
Also bei Records ist es ganz einfach: Du erstellst parallel zur Klasse noch einen Record mit den gleichen Variablen wie die Klasse nur ohne Methoden und speicherst den dann in ein File.
Bei Vergiftung usw. musst du das halt dann anders machen: Poisoned, Frozen, Burning: Boolean; PoisonDamage, PoisonTime, FrozenTime, BurnTime: Cardinal; //(in ms) Du kannst natürlich einen Grundcharakter erstellen und dann noch THaendler usw. Aber nicht sowas in der Art, dass jeder Charakter in deiner Welt eine eigene Klasse hat, das gibt ein Chaos. Kannst ihm ja noch userdefined Variablen geben. Eine Idee für Quests habe ich auch:
Delphi-Quellcode:
Bei TCharacter kannst du noch die Variable AttackTarget: ^TCharacter; hinzufügen.
type
TQuest = class public Status=(qsUnknown,qsAccepted,qsDenied,qsSolved,qsFailed); UserDefined1, UserDefined2, UserDefined3, UserDefined4...UserDefined10: Integer; //Questabhängig end; |
Re: OOP und RPG
Zitat:
Du solltest doch wissen, ob du eine Eigenschaft bereits gesetzt hast, oder nicht. Ansonsten: Compiler-Fehler abwarten ;) |
Re: OOP und RPG
Allerdings musst du bedenken das du wenn du jeden Charakter als Klasse abbildest du bei jedem Patch den Code ändern musst. Daher empfiehlt es sich .NET zu verwenden, da du dort jeden Charakter in eine Assembly packen kannst, und diese Dynamisch laden!
|
Re: OOP und RPG
Na ja, die Idee hinter dem Vererben ist es natürlich, dass du dem Grundcharakter erstmal alle sehr allgemeinen Eigenschaften zuweist (e.g. Name, Aussehen, Job, ...).
Dann erben von denen die Spezielleren Charaktere, die haben (dadurch dass sie den allgemeinsten beerben schon all dessen Eigenschaften). Alle erbenden werden dann weiter unterteilt in speziellere Erben. So könntest du von ganz Allgemein Charakter (mit Name, Aussehen und Job) eine Klasse NPC und eine Klasse Characters ableiten. Dann hat ein NPC also auch einen Namen, einen Job und ein Aussehen. Das wird sicher auch jeder Character haben. Doch wird ein NPC wohl eher nie krank und wenn er in Ruhe in seinem Haus sitzt interessieren dich wohl auch die LPs weniger. Den Characters könntest du noch weitere Eigenschaften geben (Lebenspunkte, Mana, Gegenstände, was weiß ich...). Beim Abspeichern musst du dir nur überlegen, wie du alles am besten ablegen (und wieder laden) kannst. Meine damit garnicht, dass du dir überlegen sollst ob nun IniFile, XML oder Records (wie speichert man denn die direkt?). Sondern vielmehr welche Daten du hast und wie man die am besten Strukturiert. Du kannst zum Beispiel in einer zip-Datei (mit eigener Erweiterung != .zip) mehrere Dateien anlegen. In einer speicherst du dann nur, was zu deinem Avatar gehört, in ner anderen die erfüllten Quests oder so... Zum Speichern, letztlich ist ein Stream nur ein sehr einfaches Modell. Du streamst (wer hätte das Gedacht) einfach ein paar Bytes weg. Wo die hingehen wird durch den Stream komplett abstrahiert. Könnte ein Netzwerk sein, eine File oder was ganz anderes. Sehr Flexibel, aber halt eher low-level. Also beim Laden hast du dann nur Bytes und musst dir halt vorher ne Struktur überlegen, wo was liegt. Aber beim Speichern und Laden von eigenen Daten kommst du da eh weniger drum rum. Also heißt es erstmal die Struktur zum Laden/Speichern überlegen. Was muss gespeichert werden? Wie kann man das flexibel halten (weitere Daten hinzufügen, alte entfernen...) |
Re: OOP und RPG
Zitat:
|
Re: OOP und RPG
Der is halt grade auf dem .NET Trip. :mrgreen:
|
Re: OOP und RPG
Zitat:
|
Re: OOP und RPG
Ich frage mich auch, was er mit OpenGL will. Für das, was wir vorhaben ist es nicht nötig, plattformübergreifend zu werden.
@Master_RC: Wenn du mal allgemein Hilfe brauchst (wenn du weiter bist, Charaktere, Quests, Maps, Story usw.) wäre ich froh, wenn du mich fragen würdest. Ich hätte seeehr gerne ein RPG á la DivineDivinity (nur so ungefähr, nie so eine hohe Qualität) hingekriegt, bin aber dafür wohl zu dumm/newbig. |
Re: OOP und RPG
Mal ganz allgemein und damit Off-Topic?, nehmt immer das womit ihr es am leichtesten hinbekommt. Und wenn jmd. ein super RPG in 3D nur in Lisp schreiben kann, dann sollte er/sie halt Lisp benutzen. Also letztlich sind alle Programmiersprachen (annähernd) gleichmächtig, auch wenn es in einigen ein, zwei Zeile mehr Code braucht.
Selbes gilt natürlich auch für OpenGL (kann nicht sehen dass es hier jmd. empfohlen hat) und DelphiX (und allem anderen). Kann hier nur sagen was schon gaaaaaanz viele vor mir sagten, ist einfach nur Geschmackssache. Denke jeder hat da seine Gründe und Vorlieben und wen interessiert bitte ob ein Spiel mittels OpenGL oder DirectX oder KryptaV7build 28 alpha gemacht wurde, hauptsache es sieht nett aus und macht Spaß. Also nie reinreden lassen und nehmen was einem liegt! |
Re: OOP und RPG
Zitat:
Naja, es gibt einige Vorteile, z.b. das benutzen von List<> ermöglicht jedes beliebige Objekt mit beliebig vielen Eigenschaften in eine Liste zu fassen. Zudem lassen sich neue Spielelemente ohne großes Umschreiben hinzufügen. Es für viele Spielefirmen auch keinen Grund nicht .NET zu verwenden( Ausser vielleicht der etwas bessere lesbare Code ), nur haben sie den großen Teil ihrer Engine schon in C++ geschrieben und das wäre zuviel Arbeit es umzuschreiben in einen .NET Dialekt. Zitat:
Du glaubst garnicht wieviele Spielefirmen inzwischen Linuxversionen mit auf die CD packen! |
Re: OOP und RPG
Zitat:
ich denke kaum, dass ich soweit komme ;) @Der_Unwissende: Gut... dann wären da wieder Fragen: Wie geht das mit dem Vererben, bzw. wie stelle ich das am blödsten an? Und... wie kann ich dann so eine Art ZIP-Archiv ertsllen? Wegen den verschiedenen Dateien: Ich hatt ja schonmal ein RPG versucht ;) Da hab ich dann eben für jeden Charakter/Avatar einen exra Ordner angelegt, in dem jede Menge Dateien waren ^^ Und... wie kann ich "streamen"? Wie schwer ist das? [ot]Mir kommts so vor, als ob du schon einige Erfahrung damit gesammelt hast... (Und du hast Spellforce gespielt ;) )[/ot] |
Re: OOP und RPG
[ot]Meinst du mich?[/ot]
Übrigens: Ich habe geschrieben: nur so ungefähr, nie so eine hohe Qualität Also, ich habe das auch nicht erwartet. ZIP kriegste mit der ZLib hin. Guck mal in ![]() |
Re: OOP und RPG
Zitat:
Versuch mal DirectX ohne emulator auf Linux zum laufen zu bekommen. Oder schreib mir mal ein Game mit Brainf*ck( Ok schlechtes Beispiel ), sicherlich hat jeder Vorlieben, aber warum nichts neues Probieren? |
Re: OOP und RPG
Zitat:
Delphi-Quellcode:
Dazu noch eine globale Liste, in die sich der State einfügt (nur über das Interface) und die dann jeden Frame ihre Items durchrattert.
ITiming = interface
procedure Advance(dTime: Cardinal); end; //[...] TState = class protected FOwner: TAvatar; public constructor Create(AOwner: TAvatar); end; TTimeBasedState = class(TState, ITiming) protected FRemainingTime: Cardinal; class function GetDuration: Cardinal; virtual; abstract; public property RemainingTime: Cardinal read FRemainingTime; constructor Create(AOwner: TAvatar); procedure Advance(dTime: Cardinal); virtual; end; TPoison = class(TTimeBasedState) protected class function GetDuration: Cardinal; override; public procedure Advance(dTime: Cardinal); override; end; implementation {$R *.dfm} { TState } constructor TState.Create(AOwner: TAvatar); begin FOwner := AOwner; end; { TTimeBasedState } constructor TTimeBasedState.Create(AOwner: TAvatar); begin FRemainingTime := GetDuration; end; procedure TTimeBasedState.Advance(dTime: Cardinal); begin Dec(FRemainingTime, dTime); FOwner.States.RemoveMe; end; { TPoison } class function TPoison.GetDuration: Cardinal; begin Result := 10 * 1000; // 10 s end; procedure TPoison.Advance(dTime: Cardinal); begin inherited; FOwner.Health -= 10 * dTime / 1000; // 10 Schaden pro Sekunde end; Naja, so könnte ich es mir jedenfalls vorstellen ^^ . *diskussionwiederauftopicführ* :angel2: |
Re: OOP und RPG
Immer ich. Aber er hat ja recht. Ich bin so strenge OT Regelungen nicht gewohnt.
|
Re: OOP und RPG
Zitat:
Zitat:
Was das zippen angeht, es gibt ein paar Komponenten die das können. Hab leider im Moment keine, die ich verwende. Aber du findest mit googlen oder hier suchen sicher schnell was passendes. Und da ist es eigentlich die Regel, dass die in einer Datei beliebig viele weitere speichern können. Würde dir dazu raten, dann eine Datei für die NPCs, eine für die Quests usw. anzulegen. In den Dateien kannst du dann (hoffentlich) die gespeicherten Daten immer gleich strukturiert (also gleich groß) ablegen, dass macht das lesen schonmal leichter. Was das Vererben angeht, auch dass ist eigentlich sehr einfach. Du hast eine Klasse
Delphi-Quellcode:
Beim ableiten schreibst du die Basisklasse (immer nur eine möglich) in die Klammern hinter class
type
TBaseClass = class(TObject) private // Felder & Methoden die nur TBaseClass sehen soll protected // Felder & Methoden die beim vererben auch von der erbenden Klasse gesehen werden public // Felder & Methoden die jeder sieht end;
Delphi-Quellcode:
wobei dann TNpc auch das Feld aussehen, job und die Methode doFoo hat, zusätzlich halt auch building.
type
TCharacter = class(TObject) protected job : TJob; aussehen : TAussehen; procedure doFoo(); public constructor create(...); destructor destroy; override; end; TNpc = class(TCharacter) private building : TBuilding; public end; |
Re: OOP und RPG
Nebenbei bemerkt kann man das (TObject) nach dem Klassennamen auch weglassen.
|
Re: OOP und RPG
Zitat:
Hui, denn genauso will ichs haben :mrgreen: Nur kann ich mit dem Code wenig anfangen, vlcht. muss ich nur näher hingucken... :? kann mir jemand zu dem code von Khabarakh eine Art "Tutorial" - oder eher eine gute Beschreibung liefern? So... jetzt ist mir noch was aufgefallen: Wenn das vorhin der Code fürs Vergisten war. So... nehmen wir an, ich hätte noch Verbrennung, Dies, Das, Et cetera, Et ceteri (hihi, "ceteri" gibts nicht ^^) Dann wird das ja im Quelltcode nen Haufen Text... :| Kann ich den Code vlcht. irgendwie irgendwo auslagern oder so? |
Re: OOP und RPG
Auch mal ne Frage zum Thema (MMO)RPG ;)
Ich bin grad lustigerweise auch dran *fg* und schreib grad die Klasse für einen NPC. Laufen tut er ja - allerdings sollte er sich etwas schlauer verhalten im Laufen. Momentan mache ich es so, dass ich per "if Random(200)=0" entscheide, ob er überhaupt die Richtung wechseln soll. Allerdings führt das eben zu recht blöden Laufverhalten *fg* Gibt es da evtl. eine bessere Lösung, die ihn etwas realistischer laufen lässt? air |
Re: OOP und RPG
Du kannst ihm einen vorgefertigten Weg vorgeben. Oder nur bei jedem x-ten Durchlauf eine Richtungsänderung vorschlagen.
|
Re: OOP und RPG
@airblader:
Bitte mach damit ein eigenes Thema auf, ich bin hier sowieso schon stark gefordert! Danke ;) (Arrrgh... wär ich doch nur in der Schule gefordert, wär ichs gewohnt ;) ) |
Re: OOP und RPG
Die Idee ist Grundsätzlich richtig, nur würde ich mir über den Aufbau noch Gedanken machen.
Code:
Dies Stellt eine Sinnvolle Schnittstelle dar( Ist allerdings sicher noch ein Fehler drin ), welche demonstrieren soll wie man ein Schadenssystem erstellt!
interface IDamage
{ int TakeDamage(int mode, int damage); int GetDamageMode(); void DirectDamage(int damage); } class RPGObject { private int health; private Vector3f position; //.... propertys und sowas } class Human : RPGObject { private HumanDamage Damagesystem; // ....blablabla void TakeFightAction(IDamage damagesystem) { .... } } class HumanDamage : IDamage { int TakeDamage(int mode, int damage) { .... } int GetDamageMode() { .... } void DirectDamage(int damage) { .... } } Dies ist nur ein kurzer Hinweiss von mir wie man ein Spiel mithilfe von Klassen und Interfaces aufbauen kann. Wenn man mit Interfaces Arbeitet kann man sich einige Lästige Dinge Erspaaren, und kann unabhängig von Fähigkeiten und Spezialfähigkeiten ein Spiel Programmieren welches auch ohne Fehler läuft. Dazu muss man eben wie oben im Beispiel gezeigt z.b. eine Sinnvolle Schnittstelle für das Schadenssystem programmieren. |
Re: OOP und RPG
muss das unbedingt C sein? :gruebel:
|
Re: OOP und RPG
Zitat:
Das ist C#!! :mrgreen: Zudem weiss ich garnicht ob das mit der Interfaceübergabe in Delphi möglich ist( Inzwischen bin ich mehr in C# drin als in Delphi :zwinker: )!?!?! Sollte allerdings kein Hinderniss darstellen, da ja kein Quellcode drin ist der kompliziert ist! |
Re: OOP und RPG
kann ich das nicht anders machen?
Äh.. junge.. ich steh grad erstmal bei en Grundlagen da, wie ich das Projekt machen soll :gruebel: Und ob des nun C oder C# ist, ist mir eigentlich egal, weil ich jetzt erstmal Delphi mach! Sry, aber ich will mich grade nur auf das Ding hier konzentrieren! |
Re: OOP und RPG
Delphi-Quellcode:
so besser?
Type IDamageable = interface
function TakeDamage(Mode, Damage: integer): integer; function GetDamageMode: integer; procedure DirectDamage(damage: integer); dann müsste jedes Objekt, das Schaden nehmen kann, IDamageable implementieren(ja, so heisst das):
Delphi-Quellcode:
Jeder, der Schaden zufügen will, braucht sich dann nur das IDamgeable-Interface von einem TCharacter zu holen, und kriegt vom Rest nix mit. Ein sehr schöner Weg, um das Sichtbarkeitsprinzip von OOP umzusetzen, und für verteilte Projekte mit mehreren Entwicklern ("Gib mir nur das Interface...") fast unumgänglich.
type TCharacter = class(TEntity, IDamageable, ISomethingElse)
//hier irgendwas.... public //IDamageable function TakeDamage(Mode, Damage: integer): integer; function GetDamageMode: integer; procedure DirectDamage(damage: integer); public //ISomethingElse function WhatEver():TSomeType; Das als kleine Einführung in Interfaces ;) |
Re: OOP und RPG
Zitat:
Beide Wege kommen auf das selbe hinaus, nur deiner ist etwas schöner! :wink: |
Re: OOP und RPG
Und wie benutz eich dann dieses "Interface"?
|
Re: OOP und RPG
Zitat:
Code:
In Delphi( hoffe es geht so ):
void TakeFightAction(IDamage damagesystem)
{ .... }
Delphi-Quellcode:
procedure TakeFightAction(var damagesystem: IDamage)
begin damagesystem.DirectDamage(50); end; |
Re: OOP und RPG
jetzt qeiß ich immernoch nicht, wo ich es benutze :lol:
|
Re: OOP und RPG
Mein
![]() |
Re: OOP und RPG
Zitat:
|
Re: OOP und RPG
@sniper_w:
danke, ich werds mir mal anschauen, hab ich moment abe rwenig zeit :( @speedmaster: toll... was bringt mir ein schnippselchen code, wenn ich nicht weiß, wo ich ihn benutzen soll? Dann hätt ich ja ga rnicht mit dem Thema hier nafangen brauchen -,-' |
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:52 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz