Programmieren - alles kontrollieren 4.939 Themen, 20.672 Beiträge

Frage zu Delphi 7 - mal wieder ;-)

KoRny Boy / 7 Antworten / Flachansicht Nickles

moin moin,

ich hab in einem Programm das ich mit Delphi 7 programmiere(also es soll ein kleines Spiel werden) folgende Vorstellung wie es funktionieren soll:

- 4 Planeten
- 2 Spieler mit verschiedenen Werten(Rohstoffe, Militäreinheiten,...)

Jetzt bin ich dabei, dafür ein Object zu definieren:

Type
Planet = Object
Spieler1 : Record // Spieler1 = Mensch
{Variablen für
Rohstoffe, Miltär,
Wirtschaft,...}
End; // End Of Record
Spieler2 : Record // Spieler2 = Computergegner
{Variablen für
Rohstoffe, Miltär,
Wirtschaft,...}
End; //End Of Record
End; // End Of Object

Var
Planet_ : Array [1..4] Of Planet

dann möchte ich später das im folgenden Sinne verwenden:

Planet[1].Spieler[1].Gold := x;
oder
Planet[4].Spieler[1].Gold := y;

halt so, dass die Werte der Variablen vom Planeten, den der Spieler besitzt, abhängt, aber trotzdem beide einem Spieler zugeordnet sind...

Jetzt finde ich das aber unprofessionell dass ich die Variablen alle doppelt deklarieren muss. Also dachte ich an einen Array[1..2](Also dann Player[1].Gold zum Beispiel und Player2.Gold) des Records, aber das ist nicht möglich, bzw ich weiß nich wie man das programmiert...

Ich hoffe ich konnte meine Vorstellung einigermaßen klar darstellen.
Wäre nett wenn mir da jemand weiterhelfen könnte...

MfG KoRny Boy

Wer anderen eine Grube gräbt ist selbst ein Schwein
bei Antwort benachrichtigen
Andreas42 KoRny Boy „hmmmmmmmmm..... type TWirtschaft1 Object Menge, Ertrag : Integer Kosten:Record...“
Optionen

Hi!

Ich hab' im Moment leider kein Delphi oder Turbo-Pascal da, deshalb mache ich meine Beispiele mal aus dem Gedächtnis im TurboPascalformat. Ich nutze Records, damits nicht zu komplex wird (für den Anfang). Ja, es ist übrigends so, dass man RECORD durch OBJECT ersetzen kann. CLASS hat (glaube ich) eine leicht andere Syntax.

Ich würde mir einen Datensatz für die einzelnen Besitzvarianten erstellen. Das hat IMHO den Vorteil, dass man dann beim Verwalten mit allgemeinen Routinen auskommen kann, ohne dass man dabei dann sachen wie Milität oder Landwirtschaft unterscheiden muss.
Irgendwie werden die ganzen Dinge ja vergleichbar sein: man muss ein paar Werte verwalten, dass wird bei Milität und bei Landwirtschaft auch so sein.

TypeGameBesitz:record
TypeID:integer;
OwnerID:integer;
Desc:string;
Wert1:extended;
end;

In TypeID wird ein Wert eingetragen, der festlegt, um was es geht, am besten definiert man die Rypen als Konstanten:

const
ID_Militaer = 1;
ID_Landwirtschaft = 2;
ID_Energiewitschaft = 3;
ID_Kulturstand = 4;

Der Vorteil ist, dass du dann später recht einfach neue Typen hinzufügen kannst: an den eigentlichen Verwaltungsroutinen braucht man nichts zu ändern, nur die Auswertung muss erweitert werden.

Die OwnerID ist ein kleiner Kunstgriff im Voraus: da speichern wir die Nummer des Spielers ab, der dann diesen Besitz zugeordnet wird. Desc ist einfach eine Beschreibung, die sollte man auch als Konstante anlegen:

const
ID_DescMilitaer = 'Militär';
ID_DescLandwirtschaft = 'Landwirtschaft';
ID_DescEnergiewitschaft = 'Energiewirtschaft';
ID_DescKulturstand = 'Kultur';

OK, kommen wir zu den Planeten:

TypeGamePlanet:record
PlanetID:integer;
Desc:string;
besitz:array[1..20] of ^TypeGameBesitz;
end;

Das meiste ist schon bekannt: der Planet bekommt eine Kennung (Kennnummer) und eine Beschreibung. Würde ich wieder als Konstanten anlegen.

Die Besitztümer speichern wir einfach in einem Array ab. Die Beschränkung auf 20 Elemente ist jetzt willkührlich. Dassann man erweitern, sinnvoll wäre eigentlich eine variable Grösse, da kannst du dich ja austoben. ;-)

Im Prinzip braucht man jetzt noch ein paar Routinen zur Verwaltung des ganzen. fangen wir mit einer zur Initialisierung der Besitzthümer an.

