![]() |
gegenseitiger Zugriff von zwei abgeleiteten Klassen
Hi alle zusammen.
Folgendes Problem: Ich versuche gerade ein kleines Rollenspiel zu programmieren, wo ich zum ersten Mal versuche, mittels Objekten meine Dinge im Spiel zu beschreiben (bietet sich ja besonders an :-D). Grober Aufbau soweit: Bewegliches Objekt = Class () mit x-Position, y-Position ,Leben, Angriffskraft etc 1x Spieler Objekt = Class (Bewegliches Objekt) viele Monster Objekte = Class (Bewegliches Objekt) Dinge die schon funktionieren sind z.B. das Bewegen, da wird eine Funktion aus Bewegliches Objekt aufgerufen, mit der ich den Spieler oder die Monster bewegen kann. Soweit so gut. Was ich jetzt versuche herauszubekommen: Ich möchte eine gemeinsame Angriffsroutine schreiben, die in Bewegliches Objekt verankert ist. Einerseits soll es möglich sein, dass das Spieler Objekt ein beliebiges Monster Objekt angreifen kann. Andererseits soll es möglich sein das ein Monster Objekt das Spieler Objekt angreift. Zur Krönung soll es dann noch möglich sein, das ein beliebiges Monster Objekt ein anderes beliebiges Monster Objekt angreifen kann. (hoffe das versteht einer :?) Wie kann ich ein Zugriff von einem Beweglichem Objekt auf ein anderes Bewegliches Objekt ermöglichen? Ist es sinnvoll eine Art Counter-ID für jeden neue Bewegliche Objekt zu vergeben? Kann ich eine Funktion in Beweglichen Objekt aufrufen, die einen Zeiger auf ein anderes Bewegliches Objekt hat? Welche Texte sollte ich zu dem Thema noch lesen? Danke euch soweit erst einmal. Martin |
AW: gegenseitiger Zugriff von zwei abgeleiteten Klassen
Einfach als "Bewegliches Objekt". GGf. dann wirklichen Typ überprüfen
Delphi-Quellcode:
if <Objekt> is Spieler then ...
|
AW: gegenseitiger Zugriff von zwei abgeleiteten Klassen
Delphi unterstützt leider keine
![]() M.E. Ist das der einzige wirkliche Makel an Delphi. Die Kompilierung geht so schneller, man muss allerdings häufig auf Typecasts zurückgreifen. Ich würde mir wünschen, dass sich Vorwärtsdeklarationen (die ja innerhalb einer Unit möglich sind):
Delphi-Quellcode:
ClassB = class;
auch auf andere Units anwenden lassen:
Delphi-Quellcode:
ClassB = class in unit ClassB;
Zumindest wenn bestimmte Rahmenbedingungen (die eine solche Auflösung absolut ausschließen würden) eingehalten werden. Im Moment meckert mir der Compiler einfach zu schnell. Habe ich ClassA und ClassB in einer Unit stehen, gibt es keine Probleme. Gliedere ich diese aber aus Gründen der Übersichtlichkeit in zwei getrennte Units aus, ändert sich ja eigentlich an den Beziehungen untereinander nichts. Delphi lehnt dies aber ab - und DAS PRANGERE ICH AN! :stupid: |
AW: gegenseitiger Zugriff von zwei abgeleiteten Klassen
Hi.
Ja das es keine überkreuzenden Units gibt, finde ich auch 'ungünstig'. Daher muss ich ja auch alle wichtigen Objekte in eine Unit schreiben. @mkinzler Der is Operator funktioniert doch nur wenn die Objekte auch erzeugt habe, oder? (bei mir ist Bewegliches Objekt nur die Basis, von den ich dann Spieler und Monster ableite diese dann deklariere und initialisiere...) Martin |
AW: gegenseitiger Zugriff von zwei abgeleiteten Klassen
Ja ab, da ja die IS-A Beziehung zwischen Klasse und Superklasse besthet, ist jedes Objekt vom Typ Spieler/Monster gleichzeitig auch vom Typ "Bewegliches Objekt"
Delphi-Quellcode:
function <Klasse>.TesteWas( Obj1, Obj2: TBewObjekt);
begin if ((Obj1 is TPlayer) and (Obj2 is TMonster)) or ((Obj2 is TPlayer) and (Obj1 is TMonster)) then //Kollision Spieler mit Monster begin ... end; ... end; |
AW: gegenseitiger Zugriff von zwei abgeleiteten Klassen
Du willst doch 2 Objekte gegeneinander kämpfen lassen. Dann mach das doch
Delphi-Quellcode:
procedure Fight( const AObj, BObj : TBewObj );
begin AObj.Leben := AObj.Leben - BObj.Staerke; BObj.Leben := BObj.Leben - AObj.Staerke; end; |
AW: gegenseitiger Zugriff von zwei abgeleiteten Klassen
Zitat:
Delphi-Quellcode:
Das ist ziemlich straightforward.
procedure TMovableObject.Fight(AOther : TMovableObject);
begin Self.Leben := Self.Leben - AOther.Staerke; AOther.Leben := AOther.Leben - Self.Staerke; end; Interessant wirds erst, wenn es einen Unterschied macht, wer gegen wen kämpft. Siehe hierzu: ![]() ![]() mfg Christian |
AW: gegenseitiger Zugriff von zwei abgeleiteten Klassen
Zitat:
Da kann auch jeder mit jedem und die lästige Forward-Deklaration fällt auch weg.
Delphi-Quellcode:
type
TThing = class procedure CollideWith( Thing : TThing ); end; TShip = class( TThing ) end; TAsteroid = class( TThing ) end; TBase = class( TThing ) end; TThingCollisionHelper = class helper for TThing procedure CollideWith( Thing : TShip ); reintroduce; overload; end; TShipCollisionHelper = class helper for TShip procedure CollideWith( Thing : TShip ); reintroduce; overload; procedure CollideWith( Thing : TAsteroid ); reintroduce; overload; procedure CollideWith( Thing : TBase ); reintroduce; overload; end; TAsteroidCollisionHelper = class helper for TAsteroid procedure CollideWith( Thing : TShip ); reintroduce; overload; procedure CollideWith( Thing : TAsteroid ); reintroduce; overload; end; |
AW: gegenseitiger Zugriff von zwei abgeleiteten Klassen
Class helpers hier zu nutzen ist ne interessante Idee. Gefällt mir. Aber es löst das Problem nicht. Zusätzlich ist immer noch eine is-Verzweigung oder das Visitor-Pattern nötig. Beispiel:
Delphi-Quellcode:
Hier wird
var
a, b: TThing; begin a := TAsteroid.Create; b := TShip.Create; a.CollideWith(b);
Delphi-Quellcode:
aufgerufen. Und nicht
TThing.CollideWith( Thing : TThing );
Delphi-Quellcode:
Und das ist der springende Punkt...
TAsteroidCollisionHelper.CollideWith( Thing : TShip );
mfg Christian |
AW: gegenseitiger Zugriff von zwei abgeleiteten Klassen
Es fehlt mindestens eine weitere Klasse.
Beim Spieler und Monster würde man eine zusätzliche Waffen-Klasse einsetzen. Wenn der Spieler das Monster angreift, dann stirbt das Monster nicht durch den Spieler, sondern durch dessen Waffe(n). Wenn also eine Figur angegriffen wird, dann entscheidet die Waffe(n) und die Defensivkraft des Gegners über den Ausgang des Angriffs. Daher müssen zwei Klassen (TSpieler und TMonster) sich gegenseitig nicht kennen, sondern sie können jede notwendige Information über die gemeinsame Basisklasse erfahren. |
AW: gegenseitiger Zugriff von zwei abgeleiteten Klassen
Zitat:
mfg Christian |
AW: gegenseitiger Zugriff von zwei abgeleiteten Klassen
Ich denke man kann hier folgendermaßen vorgehen(so mach ich das normalerweise)
Wir definieren eine Klasse TEntity. TEntity hat verschiedene Parameter die genutzt werden können(leben, waffen und vielleicht nochn paar neutrale skills bei bedarf). TEntity besitzt ein Event EntityAction. Ich entferne mich an dieser stelle davon für jeden Typus eines Gegners eigene Klassen abzulaieten, und benutze eine einzige. Der clou an der sache ist, dass das was das Object machen soll an dass EntityAction event Attached wird. Erstellen wir eine TEntity dass als Gegner fungieren soll kann so zb die selbstgeschriebene Methode Gegner genutzt werden, ODER wir schreiben eine Methode die den Playercode enthält. Beispiel(aus meiner kleinen mini 2dengine)
Code:
Ein einfaches beispiel für eine Entity Klasse
TEntity = class(TComponent)
public Mesh: TMesh; Skill1: Single; Skill2: Single; Skill3: Single; Skill4: Single; Skill5: Single; Skill6: Single; Skill7: Single; Skill8: Single; Skill9: Single; Skill10: Single; EntityAction: procedure(My: TEntity); constructor Create(AOwner: TComponent); override; end; Eine Aktion für das Object kann dann so geschrieben werden:
Code:
Zugewiesen kann es dann so werden:
procedure MeineAktion(My: TEntity)
begin My.Skill1 := My.Skill1+2; end;
Code:
MeineEntity.EntityAction := MeineAktion;
Dann brauchst du noch eine schleife, die alle aktionen der in einer liste gespeicherten Objekte ausführt:
Code:
FEntityList ist ein Array indem alle erstellten Entyties hinterlegt sind.
procedure TEngine.DoEntityActions;
var i: Integer; begin for i := 0 to FEntityCount - 1 do begin if Assigned(FEntityLIst[i].EntityAction) then begin FEntityLIst[i].EntityAction(FEntityLIst[i]); end; end; end; Deren EntityAction wird(falls verfügbar) aufgerufen und der Action die Entity instanz übergeben. Dass mal als anregungen ;) Wenn was unverständlich ist, einfach nachfragen^^. Bin schlecht im erklären :D EDIT: die erstellung meines Spielers sieht bei mir dann z.B. so aus(ginge noch schöner, aber war maln "Iam Boored" projekt^^:
Code:
EDIT2: Und Außerdem gehören Pos_X/Y eigentlich nicht in die Meshklasse*hust*
Player := GameEngine.AddEmptyEntity(Point(0,0),Self);
Player.Mesh.LoadFromMesh(CarMesh); Player.Mesh.Pos_X := -25; Player.Mesh.Pos_Y := 650; Player.Mesh.RefreshBBox(); Player.EntityAction := PlayerAction; Kommt zur Entity, da das Mesh per Entity Position für die WeltPosition versetzt wird. MFG Memnarch |
AW: gegenseitiger Zugriff von zwei abgeleiteten Klassen
Ja das geht auch, ich würde das so aber nicht machen. Aus mehreren Gründen. Der Hauptgrund ist, dass es letztendlich unübersichtlich wird. Wenn das Programm wächst hast du viele Objekte, die sich nur in den zugewiesenen Events unterscheiden. Wenn du jetzt mehr als nur eine Stelle hast, die sich für verschiedene Gegner ändert (Bewegung, Aussehen, Kampftaktik, was weiß ich), wird es schwer noch durch zu blicken, weil nicht klar ist, welche Events zusammengehören also dem selben Gegnertyp zuzurechnen sind. Außerdem kannst du so nicht so einfach mehrere gleichartige Gegner erstellen (der Aufwand hält sich in Grenzen, aber du müsstest extra ne Funktion dafür schreiben).
Zudem sind so die Variationen an Gegnern beschränkt. Events haben den Vorteil, dass du sie zur Laufzeit wechseln und zuweisen kannst. Das nutzt du hier aber nicht. Und selbst wenn du das bräuchtest, könntest du das besser per Delegation lösen... Events verwendet man normalerweise nur da, wo es wirklich um Ereignisse geht (ja es gibt diverse Ausnahmen). Also um Schnittstellen zu anderen Klassen. Als Ersatz für Vererbung sind sie IMHO eher nicht sinnvoll. Sry, aber IMHO hat deine Lösung mehr Nach- als Vorteile. mfg Christian P.S.: Nimm properties. Public fields sind bööse... |
AW: gegenseitiger Zugriff von zwei abgeleiteten Klassen
Zitat:
Ich glaube du hast DoEntityAction nicht verstanden. Der MY parameter wird auf das aktuell zu nutzende objekt gesetzt. Zitat:
Bitte nicht vergessen, Es wird auch nicht spezielle eine Angriffsfunktion geschrieben, sondern generell eine Angreif funktion die verschiedene werte von EntityA und EntityB auswertet. |
AW: gegenseitiger Zugriff von zwei abgeleiteten Klassen
Zitat:
Zitat:
Zitat:
- du kannst auf keine privaten Felder zugreifen - damit kannst du auch keine Methoden (bzw. bei dir Events) über einen internen Zustand koppeln. Alles, was deine Events tun, muss nach außen sichtbar sein. - du kannst auch keine neuen Methoden und Eigenschaften hinzufügen Das alles (und vielleicht noch mehr) schränkt dich ein. Auf der anderen Seite hast du diverse Nachteile auf Seiten der Lesbarkeit: - du verstößt gegen das Prinzip der geringsten Überraschung: Man erwartet eine solche Verwendung von Events nicht. Man kann so etwas tun, sollte dann aber einen sehr guten Grund dafür haben. - zusammengehöriger Code (Code für Gegner A) ist nicht in einer Klasse gruppiert. Damit fehlt Übersicht - du bietest diverse Möglichkeiten deinen Code falsch zu benutzen. Beispielsweise durch falsche oder fehlende Eventzuweisungen. Guten Code kann man intuitiv richtig benutzen, aber nur schwer falsch. Das alles sind Nachteile. Gravierende Nachteile. Echte Vorteile bringt dein Ansatz aber keine. Zumindest hab ich keine entdecken können. Auf weitere Probleme in deinem Code (Skill1..Skill10 uaahhh...) gehe ich aus Zeitgründen jetzt nicht weiter ein. Sei mir nicht böse, aber dein Ansatz ist wirklich nicht so gut. Überdenke ihn nochmal. mfg Christian |
AW: gegenseitiger Zugriff von zwei abgeleiteten Klassen
Zitat:
So z.B. Move, was eine Entity zum gegebenen Punkt bewegt und dabei kollision ausführt. Aber stimmt für reines OOP ist das nicht unbedingt was :P Rührt noch aus alten Tagen diese Angewohnheit:twisted: Is jetzt Ca 3/4 MOnate alt der Code, seitdem einiges mehr gemacht in Delphi. Trotzdem gäbe es bei mir immer einige Funktionen die absolut nicht in der Entity landen würden(siehe move). Ich bin als Zentrum TEngine orientiert die alles andere Steuern kann(Bzw, deren funktionen werden von dene ntities genutzt. Enginen verwaltet halt alles) Und was SKill1-X angeht..naja, wirklich nichts feines :D |
AW: gegenseitiger Zugriff von zwei abgeleiteten Klassen
Zitat:
![]() mfg Christian |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:27 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