Ich hoffe, ich komme mit der Systax für zeiger nicht durcheinander...

function InitGameBesitz(ID;Owner:interger; NewDesc:string; NewValue:Extended):^TypeGameBesitz;
begin
InitGameBesitz := new(TypeGameBesitz);
with InitGameBesitz^ do
begin
TypeID:0id,
OwnerID:=Owner;
Desc:=NewDesc;
Wert1:=NewValue;
end;
end;

Für den Planet muss man nun drei Funktionen schreiben:

1. Eine Init zum Initialisieren des Planeten mit seiner Nummer, der Beschreibung.
Hier sollte dann auch der Array gelöscht werden.
2. Eine Funktion zum Abspeichern oder ändern eines Besitzes.
Als Parameter würde die Funktion nur einen zeiger auf einen besitz bekommen. Mit dessen BesitzID (die den Typ des Besitzes festlegt) und der OwnerID kann man feststellen, ob der Spieler (OwnderID) bereits einen solchen Besitz auf dem Planeten hat, falls nein, wird er neu im Array gespeichert, falls ja, dann muss man den Eintrag austauschen.
3. Eine Funktion, die einen Besitz in ihrem Array sucht. Sie erwartet ebenfalls den BesitzTyp und die Nummer des Spielers. Sie durchsucht dann das Array und liefert NIL oder einen Zeiger auf den entsprechenden Besitz zurück.

Wie gesagt: der Vorteil ist, dass diese ganzen Verwaltungsroutinen dann unabhängig vom besitztyp funktionieren. Egal, ob das nun Militär oder Landwirtschaft ist.

Was so noch nicht geht, ist verschiedene Definition von Besitztypen parallel zu nutzen. dazu muss man dann an die Objekte ran. Das wäre aber auch nciht alzu schwer, da ich mit meinem "Plan" bereits eine typische Struktur erzeugt habe, die man dann recht einfach in Objekte überführen kann: es gibt feste Datentypen und Routinen, die nur einen speziellen datentyp bearbeiten können - aber es gibt noch keine formelle Verbindung zwischen diesen beiden Bestandteilen. das machen erst Objekte: die können dann neben variablen auch Prozeduren und Funktionen wie eine Vraiable aufnehmen. Die Deklaration des Besitzes als Objekt sieht dann so aus:

TypeGameBesitz:object
{Variablen des Objektes:}
TypeID:integer;
OwnerID:integer;
Desc:string;
Wert1:extended;
{Funktionen des Objektes:}
constructor Init(ID;Owner:interger; NewDesc:string; NewValue:Extended);
function GetValue:extended;
end;

constructor TypeGameBesitz.Init(ID;Owner:interger; NewDesc:string; NewValue:Extended)
begin
TypeID:=ID;
OnerID:=Owner;
Desc:=NewDesc;
Wert1:=NewValue;
end;

function TypeGameBesitz.GetValue:extended;
begin
GetValue:=Wert1;
end;

Eine neue Variable (bei Objekten spricht man von Instanz) legt man dann per New an:

var NewBesitz:^TypeGameBesitz;

NewBesitz:=new(TypeGameBesitz,Init(ID_Militaer, IDPlayerI1, D_DescMilitaer, 1.5));

Wenn man nun Wert1 aus der Waribake lesen will, dann kann man die Funktion nutzen:

var DummyE:extended;

DummyE:=NewBesitz^.GetValue;

So, dass reicht für Heute. ;-)

Ach ja, das Verwenden von abgekieteten Objekten:

Nur ein schnelles Beispiel, indem wir eine Klasse für eine Flotte anlegen:

TypeGameBesitzFlotte:object(TypeGameBesitz)
{Variablen des Objektes:}
TypeGameBesitz{Funktionen des Objektes:}
shipname:string;
constructor Init(ID;Owner:interger; NewDesc:string; NewValue:Extended; NewShipName:string);
end;

Den Construktor muss man entsprechend neu schreiben, er kann aber kann den Contructor der Parent-Klasse aufrufen:

constructor TypeGameBesitzFlotte.Init(...)
begin
{Erst die geerbten Variablen initialisieren:}
inherited Init(usw...);
{dann die eigene:}
shipname:=NewShipname;
end;

Später kann man in dieser Klasse dann auch die Funktionen oder Variablend es Vorgängers erreichen, also kann man GetValue ganz normal nutzen. Was auch eght, ist eine Variable vom tp TypeGameBesitzFlotte anzulegen und diese als Parameter an einen Wert zu übergeben,d er eigentlich vom Typ TypeGameBesitz sein müsste.
-> Die Routinen von TypeGamePlanet laufen also auch, wenn ich dort diese abgeleitete Version übergebe, man muss also9 dort nichts ändern!

Bis dann
Andreas

Hier steht was ueber mein altes Hard- und Softwaregedoens.
bei Antwort benachrichtigen