Entwickler-Ecke
Sonstiges (Delphi) - Gebäudelogik in Strategiespiel
kai_lamers - Mi 08.10.08 12:01
Titel: Gebäudelogik in Strategiespiel
Hallo liebe Leute,
ich bin grad dabei für die Schule ein kleines Strategiespiel in 2d (Iso Darstellung) zu schreiben, Grafikmäßig ist alles soweit erstmal alles kein Problem und läuft, nun wollte ich jedoch, bevor ich anfange die Spiellogik zu implementieren einfach mal nachfragen, ob ihr Schwachpunkte in der Vorgehensweise findet oder wie ihr es machen würdet.
Es geht in diesem Thema erstmal nur um die Gebäude, später werde ich wohl sicherlich auch noch andere Fragen stellen ;)
Also mein grundlegender Gedanke war:
Es gibt eine Klasse TBuilding, die folgende Eigenschaften besitzt:
X,Y : Positionierung auf der Weltkarte
getreide,stein,metall: Variablen für Baukosten
entwicklungsstufe:integer
Eine geerbte Klasse sähe dann etwa so aus
TMuehle = Class (TBuilding)
Es gibt folgende Prozeduren und Eigenschaften:
property ertraggetreide, etraggestein, ertragmetall: Werte, die in Abhängigkeit der Entwicklungsstufe angeben, welche Ressourcen die Mühle erzeugt
property produktionszeit: Anzahl der Zeiteinheiten, bis die Werte (ertraggetreide, ertraggestein,ertragmetall) dem Spielerkonto zugefügt werden.
Prozedur entwickeln: Setzt die Gebäudestufe eins nach oben
Die Klassen sind jetzt nur grob skizziert, genauere Ausarbeitung habe ich noch nicht durchgeführt
Dieser Ansatz wirkt auf mich aber bei näherer Betrachtung ziemlich unklug, da ich das Gefühl habe, dass ich später ziemlich eingeschränkt sein werde.
Wie geht man also in solche einem Fall klugerweise vor?
Danke schonmal,
Kai
jaenicke - Mi 08.10.08 12:23
Grundsätzlich ist das schon eine mE nach gute Vorgehensweise, du müsstest halt schauen, dass du so viel wie möglich "standardisierst" und in die Oberklasse packst, ich habe dann auch teilweise, wenn es um eine Darstellung ging diese wiederum auch gekapselt, so dass die Grundmethoden davon auch in einer Oberklasse als Eigenschaft deiner Oberklasse stehen.
Also so in der Art:
Delphi-Quelltext
1:
| Game.ObjectManager.Object[i].PropertyManager.ShowProperties; |
ShowProperties wäre dann überschrieben durch den passenden PropertyManager und würde im Spiel eine entsprechende Anzeige aufbauen, deren benötigte Größe du wiederum standardisiert abfragen könntest, etc.
Die Frage ist immer, wo sich so etwas lohnt. Wenn du ohnehin auch von der Spiellogik her sehr viel mit den speziellen Gebäuden machst, dann lohnt sich das nicht so sehr, weil du ohnehin nach Typ unterscheiden musst. Wenn aber außer (z.B. regelmäßig angestoßenen) objektinternen Berechnungen der Typ in der Spiellogik keine große Rolle spielt, dann lohnt sich das, weil du dich um den Typ selbst bei der Darstellung und ggf. Einstellung von Parametern nicht um den Typ kümmern musst. Das Eintragen in ein Einstellungsinterface o.ä. könnte wie die Darstellung der Parameter der entsprechende typbezogene PropertyManager übernehmen.
Das würde dann so aussehen, dass du deinem Objektmanager sagst, welchen Typ er erzeugen soll, der tut das, dann wird z.B. eine Mühle erzeugt und diese erstellt sich den passenden PropertyManager dazu und packt den in die geerbte allgemeine Property. Mir hat es Spaß gemacht mit derartigen Konstrukten herumzuspielen und hatte dann performanten aber auch einfach zu ändernden Code. Den Überblick zu behalten ist aber nicht ganz einfach, deshalb musst du aufpassen, dass du deinen Quelltext gut kommentierst, vor allem im Hinblick darauf was wo erzeugt wird und was von anderer Stelle her vorausgesetzt wird. (Eben zum Beispiel,
dass die spezielle Klasse sich auch einen eigenen PropertyManager erstellt, und das bei einem neuen Typ nicht vergessen wird.)
Ob das eine wirklich gute Vorgehensweise ist, kann ich nicht so gut beurteilen, da ich selbst eher durch Ausprobieren denn durch Lehrer gelernt habe. ;-)
Hidden - Mi 08.10.08 14:52
Hi,
- Gibt es denn viele Gebäude, die mehrere Sachen erzeugen? Ich würde davon eine Klasse ableiten, die zwei Eigenschaft hat: Produkt, Menge. Davon überschreibst du dann die Methode zum Erzeugen von Rohstoffen so, dass du beim Ableiten nurnoch den Rohstoff und die Menge angeben musst.
Generell: Wenn du etwas häufige brauchen könntest, ruhig nochmal eine Zwischenstufe machen ;)
- Eine weitere Klasse davon ableiten, die eine Ereignismethode OnProduction hat. Damit ließen sich dann auch Sachen wie eine Werft(da muss ja ein Schiff raus, dann. Also noch etwas passieren) oder im Extremfall ein Kanonenturm(Kugel Abfeuern, bräuchte allerdings eine schnelle "Produktionsfolge" :lol:) realisieren.
Eigentlich bist du mit dem objektorientierten Ansatz schon ganz richtig(hättest du nciht gedacht, was?^^). Es lassen sich ja jederzeit besondere Ereingnisse einbauen. An welcher Stelle vermutest du denn, dass dich der Ansatz blockieren könnte?
mfG,
kai_lamers - Mi 08.10.08 14:53
Hey,
danke schonmal - die Idee mit dem Objekt Manager ist sehr gut, sodass man von einer zentralisierten Klasse Zugriff auf alle Objekte hat - das werde ich auf jeden Fall implementieren! :)
Danke schonmal
"Viele Gebäude" ist natürlich relativ. Ich wollte die typischen Anlagen übernehmen: Wohnhaus, Mühle-->Feld, Werft, Kaserne, Waffenschmiede, Steinbruch, Metallabbaustätte, Kirche, Hafen, Markt,Wall,Kanonenturm,Tor... Ich denke grob waren das alle.
Aber grob muss es erstmal mit einem Gebäude logisch richtig funktionieren, weitere zu implementieren sollte kein Problem darstellen, wenn die Mutterklasse entsprechend ordentlich gestaltet ist.
An welcher Stelle genau dieser Ansatz für mich etwas zu "simpel" scheint, kann ich gar nicht sagen.
Es war eben der erste Ansatz und ich weiß erfahrungsgemäß von mir, dass mein erster Ansatz im Bereich der OOP IMMER grundsätzliche Fehler enthält, das ist quasi ein Naturgesetz *g*
EDIT:
Hier ist dann mal die erste Version meiner Klassen, ist nicht ganz so, wie oben beschrieben, aber auf mich macht das jetzt erstmal einen relativ guten Eindruck, getestet ist das ganze noch nicht. Habs grad eben erstmal runtergetippt.
Praktisch an dieser Vorgehensweise ist es, dass man absolut flexibel bleibt bezüglich der Gebäude bleibt, da alle Gebäude über eine externe (noch unverschlüsselte) Textdatei eingelesen werden :)
Neues Gebäude = Neue Zeile in Datei, schon ist das Gebäude verfügbar.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195:
| unit Uobject;
interface
Uses SysUtils,Classes;
type TSTringdynarray = array of String;
type Tpropertylist=Record name:string; building_id:integer; tile_id:integer; need_oat:integer; need_stone:integer; need_metal:integer; produce_oat:integer; produce_stone:integer; produce_metal:integer; produce_oat_time:integer; produce_stone_time:integer; produce_metal_time:integer; end;
type TPropertymanager=Class(Tobject) private props:Tpropertylist;
public constructor create(building_file:string;building_typ:integer); property properties:Tpropertylist read props; end;
TBuilding=Class(Tobject) private prope_manager:Tpropertymanager; xcoord:integer; ycoord:integer; b_typ:integer; b_level:integer; b_status:integer; procedure setx(x:integer); procedure sety(y:integer); procedure settyp(typ:integer); procedure setlevel(level:integer); procedure setstatus(status:integer); public constructor create(building_typ:integer); property x:integer read xcoord write setx; property y:integer read ycoord write sety; property typ:integer read b_typ write settyp; property level:integer read b_level write setlevel; property status:integer read b_status write setstatus; property prop_manager:Tpropertymanager read prope_manager; procedure develop; end;
TObjectmanager=Class(TObject) private object_id:integer; object_array:array[0..2500] of Tbuilding; protected function getbuilding(Index: Integer): Tbuilding; public constructor create; function build(typ:integer;x,y:integer;stufe:integer):integer; property objects[Index: Integer]: Tbuilding read getbuilding ; default; end;
implementation
function Explode(const Separator, S: string; Limit: Integer = 0): TStringDynArray; var SepLen: Integer; F, P: PChar; ALen, Index: Integer; begin SetLength(Result, 0); if (S = '') or (Limit < 0) then Exit; if Separator = '' then begin SetLength(Result, 1); Result[0] := S; Exit; end; SepLen := Length(Separator); ALen := Limit; SetLength(Result, ALen);
Index := 0; P := PChar(S); while P^ <> #0 do begin F := P; P := AnsiStrPos(P, PChar(Separator)); if (P = nil) or ((Limit > 0) and (Index = Limit - 1)) then P := StrEnd(F); if Index >= ALen then begin Inc(ALen, 5); SetLength(Result, ALen); end; SetString(Result[Index], F, P - F); Inc(Index); if P^ <> #0 then Inc(P, SepLen); end; if Index < ALen then SetLength(Result, Index); end;
constructor Tpropertymanager.create(building_file:string;building_typ:integer); var b_file:textfile; var line:string; var res:TSTringdynarray; begin AssignFile(b_file,building_file); Reset(b_file); while not eof (b_file) do begin readln(b_file,line); res:=Explode(',',line,0); props.name:=res[0]; props.building_id:=strtoint(res[1]); props.tile_id:=strtoint(res[2]); props.need_oat:=strtoint(res[3]); props.need_stone:=strtoint(res[4]); props.need_metal:=strtoint(res[5]); props.produce_oat:=strtoint(res[6]); props.produce_stone:=strtoint(res[7]); props.produce_metal:=strtoint(res[8]); props.produce_oat_time:=strtoint(res[9]); props.produce_stone_time:=strtoint(res[10]); props.produce_metal_time:=strtoint(res[11]); if building_typ=props.building_id then break; end; end;
constructor Tbuilding.create(building_typ:integer); begin inherited create; prope_manager:=Tpropertymanager.create('building.txt',building_typ); end;
function Tobjectmanager.getbuilding(Index: Integer): Tbuilding; begin Result := object_array[Index]; end;
procedure Tbuilding.develop(); begin inc(b_level); end;
procedure Tbuilding.setx(x:integer); begin xcoord:=x; end;
procedure Tbuilding.sety(y:integer); begin ycoord:=y; end;
procedure Tbuilding.settyp(typ:integer); begin b_typ:=typ; end;
procedure Tbuilding.setlevel(level:integer); begin b_level:=level; end;
procedure Tbuilding.setstatus(status:integer); begin b_status:=status; end;
constructor Tobjectmanager.create(); begin object_id:=0; end;
function Tobjectmanager.build(typ:integer;x,y:integer;stufe:integer):integer; begin object_array[object_id]:=TBuilding.create(typ); object_array[object_id].typ:=typ; object_array[object_id].x:=x; object_array[object_id].y:=y; object_array[object_id].level:=stufe; result:=object_id; inc(object_id); end;
end. |
Building.txt:
Quelltext
1: 2:
| Muehle,1,16,10,10,10,5,0,0,20,0,0 Bauernhaus,2,17,20,15,10,0,0,0,0,0,0 |
EDIT 2:
Ich glaube es ja kaum, aber die oben abgebildeten Klassen tun tatsächlich alles so, wie ich es mir gewünscht habe und das ziemlich auf Anhieb :)
Wenn ihr mir jetzt noch sagt, dass ihr den obigen Ansatz auch noch als sinnvoll erachtet, dann bin ich froh und sehe mein Grundgerüst als geebnet an!
Ich bekam grad eine PN, ob ich zwischendurch mal einen Zwischenstand hochladen kann:
Tu ich gerne und mache ich auch. Es wird zwar kein Age of Empires, aber ein niedliches kleines Spielchen wirds schon werden, ist halt für die Schule :)
ANBEI DIE ERSTE VERSION ONLINE:
Bisher kann man nur Mühlen bauen, ich weiß noch nicht, wie ich das Gamehandling an sich gestalten werde, es ist aber ja auch erstmal nur eine Testversion. Sämtliche Klasse sind bereits implementiert und funktionieren, überzeugt euch selbst.
Die Building.txt muss im gleichen Ordner wie das Programm an sich sein.
Lg,
Kai
kai_lamers - Do 09.10.08 12:19
Hey,
heute geht es dann weiter. Nachdem ich die Gebäudelogik nun implementiert habe, bin ich grad noch recht unschlüssig, womit ich am besten weiter mache.
Wo würdet ihr weitergehend ansetzen?
Danke und lieben Gruß,
Kai
elundril - Do 09.10.08 12:31
in der einheitenproduktion würd ich weitermachen, falls es sowas gibt. aber bis jetzt hast du nur geschrieben da es ein strategiespeil sein soll, nicht was für eins! ein friedliches a la Siedler oder ein kriegerisches a la Cossacks.
kai_lamers - Do 09.10.08 12:50
Stimmt, du hast Recht - das sollte ich auf jeden Fall noch ergänzen.
Erstmal soll es nur ein friedliches Strategiespiel werden, welches noch ohne Gegner und Kriege auskommt, einfach - weil ich mich vor der Entwicklung einer entsprechenden KI fürchte.
Allerdings möchte ich das ganze so offen halten, dass ich im Nachhinein immer noch Gegnerklassen ein bauen kann.
Ich habe mich gerade an die Entwicklung der Gamehandling Klasse gemacht, denn ohne die kann ich noch so viel programmieren, wenn ich es nicht anwählen kann, ist's doof.
Beispiel das Ressourcenfeld (grad noch in Entwicklung):
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44:
| TRessourcewindow=Class(TObject) private b_posx:integer; b_posy:integer; b_width:integer; b_height:integer; b_visible:Boolean; protected procedure setvisible(vis:Boolean); public procedure draw(canvas:TDirectDrawSurfaceCanvas); constructor create(x,y,width,height:integer;visible:boolean); property visible:Boolean read b_visible write setvisible; procedure setpos(posx,posy:integer); end;
constructor TRessourcewindow.create(x:integer;y:integer;width:integer;height:integer;visible:boolean); begin b_posx:=x; b_posy:=y; b_width:=width; b_height:=height; b_visible:=visible; end;
procedure TRessourcewindow.setpos(posx:Integer;posy:integer); begin b_posx:=posx; b_posy:=posy; end;
procedure TRessourcewindow.draw(canvas:TDirectDrawSurfaceCanvas); begin if b_visible then begin canvas.Brush.Color:=clred; canvas.Rectangle(b_posx,b_posy,b_posx+b_width,b_posy+b_height); canvas.release; end; end;
procedure TRessourcewindow.setvisible(vis:Boolean); begin b_visible:=vis; end; |
Lg,
Kai
jaenicke - Do 09.10.08 12:51
Du hast beim Zugriff auf die building.txt vergessen den Pfad hinzuzufügen (ExtractFilePath(ParamStr(0)) + 'building.txt'). Als ich zuerst aus dem Browser direkt gestartet habe (der Download ging ja in den selben Ordner) kam beim Klick die Meldung "Datei nicht gefunden". Deshalb musste ich es aus dem Windows Explorer starten, wo dann das Arbeitsverzeichnis zufälligerweise dem Anwendungsverzeichnis entspricht. ;-)
http://www.delphi-library.de/viewtopic.php?p=499701
Ja, du musst dir dann überlegen was im Spiel passieren soll, und dementsprechend weitermachen. Die bereits benannte Einheitenproduktion ist eine Möglichkeit, du kannst auch erstmal allgemein schauen wie denn eigentlich mit Produkten umgegangen wird. Irgendwie musst du ja in Zyklen die Produktion bei allen Gebäuden "abholen" und in deine Gesamtressourcen einbinden, etc.
Hidden - Do 09.10.08 13:03
Hi,
Das oben könntest du noch etwas kompakter machen, indem du Einen Unterrecord TRecources definierst, der oat, stone, metal: Integer enthält. Der andere Record vereinfacht sich dann zu Produce, Need, Time: TRecources.
Damit wird das ganze nicht nur schneller zu Tippen(du wirst diese Dreierrecourcen sicher noch etliche Male verwenden, also kannst du es auch gleich zusammenfassen). Der Hauptgrund ist, dass du und andere schneller durch den Quelltext finden, wenn er übersichtlicher und kürzer wird.
@Elundriel: Stimme ich zu. Als erstes mal die Hauptprocedure, in der das Spiel läuft(und sei es nun in einem Timer oder in eir Schleife). Damit auch wahrscheinlich eine Unterprocedure(schön viele davon, damit's übersichtlich wird ;)) mit "for Buildings do Produce;" oder in der Art.
Wenn du die oberen Prozeduren in schön viele Unterprozeduren unterteilst, kommst du schonmal schneller voran: Du umschreibst den Programmablauf, ohne dich mit Details aufzuhalten. Außerdem ist alles für jemanden, der sich einliest, wie Pseudocode lesbar :D
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32:
| procedure TGameForm.GameStepTimer(Sender: TObject); begin Game.Tick; end;
procedure TGame.Tick; begin CalcRecources; CalcDamage; InformPlayer; end;
procedure TGame.CalcRecources; var i: Integer; begin for i := 0 to Length(Buildings) - 1 do Building[i].CalcRecources(Player.Recources); end;
procedure TBuilding.CalcRecources(aPlayerRecources: TRecources); begin DecRec(self.ProduceTime, 1); if BiggerThan(aPlayerRecources, self.Need) then IncRec(aPlayerRecources, self.Produce, self.Need); end;
function BiggerThan(A, B: TRecources): Boolean; begin result := (A.Oat >= B.Oat) and (A.Stone >= B.Stone) and (A.Metal >= B.Metal); end; |
mfG,
kai_lamers - Do 09.10.08 13:19
Hey,
danke die Sache mit dem Dateipfad ist korrigiert, die Idee zum neuen Record finde ich super, danke! Auch schon eingefügt und ich werde jetzt mal eine entsprechende Hauptroutine fertigen, das scheint mir auch sinnvoll.
Echt vielen Dank für Eure Anregungen, mit solchen Ideen von anderen macht es das ganze viel realisierbarer :)
Liebe Grüße,
Kai
kai_lamers - Do 09.10.08 19:00
Hey,
wow - ich freu mir hier grad ein Ast ab - weswegen: Meine Gebäude können nun endlich produzieren, es ist echt erstaunlich, wie man sich über so eine doofe Änderung von Zahlen freuen kann :)
Aber ich kann inzwischen auch jedem nur solch einen Objektorientieren Ansatz empfehlen. Es ist zwar eine Menge Mehrarbeit bis zum ersten sichtbaren Erfolg, doch wenn man dann einmal soweit ist, dass das Grundgerüst steht, dann funktioniert auch alles.
Anbei meine aktuelle Klassenunit:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453: 454: 455: 456: 457: 458: 459: 460: 461: 462: 463: 464: 465: 466: 467: 468: 469: 470: 471: 472: 473: 474: 475: 476: 477: 478: 479: 480: 481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491: 492: 493: 494: 495: 496: 497: 498: 499: 500: 501: 502: 503: 504: 505: 506: 507: 508: 509: 510: 511: 512: 513: 514: 515: 516: 517: 518: 519: 520: 521: 522: 523: 524: 525: 526: 527:
| unit Uobject;
interface
Uses SysUtils,Classes,Graphics,DXDraws;
type TSTringdynarray = array of String;
type
Tressources=Class(TObject) private b_oat:integer; b_stone:integer; b_metal:integer; procedure setoat(o:integer); procedure setstone(s:integer); procedure setmetal(m:integer); public property oat:integer read b_oat write setoat; property stone:integer read b_stone write setstone; property metal:integer read b_metal write setmetal; end;
Tpropertylist=Class(TObject) private b_name:string; b_building_id:integer; b_tile_id:integer; b_need:Tressources; b_produce:Tressources; b_produce_time:TRessources; b_make_inhabitants:integer; b_max_level:integer; b_life_points:integer; b_time:Tressources; procedure setname(n:string); procedure setbuilding_id(b:integer); procedure settile_id(ti:integer); procedure setneed(ne:Tressources); procedure setproduce(pro:Tressources); procedure setproduce_time(prot:Tressources); procedure setmake_inhabitants(mi:integer); procedure setmax_level(ml:integer); procedure setlife_points(lp:integer); procedure settime(t:Tressources); public constructor create; property name:string read b_name write setname; property building_id:integer read b_building_id write setbuilding_id; property tile_id:integer read b_tile_id write settile_id; property need:Tressources read b_need write setneed; property produce:Tressources read b_produce write setproduce; property produce_time:TRessources read b_produce_time write setproduce_time; property make_inhabitants:integer read b_make_inhabitants write setmake_inhabitants; property max_level:integer read b_max_level write setmax_level; property life_points:integer read b_life_points write setlife_points; property time:Tressources read b_time write settime; end;
Tspieler=Class(TObject) private b_res:Tressources; b_inhabitants:integer; b_century:integer; procedure setressources(res:Tressources); procedure setinhabitants(inhab:integer); procedure setcentury(centu:integer); public constructor create(oat,stone,metal,inhabitants,century:integer); property ressources:Tressources read b_res write setressources; property inhabitants:integer read b_inhabitants write setinhabitants; property century:integer read b_century write setcentury; end;
TMessagewindow=Class(TObject) private b_posx:integer; b_posy:integer; b_width:integer; b_height:integer; b_visible:Boolean; b_text:string; protected procedure setvisible(vis:Boolean); procedure settext(tex:string); public procedure draw(canvas:TDirectDrawSurfaceCanvas); constructor create(x,y,width,height:integer;visible:boolean); property visible:Boolean read b_visible write setvisible; procedure setpos(posx,posy:integer); property text:string read b_text write settext; end;
TPropertymanager=Class(Tobject) private props:Tpropertylist; procedure setprops(prop:Tpropertylist); public constructor create(building_file:string;building_typ:integer); property properties:Tpropertylist read props write setprops; end;
TBuilding=Class(Tobject) private prope_manager:Tpropertymanager; xcoord:integer; ycoord:integer; b_typ:integer; b_level:integer; b_status:integer; procedure setx(x:integer); procedure sety(y:integer); procedure settyp(typ:integer); procedure setlevel(level:integer); procedure setstatus(status:integer); procedure setpropmanager(propmanager:Tpropertymanager); public constructor create(building_typ:integer); property x:integer read xcoord write setx; property y:integer read ycoord write sety; property typ:integer read b_typ write settyp; property level:integer read b_level write setlevel; property status:integer read b_status write setstatus; property prop_manager:Tpropertymanager read prope_manager write setpropmanager; procedure develop; end;
TObjectmanager=Class(TObject) private object_id:integer; object_array:array[0..2500] of Tbuilding; protected function getbuilding(Index: Integer): Tbuilding; procedure putbuilding(Index: Integer; build:Tbuilding); public constructor create; function build(typ:integer;x,y:integer;stufe:integer):integer; function search(x,y:integer):integer; property objects[Index: Integer]: Tbuilding read getbuilding write putbuilding; default; property max_id:integer read object_id; end;
TGame=Class(TObject) private b_objectmanager:Tobjectmanager; b_reswindow:TMessagewindow; b_eventwindow:TMessagewindow; b_spieler:Tspieler; procedure inctime(res:Tressources); procedure setobjectmanager(om:Tobjectmanager); public constructor create(); procedure calcressources; procedure tick; procedure informplayer; property Objectmanager : TObjectmanager read b_objectmanager write setobjectmanager; property reswindow : TMessagewindow read b_reswindow; property eventwindow : TMessageWindow read b_eventwindow; property spieler : TSpieler read b_spieler; end;
implementation
function Explode(const Separator, S: string; Limit: Integer = 0): TStringDynArray; var SepLen: Integer; F, P: PChar; ALen, Index: Integer; begin SetLength(Result, 0); if (S = '') or (Limit < 0) then Exit; if Separator = '' then begin SetLength(Result, 1); Result[0] := S; Exit; end; SepLen := Length(Separator); ALen := Limit; SetLength(Result, ALen);
Index := 0; P := PChar(S); while P^ <> #0 do begin F := P; P := AnsiStrPos(P, PChar(Separator)); if (P = nil) or ((Limit > 0) and (Index = Limit - 1)) then P := StrEnd(F); if Index >= ALen then begin Inc(ALen, 5); SetLength(Result, ALen); end; SetString(Result[Index], F, P - F); Inc(Index); if P^ <> #0 then Inc(P, SepLen); end; if Index < ALen then SetLength(Result, Index); end;
procedure Tressources.setoat(o:integer); begin b_oat:=o; end;
procedure Tressources.setstone(s:integer); begin b_stone:=s; end;
procedure Tressources.setmetal(m:integer); begin b_metal:=m; end;
constructor Tpropertylist.create(); begin b_need:=Tressources.create; b_produce:=Tressources.create; b_produce_time:=Tressources.create; b_time:=Tressources.create; end;
procedure Tpropertylist.setname(n:string); begin b_name:=n; end;
procedure Tpropertylist.setbuilding_id(b:integer); begin b_building_id:=b; end;
procedure Tpropertylist.settile_id(ti:integer); begin b_tile_id:=ti; end;
procedure Tpropertylist.setneed(ne:Tressources); begin b_need:=ne; end;
procedure Tpropertylist.setproduce(pro:Tressources); begin b_produce:=pro; end;
procedure Tpropertylist.setproduce_time(prot:Tressources); begin b_produce_time:=prot; end;
procedure Tpropertylist.setmake_inhabitants(mi:integer); begin b_make_inhabitants:=mi; end;
procedure Tpropertylist.setmax_level(ml:integer); begin b_max_level:=ml; end;
procedure Tpropertylist.setlife_points(lp:integer); begin b_life_points:=lp; end;
procedure Tpropertylist.settime(t:Tressources); begin b_time:=t; end;
constructor Tspieler.create(oat,stone,metal,inhabitants,century:integer); begin b_res:=Tressources.Create; b_res.oat:=oat; b_res.stone:=stone; b_res.metal:=metal; b_inhabitants:=inhabitants; b_century:=century; end;
procedure Tspieler.setressources(res:Tressources); begin b_res:=res; end;
procedure Tspieler.setinhabitants(inhab:integer); begin b_inhabitants:=inhab; end;
procedure Tspieler.setcentury(centu:integer); begin b_century:=centu; end;
constructor TMessagewindow.create(x:integer;y:integer;width:integer;height:integer;visible:boolean); begin b_posx:=x; b_posy:=y; b_width:=width; b_height:=height; b_visible:=visible; end;
procedure TMessagewindow.setpos(posx:Integer;posy:integer); begin b_posx:=posx; b_posy:=posy; end;
procedure TMessagewindow.draw(canvas:TDirectDrawSurfaceCanvas); begin if b_visible then begin canvas.Brush.Color:=clred; canvas.Font.Color:=clblack; canvas.Rectangle(b_posx,b_posy,b_posx+b_width,b_posy+b_height); canvas.TextOut(b_posx+1,b_posy+1,b_text); canvas.release; end; end;
procedure TMessagewindow.setvisible(vis:Boolean); begin b_visible:=vis; end;
procedure TMessagewindow.settext(tex:string); begin b_text:=tex; end;
constructor Tpropertymanager.create(building_file:string;building_typ:integer); var b_file:textfile; var line:string; var res:TSTringdynarray; begin props:=Tpropertylist.Create; AssignFile(b_file,ExtractFilePath(ParamStr(0)) + building_file); Reset(b_file); while not eof (b_file) do begin readln(b_file,line); res:=Explode(',',line,0); props.name:=res[0]; props.building_id:=strtoint(res[1]); props.tile_id:=strtoint(res[2]); props.need.oat:=strtoint(res[3]); props.need.stone:=strtoint(res[4]); props.need.metal:=strtoint(res[5]); props.produce.oat:=strtoint(res[6]); props.produce.stone:=strtoint(res[7]); props.produce.metal:=strtoint(res[8]); props.produce_time.oat:=strtoint(res[9]); props.produce_time.stone:=strtoint(res[10]); props.produce_time.metal:=strtoint(res[11]); props.make_inhabitants:=strtoint(res[12]); props.max_level:=strtoint(res[13]); props.life_points:=strtoint(res[14]); if building_typ=props.building_id then break; end; end;
procedure Tpropertymanager.setprops(prop:Tpropertylist); begin props:=prop; end;
constructor Tbuilding.create(building_typ:integer); begin inherited create; prope_manager:=Tpropertymanager.create('building.txt',building_typ); end;
procedure Tbuilding.setpropmanager(propmanager:Tpropertymanager); begin prope_manager:=propmanager; end;
procedure Tbuilding.develop(); begin inc(b_level); end;
procedure Tbuilding.setx(x:integer); begin xcoord:=x; end;
procedure Tbuilding.sety(y:integer); begin ycoord:=y; end;
procedure Tbuilding.settyp(typ:integer); begin b_typ:=typ; end;
procedure Tbuilding.setlevel(level:integer); begin b_level:=level; end;
procedure Tbuilding.setstatus(status:integer); begin b_status:=status; end;
constructor Tobjectmanager.create(); begin object_id:=0; end;
function Tobjectmanager.search(x:integer;y:integer):integer; var i:integer; begin if object_id>0 then begin for i:=0 to object_id-1 do begin if (object_array[i].x=x) and (object_array[i].y=y) then begin result:=i; break; end; result:=-1; end; end else result:=-1; end;
function Tobjectmanager.getbuilding(Index: Integer): Tbuilding; begin result:=nil; if object_id > 0 then Result := object_array[Index]; end;
procedure Tobjectmanager.putbuilding(Index: Integer; build:Tbuilding); begin if object_id > 0 then object_array[Index] := build; end;
function Tobjectmanager.build(typ:integer;x,y:integer;stufe:integer):integer; begin object_array[object_id]:=TBuilding.create(typ); object_array[object_id].typ:=typ; object_array[object_id].x:=x; object_array[object_id].y:=y; object_array[object_id].level:=stufe; result:=object_id; inc(object_id); end;
constructor Tgame.create; begin b_objectmanager:=Tobjectmanager.create; b_reswindow:=TMessagewindow.create(0,0,250,15,true); b_eventwindow:=TMessagewindow.create(0,500,768,150,true); b_spieler:=Tspieler.create(100,100,100,10,1); b_reswindow.text:=' Getreide: '+inttostr(b_spieler.ressources.oat)+' Stein: '+inttostr(b_spieler.ressources.stone)+' Metall: '+inttostr(b_spieler.ressources.metal);end;
procedure Tgame.setobjectmanager(om:Tobjectmanager); begin b_objectmanager:=om; end;
procedure Tgame.tick; begin calcressources; b_reswindow.text:=' Getreide: '+inttostr(b_spieler.ressources.oat)+' Stein: '+inttostr(b_spieler.ressources.stone)+' Metall: '+inttostr(b_spieler.ressources.metal); informplayer; end;
procedure Tgame.calcressources; var i,x:integer; begin for i:=0 to b_objectmanager.max_id-1 do begin inctime(b_objectmanager.objects[i].prop_manager.properties.time); if b_objectmanager.objects[i].prop_manager.properties.time.oat>=b_objectmanager.objects[i].prop_manager.properties.produce_time.oat then begin b_spieler.ressources.oat:=b_spieler.ressources.oat+b_objectmanager.objects[i].prop_manager.properties.produce.oat; b_objectmanager.objects[i].prop_manager.properties.time.oat:=0; end; if b_objectmanager.objects[i].prop_manager.properties.time.stone>=b_objectmanager.objects[i].prop_manager.properties.produce_time.stone then begin b_spieler.ressources.stone:=b_spieler.ressources.stone+b_objectmanager.objects[i].prop_manager.properties.produce.stone; b_objectmanager.objects[i].prop_manager.properties.time.stone:=0; end; if b_objectmanager.objects[i].prop_manager.properties.time.metal>=b_objectmanager.objects[i].prop_manager.properties.produce_time.metal then begin b_spieler.ressources.metal:=b_spieler.ressources.metal+b_objectmanager.objects[i].prop_manager.properties.produce.metal; b_objectmanager.objects[i].prop_manager.properties.time.metal:=0; end; end; end;
procedure Tgame.inctime(res:Tressources); begin res.oat:=res.oat+1; res.stone:=res.stone+1; res.metal:=res.metal+1; end;
procedure Tgame.informplayer; begin end;
end. |
Ich habe deinen Vorschlag, hidden, ziemlich genau so umgesetzt.
So, nun ist erstmal 'ne kleine Pause angesagt, heute kann ich mich nicht mehr konzentrieren.
Anbei wieder die aktuelle Engine.
DIE OBEN ZU DOWNLOADENDE BUILDING.TXT MUSS WIEDER DABEI SEIN!
Lg,
Kai
elundril - Do 09.10.08 19:03
schaut schon mal nicht schlecht aus! jedoch sollte die steuerung dann irgendwann noch angepasst werden.
kai_lamers - Do 09.10.08 19:16
Der Steuerung wollte ich mich als nächstes widmen, denn die tollsten Features bringen nix, wenn man sie durch die bisher nicht ausreichende Steuerung hervorrufen kann.
Das kommt dann morgen - noch sind ja Ferien.
Lg,
Kai
Hidden - Do 09.10.08 19:49
Hi,
kai_lamers hat folgendes geschrieben : |
| Ich habe deinen Vorschlag, hidden, ziemlich genau so umgesetzt. |
Freut mich, wenn ich helfen konnte :)
| Zitat: |
| object_array:array[0..2500] of Tbuilding; |
Es gibt übrigens auch dynamisch Arrays. Das sind dann im Speicher zwar keine richtigen Arrays mehr, aber du kannst nach wie vor so mit ihnen arbeiten, als wären es welche:
Delphi-Quelltext
1: 2: 3: 4:
| ObjectArray: Array of TBuilding; SetLength(ObjectArray, 5); Length(ObjectArray); |
Was mir noch auffällt: Du müsstest Objekte, die du selbst erzeugst auch wieder freigeben, sobald du sie nichtmehr brauchst. Das geschieht über den Aufruf von "Free;". Wenn bei der Freigabe eines Objektes noch mehr freigegeben werden soll(dein TPropertyList-Objekt besitzt ja seinerseits Objekte, die freigegeben werden müssen), musst du einen "destructor"(analog zum constructor) daklarieren, dieser heißt im Normalfall "Destroy".
Free; macht dabei nichts anderes als "if self <> nil then Destroy;". Sprich: Wenn das Objekt nicht mehr(noch nicht) existiert, bekommst du keine Zugriffsverletzung.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32:
| constructor TPropertylist.Create(); begin b_need := TRessources.create; b_produce := TRessources.create; b_produce_time := TRessources.create; b_time := TRessources.create; end;
destructor TPropertylist.Destroy(); begin b_need.Free; b_produce.Free; b_produce_time.Free; b_time.Free; end;
procedure TGameForm.OnFormDestroy(Sender: TObject); begin b_Game.Free; end;
procedure TObject.Free; begin if Assigned(self) then self.Destroy; end;
function Assigned(X: TObject): Boolean; begin result := X <> nil; end; |
mfG,
kai_lamers - Do 09.10.08 20:32
Ja,
du hast natürlich Recht, habe ich gar nicht dran gedacht.
Schon geändert.
Kai
wurstuk - Fr 10.10.08 14:41
Titel: <(^_^)>
Hi
ähm ich check i-wie nicht wie diss geht das mann das Spiel spielen kann^^
ich habe mir erst die textdatei und dann die .exe runtegeladen (beide auf desktop) und dann in einen ordner gemacht aber dann kommt immer eine fehler meldung:
"DDraw.dll is not loaded"
dann hab ich mir nochmal dieses pgame runtergeladen und es damit probiert, es kam aber
der selbe Fehler...
kann mir i-einer sagen warum die nicht geht?
vllt liegts an dem PC, is nehmlich der von meinem Vater und der hat windows NT....
lg
wurstuk - Fr 10.10.08 14:50
ahhh an meinem Pc gehts^^
hmmm bei mir ist es i-wie sehr dunkel kann aber auch an meinem Bildschirm liegen da is immer alles dunkel^^
wenn ich auf eine Mühle drücke zeigt er mir Name usw an aber kann mann jetzt schon i-was selber bauen oder kann mann das i-wann überhaupt?
und die Steuerung ist noch ein bisschen komisch^^
aber sonst eig. ganz coool^^
wie lange machst du schon Delphi?
jaenicke - Fr 10.10.08 14:50
wurstuk hat folgendes geschrieben : |
| "DDraw.dll is not loaded" |
Nun ja, hast du denn DirectX auf dem PC überhaupt installiert? Wenn es
wirklich Windows NT (nicht 2000 oder XP) ist, dann vermute ich mal, dass das nicht der Fall ist. Mehr als DirectX 6 wird AFAIK auch gar nicht für Windows NT unterstützt.
Hidden - Fr 10.10.08 15:03
PS: Die neuste Version sollte immer im Erstpost liegen. Mach doch .exe und .txt in ein zip-Archiv, dann brauchst du nur einen Download ;)
PPS: Ja, dunkel ist es sehr ;) Und sag mal was hast du mit dem Programm gemacht? Das Standard-Taskleisten-Menü scheint deaktiviert zu sein und das Programm zwingt mich, es im Fullscreen-Modus auszuführen(so etwas würde ich ja gerne auswählen) :(
kai_lamers - Fr 10.10.08 15:15
Hey,
ich werde es gleich zu einem Zip zusammenfassen und oben hineinladen.
Hidden hat folgendes geschrieben : |
PPS: Ja, dunkel ist es sehr ;) Und sag mal was hast du mit dem Programm gemacht? Das Standard-Taskleisten-Menü scheint deaktiviert zu sein und das Programm zwingt mich, es im Fullscreen-Modus auszuführen(so etwas würde ich ja gerne auswählen) :( |
Die Grafiken sind grad eh noch Übergangsmaterial. Hm, also an der eigentlichen Programmausgabe (also auch Fullscreen Einstellungen etc. habe ich seit der ersten Version nichts verändert.
Aber auch das lässt sich noch ändern, nachher wenn ich meinen heutigen Teil anfange, ist eh erstmal die Steuerung dran.
Ich arbeite schon seit etwa 3 Jahren mit Delphi, allerdings diesmal erstmal im Bereich der Spieleprogrammierung.
Lg,
Kai
Hidden - Fr 10.10.08 19:11
Hi,
Zu deinem Scrolling: Normalerweise wird ja nur gescrollt, wenn der Cursor in die Randbereiche des Bildschirms kommt. Ich habe mir es mal objektiv angesehen.
Hat auch Vorteile. Aber: Beim Fokussieren eines bestimmten Bildschirmbereiches und gleichzeitigen Klicken auf ein Gebäude behindert es kolossal(angenommen du willst nicht einfach auf eine Stelle klicken, sondern z.B. fünf Gebäude gleichzeitig im Blickfeld haben. Und dann eben diese fünf sehen und relativ dazu ein sechstes platzieren).
Könntest du das Scrolling abschalten, während z.B. die Strg-Taste oder die rechte Maustaste gedrückt ist? Dann ginge beides :)
mfG,
kai_lamers - Fr 10.10.08 22:13
Hey,
Wunsch ist erfüllt und halte ich auch für sinnvoll. Durch Druck auf die STRG Taste wird das Scrollen für entsprechende Zeit deaktiviert - erhöht das Gameplay schon ziemlich drastisch.
Heute bin ich leider nicht in dem Maße zur Spielsteuerung gekommen, wie ich es eigentlich wollte, da ich mich vorher erstmal mit der Bildschirmausgabe von Nachrichten für den Benutzer herumquälen musste. Funktioniert nun eigentlich, aber irgendwie gibt's noch ein Zugriffsfehler, der nur dann passiert, wenn man ganz häufig hintereinander (momentan natürlich nur) Mühlen baut. Woran das liegt weiß ich noch nicht, habe aber auch heute keinen Nerv mehr das rauszufinden.
Morgen gibt's erst wieder Abends was von mir zu hören, da ich tagsüber unterwegs bin. Für morgen habe ich mir jetzt die Behebung des Bugs + Steuerung vorgenommen.
Ich weiß zwar noch nicht, wie genau ich meiner TMessageWindow Klasse eine entsprechende Klickprozedur implementieren kann (und eventuell auch noch eine Button Klasse), damit man ab morgen auch mal mehr als nur Mühlen bauen kann.
Bisher ist also Fertig gestellt:
* Gebäudeimplementierung
* Ressourcenneuberechnung nach Spielzyklus
* Statusmessageausgabe
* Grafikausgabe (nur die entsprechenden Tiles muss ich noch modellieren (Ich modelliere die Tiles in c4d mit isometrischer Ansicht und skaliere sie dann auf entsprechende 64*32px herunter))
Die aktuelle Version gibt's im ersten Beitrag.
Anbei wieder mal meine Uobject.pas:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453: 454: 455: 456: 457: 458: 459: 460: 461: 462: 463: 464: 465: 466: 467: 468: 469: 470: 471: 472: 473: 474: 475: 476: 477: 478: 479: 480: 481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491: 492: 493: 494: 495: 496: 497: 498: 499: 500: 501: 502: 503: 504: 505: 506: 507: 508: 509: 510: 511: 512: 513: 514: 515: 516: 517: 518: 519: 520: 521: 522: 523: 524: 525: 526: 527: 528: 529: 530: 531: 532: 533: 534: 535: 536: 537: 538: 539: 540: 541: 542: 543: 544: 545: 546: 547: 548: 549: 550: 551: 552: 553: 554: 555: 556: 557: 558: 559: 560: 561: 562: 563: 564: 565: 566: 567: 568: 569: 570: 571: 572: 573: 574: 575: 576: 577: 578: 579: 580: 581: 582: 583: 584: 585: 586: 587: 588: 589: 590: 591: 592: 593: 594: 595: 596: 597: 598: 599: 600: 601: 602: 603: 604: 605: 606: 607: 608: 609: 610: 611: 612: 613: 614: 615: 616: 617: 618: 619: 620: 621: 622: 623: 624: 625: 626: 627: 628: 629: 630: 631: 632: 633: 634: 635: 636: 637: 638: 639: 640: 641:
| unit Uobject;
interface
Uses SysUtils,Classes,Graphics,DXDraws;
type TSTringdynarray = array of String;
type
Tressources=Class(TObject) private b_oat:integer; b_stone:integer; b_metal:integer; procedure setoat(o:integer); procedure setstone(s:integer); procedure setmetal(m:integer); public property oat:integer read b_oat write setoat; property stone:integer read b_stone write setstone; property metal:integer read b_metal write setmetal; end;
Tpropertylist=Class(TObject) private b_name:string; b_building_id:integer; b_tile_id:integer; b_need:Tressources; b_produce:Tressources; b_produce_time:TRessources; b_make_inhabitants:integer; b_max_level:integer; b_life_points:integer; b_time:Tressources; procedure setname(n:string); procedure setbuilding_id(b:integer); procedure settile_id(ti:integer); procedure setneed(ne:Tressources); procedure setproduce(pro:Tressources); procedure setproduce_time(prot:Tressources); procedure setmake_inhabitants(mi:integer); procedure setmax_level(ml:integer); procedure setlife_points(lp:integer); procedure settime(t:Tressources); public constructor create; destructor destroy; property name:string read b_name write setname; property building_id:integer read b_building_id write setbuilding_id; property tile_id:integer read b_tile_id write settile_id; property need:Tressources read b_need write setneed; property produce:Tressources read b_produce write setproduce; property produce_time:TRessources read b_produce_time write setproduce_time; property make_inhabitants:integer read b_make_inhabitants write setmake_inhabitants; property max_level:integer read b_max_level write setmax_level; property life_points:integer read b_life_points write setlife_points; property time:Tressources read b_time write settime; end;
Tspieler=Class(TObject) private b_res:Tressources; b_inhabitants:integer; b_century:integer; b_messages:array of String; procedure setressources(res:Tressources); procedure setinhabitants(inhab:integer); procedure setcentury(centu:integer); function gettext(Index: Integer): string; procedure puttext(Index: Integer; tex: string); public constructor create(oat,stone,metal,inhabitants,century:integer); destructor destroy; property ressources:Tressources read b_res write setressources; property inhabitants:integer read b_inhabitants write setinhabitants; property century:integer read b_century write setcentury; property messages[Index: Integer]: string read gettext write puttext; default; end;
TMessagewindow=Class(TObject) private b_posx:integer; b_posy:integer; b_width:integer; b_height:integer; b_visible:Boolean; b_text:array of string; procedure setvisible(vis:Boolean); function gettext(Index: Integer): string; procedure puttext(Index: Integer; tex: string); public procedure draw(canvas:TDirectDrawSurfaceCanvas); constructor create(x,y,width,height:integer;visible:boolean); property visible:Boolean read b_visible write setvisible; procedure setpos(posx,posy:integer); procedure setzsize(width,height:integer); property text[Index: Integer]: string read gettext write puttext; default; end;
TPropertymanager=Class(Tobject) private props:Tpropertylist; procedure setprops(prop:Tpropertylist); public constructor create(building_file:string;building_typ:integer); destructor destroy; property properties:Tpropertylist read props write setprops; end;
TBuilding=Class(Tobject) private prope_manager:Tpropertymanager; xcoord:integer; ycoord:integer; b_typ:integer; b_level:integer; b_status:integer; procedure setx(x:integer); procedure sety(y:integer); procedure settyp(typ:integer); procedure setlevel(level:integer); procedure setstatus(status:integer); procedure setpropmanager(propmanager:Tpropertymanager); public constructor create(building_typ:integer); destructor destroy; property x:integer read xcoord write setx; property y:integer read ycoord write sety; property typ:integer read b_typ write settyp; property level:integer read b_level write setlevel; property status:integer read b_status write setstatus; property prop_manager:Tpropertymanager read prope_manager write setpropmanager; procedure develop; end;
TObjectmanager=Class(TObject) private object_id:integer; object_array: array of Tbuilding; protected function getbuilding(Index: Integer): Tbuilding; procedure putbuilding(Index: Integer; build:Tbuilding); public constructor create; destructor destroy; function build(typ:integer;x,y:integer;stufe:integer;spieler:Tspieler):integer; function search(x,y:integer):integer; property objects[Index: Integer]: Tbuilding read getbuilding write putbuilding; default; property max_id:integer read object_id; end;
TGame=Class(TObject) private b_objectmanager:Tobjectmanager; b_reswindow:TMessagewindow; b_eventwindow:TMessagewindow; b_infowindow:TMessagewindow; b_spieler:Tspieler; procedure inctime(res:Tressources); procedure setobjectmanager(om:Tobjectmanager); procedure setinfowindow(iw:TMessagewindow); public constructor create(); destructor destroy; procedure calcressources; procedure tick; procedure informplayer; property Objectmanager : TObjectmanager read b_objectmanager write setobjectmanager; property reswindow : TMessagewindow read b_reswindow; property eventwindow : TMessageWindow read b_eventwindow; property infowindow : TMessageWindow read b_infowindow write setinfowindow; property spieler : TSpieler read b_spieler; end;
implementation
function Explode(const Separator, S: string; Limit: Integer = 0): TStringDynArray; var SepLen: Integer; F, P: PChar; ALen, Index: Integer; begin SetLength(Result, 0); if (S = '') or (Limit < 0) then Exit; if Separator = '' then begin SetLength(Result, 1); Result[0] := S; Exit; end; SepLen := Length(Separator); ALen := Limit; SetLength(Result, ALen);
Index := 0; P := PChar(S); while P^ <> #0 do begin F := P; P := AnsiStrPos(P, PChar(Separator)); if (P = nil) or ((Limit > 0) and (Index = Limit - 1)) then P := StrEnd(F); if Index >= ALen then begin Inc(ALen, 5); SetLength(Result, ALen); end; SetString(Result[Index], F, P - F); Inc(Index); if P^ <> #0 then Inc(P, SepLen); end; if Index < ALen then SetLength(Result, Index); end;
procedure Tressources.setoat(o:integer); begin b_oat:=o; end;
procedure Tressources.setstone(s:integer); begin b_stone:=s; end;
procedure Tressources.setmetal(m:integer); begin b_metal:=m; end;
constructor Tpropertylist.create(); begin b_need:=Tressources.create; b_produce:=Tressources.create; b_produce_time:=Tressources.create; b_time:=Tressources.create; end;
destructor Tpropertylist.destroy; begin b_need.Free; b_produce.Free; b_produce_time.Free; b_time.Free; end;
procedure Tpropertylist.setname(n:string); begin b_name:=n; end;
procedure Tpropertylist.setbuilding_id(b:integer); begin b_building_id:=b; end;
procedure Tpropertylist.settile_id(ti:integer); begin b_tile_id:=ti; end;
procedure Tpropertylist.setneed(ne:Tressources); begin b_need:=ne; end;
procedure Tpropertylist.setproduce(pro:Tressources); begin b_produce:=pro; end;
procedure Tpropertylist.setproduce_time(prot:Tressources); begin b_produce_time:=prot; end;
procedure Tpropertylist.setmake_inhabitants(mi:integer); begin b_make_inhabitants:=mi; end;
procedure Tpropertylist.setmax_level(ml:integer); begin b_max_level:=ml; end;
procedure Tpropertylist.setlife_points(lp:integer); begin b_life_points:=lp; end;
procedure Tpropertylist.settime(t:Tressources); begin b_time:=t; end;
constructor Tspieler.create(oat,stone,metal,inhabitants,century:integer); begin b_res:=Tressources.Create; b_res.oat:=oat; b_res.stone:=stone; b_res.metal:=metal; b_inhabitants:=inhabitants; b_century:=century; SetLength(b_messages,1); end;
destructor Tspieler.destroy; var i:integer; begin b_res.Free; end;
function Tspieler.gettext(Index: Integer): string; begin Result := b_messages[Index]; end;
procedure TSpieler.puttext(Index: Integer; tex:string); begin if Index >= Length(b_messages)-1 then SetLength(b_messages, Length(b_messages)+1); b_messages[Index] := tex; end;
procedure Tspieler.setressources(res:Tressources); begin b_res:=res; end;
procedure Tspieler.setinhabitants(inhab:integer); begin b_inhabitants:=inhab; end;
procedure Tspieler.setcentury(centu:integer); begin b_century:=centu; end;
constructor TMessagewindow.create(x:integer;y:integer;width:integer;height:integer;visible:boolean); begin b_posx:=x; b_posy:=y; b_width:=width; b_height:=height; b_visible:=visible; SetLength(b_text,1); end;
function TMessagewindow.gettext(Index: Integer): string; begin Result := b_text[Index]; end;
procedure TMessagewindow.puttext(Index: Integer; tex:string); begin if Index >= Length(b_text) then SetLength(b_text, Length(b_text)+1); b_text[Index] := tex; end;
procedure TMessagewindow.setpos(posx:Integer;posy:integer); begin b_posx:=posx; b_posy:=posy; end;
procedure TMessagewindow.setzsize(width,height:integer); begin b_width:=width; b_height:=height; end;
procedure TMessagewindow.draw(canvas:TDirectDrawSurfaceCanvas); var i:integer; begin if b_visible then begin canvas.Brush.Color:=clsilver; canvas.Font.Color:=clblack; canvas.Rectangle(b_posx,b_posy,b_posx+b_width,b_posy+b_height); for i:=0 to Length(b_text)-1 do canvas.TextOut(b_posx+1,b_posy+1+(i*13),b_text[i]); canvas.release; end; end;
procedure TMessagewindow.setvisible(vis:Boolean); begin b_visible:=vis; end;
constructor Tpropertymanager.create(building_file:string;building_typ:integer); var b_file:textfile; var line:string; var res:TSTringdynarray; begin props:=Tpropertylist.Create; AssignFile(b_file,ExtractFilePath(ParamStr(0)) + building_file); Reset(b_file); while not eof (b_file) do begin readln(b_file,line); res:=Explode(',',line,0); props.name:=res[0]; props.building_id:=strtoint(res[1]); props.tile_id:=strtoint(res[2]); props.need.oat:=strtoint(res[3]); props.need.stone:=strtoint(res[4]); props.need.metal:=strtoint(res[5]); props.produce.oat:=strtoint(res[6]); props.produce.stone:=strtoint(res[7]); props.produce.metal:=strtoint(res[8]); props.produce_time.oat:=strtoint(res[9]); props.produce_time.stone:=strtoint(res[10]); props.produce_time.metal:=strtoint(res[11]); props.make_inhabitants:=strtoint(res[12]); props.max_level:=strtoint(res[13]); props.life_points:=strtoint(res[14]); if building_typ=props.building_id then break; end; end;
destructor Tpropertymanager.destroy; begin props.Free; end;
procedure Tpropertymanager.setprops(prop:Tpropertylist); begin props:=prop; end;
constructor Tbuilding.create(building_typ:integer); begin prope_manager:=Tpropertymanager.create('building.txt',building_typ); end;
destructor Tbuilding.destroy; begin prope_manager.Free; end;
procedure Tbuilding.setpropmanager(propmanager:Tpropertymanager); begin prope_manager:=propmanager; end;
procedure Tbuilding.develop(); begin inc(b_level); end;
procedure Tbuilding.setx(x:integer); begin xcoord:=x; end;
procedure Tbuilding.sety(y:integer); begin ycoord:=y; end;
procedure Tbuilding.settyp(typ:integer); begin b_typ:=typ; end;
procedure Tbuilding.setlevel(level:integer); begin b_level:=level; end;
procedure Tbuilding.setstatus(status:integer); begin b_status:=status; end;
constructor Tobjectmanager.create(); begin object_id:=0; SetLength(Object_Array, 2500); end;
destructor Tobjectmanager.destroy; var i:integer; begin for i:=0 to length(object_array)-1 do object_array[i].Free; end;
function Tobjectmanager.search(x:integer;y:integer):integer; var i:integer; begin if object_id>0 then begin for i:=0 to object_id-1 do begin if (object_array[i].x=x) and (object_array[i].y=y) then begin result:=i; break; end; result:=-1; end; end else result:=-1; end;
function Tobjectmanager.getbuilding(Index: Integer): Tbuilding; begin result:=nil; if object_id > 0 then Result := object_array[Index]; end;
procedure Tobjectmanager.putbuilding(Index: Integer; build:Tbuilding); begin if object_id > 0 then object_array[Index] := build; end;
function Tobjectmanager.build(typ:integer;x,y:integer;stufe:integer;spieler:Tspieler):integer; begin result:=-1; object_array[object_id]:=TBuilding.create(typ); if spieler.ressources.oat >= object_array[object_id].prop_manager.properties.need.oat then if spieler.ressources.stone >= object_array[object_id].prop_manager.properties.need.stone then if spieler.ressources.metal >= object_array[object_id].prop_manager.properties.need.metal then begin object_array[object_id].typ:=typ; object_array[object_id].x:=x; object_array[object_id].y:=y; object_array[object_id].level:=stufe; result:=object_id; spieler.ressources.oat:=spieler.ressources.oat - object_array[object_id].prop_manager.properties.need.oat; spieler.ressources.stone:=spieler.ressources.stone - object_array[object_id].prop_manager.properties.need.stone; spieler.ressources.metal:=spieler.ressources.metal - object_array[object_id].prop_manager.properties.need.metal; spieler.messages[length(spieler.b_messages)-1]:='Gebäude erfolgreich gebaut!'; inc(object_id); end; if result=-1 then begin object_array[object_id].Free; spieler.messages[length(spieler.b_messages)-1]:='Gebäude konnte aufgrund fehlender Ressourcen nicht gebaut werden!'; end;
end;
constructor Tgame.create; begin b_objectmanager:=Tobjectmanager.create; b_reswindow:=TMessagewindow.create(0,0,250,15,true); b_eventwindow:=TMessagewindow.create(0,618,375,70,true); b_infowindow:= TMessagewindow.create(0,0,150,40,false); b_spieler:=Tspieler.create(100,100,100,10,1); b_reswindow.text[0]:=' Getreide: '+inttostr(b_spieler.ressources.oat)+' Stein: '+inttostr(b_spieler.ressources.stone)+' Metall: '+inttostr(b_spieler.ressources.metal);end;
destructor Tgame.destroy; begin b_objectmanager.free; b_reswindow.Free; b_eventwindow.Free; b_infowindow.free; b_spieler.Free; end;
procedure Tgame.setobjectmanager(om:Tobjectmanager); begin b_objectmanager:=om; end;
procedure Tgame.setinfowindow(iw:TMessagewindow); begin b_infowindow:=iw; end;
procedure Tgame.tick; begin calcressources; b_reswindow.text[0]:=' Getreide: '+inttostr(b_spieler.ressources.oat)+' Stein: '+inttostr(b_spieler.ressources.stone)+' Metall: '+inttostr(b_spieler.ressources.metal); informplayer; end;
procedure Tgame.calcressources; var i,x:integer; begin for i:=0 to b_objectmanager.max_id-1 do begin inctime(b_objectmanager.objects[i].prop_manager.properties.time); if b_objectmanager.objects[i].prop_manager.properties.time.oat>=b_objectmanager.objects[i].prop_manager.properties.produce_time.oat then begin b_spieler.ressources.oat:=b_spieler.ressources.oat+b_objectmanager.objects[i].prop_manager.properties.produce.oat; b_objectmanager.objects[i].prop_manager.properties.time.oat:=0; end; if b_objectmanager.objects[i].prop_manager.properties.time.stone>=b_objectmanager.objects[i].prop_manager.properties.produce_time.stone then begin b_spieler.ressources.stone:=b_spieler.ressources.stone+b_objectmanager.objects[i].prop_manager.properties.produce.stone; b_objectmanager.objects[i].prop_manager.properties.time.stone:=0; end; if b_objectmanager.objects[i].prop_manager.properties.time.metal>=b_objectmanager.objects[i].prop_manager.properties.produce_time.metal then begin b_spieler.ressources.metal:=b_spieler.ressources.metal+b_objectmanager.objects[i].prop_manager.properties.produce.metal; b_objectmanager.objects[i].prop_manager.properties.time.metal:=0; end; end; end;
procedure Tgame.inctime(res:Tressources); begin res.oat:=res.oat+1; res.stone:=res.stone+1; res.metal:=res.metal+1; end;
procedure Tgame.informplayer; var i,j:integer; begin eventwindow.text[0]:=' STATUS'; j:=length(spieler.b_messages)-5; if j<0 then j:=0; for i:=j to length(spieler.b_messages)-1 do begin if spieler.messages[i]<>'' then begin eventwindow.text[length(spieler.b_messages)-i-1]:=' '+spieler.messages[i]; end; end; end;
end. |
Lg,
Kai
wurstuk - Sa 11.10.08 07:22
Hmmm ich finde es biss jetzt sehr gut!
Aber könnte mann nicht vllt statt dem Gitternetz einfach nur gras haben? also wo es wie in einem Gitternetz ist
bloß mann sieht es halt nicht^^
aber ich glaube das wird echt cool wenns fertig ist^^
passiv - Sa 11.10.08 09:37
ich habs mir bisher noch nicht angesehen, weils zu dick ist für meine leitung :roll: . aber was man so hört (sorry: liest) soll bisher es ganz gut sein.
was bisher nicht angebracht wurde: deine häuser sind unendlich haltbar. im normalfall, also in allen strategie-spielen, gibt es abnutzung: feuer, krankheit und einsturz. und dann hat man feuerwehr, heilanstalten und architekten/baumeister. und wenn einer das haus passiert (vorbeigeht) wird im haus ein feuer: integer; zurückgesetzt auf 0. das wär noch ein punkt für die überklasse TBuilding. und wenn der wert aber 100 erreicht, bricht feuer aus. dann strömen alle feuerwehren herbei und löschen. incrementieren tut man den halt einfach per timer oder zufall, je nachdem.
den letzten punkt würd ich erst realisieren, wenn du schon eine funktionierende wege- und wegsuchengine hast. also wie ein navi halt :lol:
auch noch: lagerhaus/silo zum lagern der waren, bevor sie aufn markt kommen.
und noch was: wasserversorgung ... falls das noch irgendwie passt :D
ansonsten toi-toi-toi! du schaffst das!
mfg
Fabian
wurstuk - Sa 11.10.08 10:53
Das erinnert mich sehr an diese "der erste Kaiser", "Pharao", "Herscher des Olymps", ... Spiele ;)
Da musste mann auch immer Architekten bauen und so^^
Aber sonst sind es Klassiker werden zwar ein bisschen Schnell Langweilig aber sonst eig. ganz gut^^ dort könntest du dir ja Ideen für dein Spiel holen :D
passiv - Sa 11.10.08 13:34
jop, im konkreten pharao und caesar. letzteres ist ein weltklassespiel 8)
Hidden - Sa 11.10.08 14:09
[OT]
Nach Pharao grabe ich schon seit zwei Jahren immer mal wieder. Bisher nicht gefunden :lol:
[/OT]
kai_lamers - Sa 11.10.08 23:44
Hey,
heute kam ich zu nix, da ich bis grad eben noch unterwegs war und jetzt weder Nerv, noch die entsprechende Wachheit habe, um noch was gescheites auf die Beine zu stellen.
Die Gebäude an sich haben schon keine unendliche Haltbarkeit, die Klasse besitzt einen Integer Wert namens Life Points, die gibt es schon, ist aber bisher nicht ordentlich in die anderen Klassen implementiert - wie auhc, es gibt ja noch keine "zerstörenden Klassen".
Danke schonmal für die Ideen, werde ich an entsprechendem Zeitpunkt gerne drauf zurückgreifen.
@Wurstuk:
Welches Gitter meinst du?
Wie es bei mir aussieht ("nur Gras"), kannst du im Screenshot im Anhang sehen.
Jetzt muss ich aber ins Bett, kam grad erst aus den Horrorwood Studios ;)
Lg,
Kai
wurstuk - So 12.10.08 02:14
Aso....
Ka warum bei mir so ein gitter ist.... liegt warscheinlich an meinem PC^^
bei dier siehts sowie so viel coller aus als bei mir :P
kai_lamers - So 12.10.08 13:12
Kannst du eventuell mal einen Screenshot hochladen?
Würde mich mal interessieren.
Danke!
wurstuk - So 12.10.08 19:27
ne kann ich nicht sry bei mir ist die drucken taste kaputt und ich hab jetzt echt kein bock gimp zu starten^^
aber du kannst es dir so vorstellen das mann das gras nicht so wirklich sieht sondern nur eine dunkelgrüne Fläche und dadrauf ist ein Gitternetz in schwarzen Linien^^
Hidden - So 12.10.08 21:18
wurstuk hat folgendes geschrieben : |
| ne kann ich nicht sry bei mir ist die drucken taste kaputt und ich hab jetzt echt kein bock gimp zu starten^^ |
Für einen versierten Programmierer sollte es selbstverständlich sein, dass er sich dann ein Programm schriebt, das mit einem anderen Shortcut einen Screenshot in die Zwischenablage kopiert :mahn:
kai_lamers - So 12.10.08 21:34
wurstuk hat folgendes geschrieben : |
ne kann ich nicht sry bei mir ist die drucken taste kaputt und ich hab jetzt echt kein bock gimp zu starten^^
aber du kannst es dir so vorstellen das mann das gras nicht so wirklich sieht sondern nur eine dunkelgrüne Fläche und dadrauf ist ein Gitternetz in schwarzen Linien^^ |
Schade, dann werde ich den Fehler bei Dir wohl auch nicht näher lokalisieren können.
Aber gut - weiter geht's.
Jetzt mache ich mich auf die Suche nach der Ursache der Zugriffsverletzung (s.o.) - damit ich danach ENDLICH mal zur Steuerung kommen kann.
Wenn's was neues gibt, melde ich mich :)
Lg,
Kai
passiv - Mo 13.10.08 14:35
ich hab mir jetzt mal den code für die häuser angesehen und denk mir: wieso hast du soviele property- und object-manager?
dann hab ichs mir durchgedacht und bin auf 2 notwendige dinge gekommen: ein Haus-Objekt (TBuilding) und ein Verwaltungs-Objekt (TObjectInspector). und da verwaltet einfach der OI jedes haus in einem array. und jedes haus hat natürlich auch noch einen pointer auf seinen eltern-OI. und wenn man das gleich für multiplayer auslegen will, schreibt man sich noch ein Spiel-Objekt (TGame), die alle OIs verwaltet ...
das wär meine Idee und ich versuch das ganze auch gerade zu implementieren. (nur scheiterts bei mir an der grafik-engine. die TPaintBox is wohl nicht so super :roll: . und ich kapier sämtliche OGL dinger nicht. [OT]jedes tutorial besteht aus einer .pas-datei und basiert auf try-and-error, was mir bisher noch zu fad war.[/OT])
mfg
passiv
Hidden - Mo 13.10.08 15:11
passiv hat folgendes geschrieben : |
| nur scheiterts bei mir an der grafik-engine. die TPaintBox is wohl nicht so super :roll: |
Kannst du das näher erläutern? IMHO für ein Spiel die
einzige saubere Lösung ;)
kai_lamers - Mo 13.10.08 16:04
Hey,
also ich halte es für sinnvoll jedem Building im Objectmanager einen propertymanager zuzuweisen, da schließlich auch jedes Gebäude eigene properties besitzt - so ist erstmal jedes Gebäude eine "autarke" Instanz, auf die ich mithilfe des Propertymanagers vollen Zugriff habe und auch haben möchte.
Es gibt übrigens nur EIN Objectmanager und den besitzt die Klasse TGame - also von vielen Objektmanagern kann da wirklich nicht die Rede sein ;)
Natürlich könnte man auch das Object Array entsprechend mehrdimensional anlegen, sodas nach festgelegter Syntax gesagt werden kann Object_Array[id, 1]=Need Oat, ...[id,2]=Need Stone, doch empfinde ich den Zugriff mithilfe des Prop.Managers anhand folgender Klassen sehr viel angenehmer.
Tgame.Tobjectinspector.TBuilding[Integer].TPropertymanager.TProperylist
Performanter und sinnvoller geht es immer - am grundlegenden Klassenkonzept werde ich auch erstmal nichts mehr großartig ändern - Da auf diesem Konzept alle meine Planungen, derzeit noch auf Papier, aufgebaut sind.
EDIT:
=====
Jetzt wo ich mir deinen Beitrag das 2. mal durchgelesen habe: Quasi genau so habe ich es doch gemacht?!
Es gibt eine Klasse Tgame, die besitzt einen Objectmanager, welcher ein Array des Typs TBuilding besitzt. Jedes TBuilding besitzt dann halt einen Objectmanager, aber dazu: s.o.
Lg,
Kai
wurstuk - Mo 13.10.08 16:09
Ok werd ein Screenshot machen^^
ich werd ihn dann morgen reinstellen und das mit dem Programm das mit einer anderen taste einen Screenshot macht
kann ich noch nicht^^ würde mich aber belehren lassen :D
kai_lamers - Mo 13.10.08 16:15
[OT]
Hey,
danke.
Hier hast du mal ein Codeschnipsel, anhand dessen wirds ziemlich schnell klar, wie's geht.
Wie du einen Tastendruck entsprechend abfängst kriegst du ja selbst hin :D
http://www.scalabium.com/faq/dct0001.htm
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27:
| procedure TForm1.Button1Click(Sender: TObject); var DCDesk: HDC; bmp: TBitmap; begin bmp := TBitmap.Create; bmp.Height := Screen.Height; bmp.Width := Screen.Width;
DCDesk := GetWindowDC(GetDesktopWindow); BitBlt(bmp.Canvas.Handle, 0, 0, Screen.Width, Screen.Height, DCDesk, 0, 0, SRCCOPY);
bmp.SaveToFile('ScreenShot.bmp');
ReleaseDC(GetDesktopWindow, DCDesk);
bmp.Free; end; |
[/OT]
Hidden - Mo 13.10.08 16:43
Jop. Nur statt SaveToFile dann CopyToClipboard ;)
wurstuk - Mo 13.10.08 21:45
hmm ich check dis i-wie nicht... hab jetzt aber auch gerade wenig zeit werde mich morgen mal eindringlicher mit der Seite beschäftigen^^ :roll:
Als Anhang ist jetzt ein Screenshot vom Spiel, war doch einfacher mit Gimp als ich es in Erinnerung hatte^^
kai_lamers - Di 14.10.08 06:12
Hey,
danke - du hast ja noch die ganz alte Version, lade doch einfach mal die neuste im Thread ganz oben herunter und schau dann, ob sich was geändert hat ;)
Lg,
Kai
elundril - Di 14.10.08 10:19
Hidden hat folgendes geschrieben : |
| Jop. Nur statt SaveToFile dann CopyToClipboard ;) |
warum statt savetofile, copytoclipboard. die meisten spiele speichern screenshots in einen extra ordner in ihrem verzeichnis. dadurch kann man einen screenshot machen und braucht ihn nicht sofort in paint einfügen wenn man ihn länger haben will.
passiv - Di 14.10.08 11:39
Hidden hat folgendes geschrieben : |
passiv hat folgendes geschrieben : | | nur scheiterts bei mir an der grafik-engine. die TPaintBox is wohl nicht so super :roll: | Kannst du das näher erläutern? IMHO für ein Spiel die einzige saubere Lösung ;) |
naja: ich kann damit nur schlecht eine Isobaten-ansicht zaubern. und fullscreen geht auch nur bedingt. geschweige denn von sinnvollem scrolling der landkarte.
kai_lamers hat folgendes geschrieben : |
| also ich halte es für sinnvoll jedem Building im Objectmanager einen propertymanager zuzuweisen, da schließlich auch jedes Gebäude eigene properties besitzt - so ist erstmal jedes Gebäude eine "autarke" Instanz, auf die ich mithilfe des Propertymanagers vollen Zugriff habe und auch haben möchte. |
na eben. jeder propertymanager ist im endeffekt die eigenschaften des buildings. d.h.: du könntest die eigenschaften vom propertymanager direkt im building einbauen ... oder check ichs einfach nicht?
kai_lamers hat folgendes geschrieben : |
| Es gibt übrigens nur EIN Objectmanager und den besitzt die Klasse TGame - also von vielen Objektmanagern kann da wirklich nicht die Rede sein ;) |
na eh ned, es waren nur so viele dinge, die alle irgendwie gekürzt/zusammengefügt werden könnte ...
kai_lamers hat folgendes geschrieben : |
Natürlich könnte man auch das Object Array entsprechend mehrdimensional anlegen, sodas nach festgelegter Syntax gesagt werden kann Object_Array[id, 1]=Need Oat, ...[id,2]=Need Stone, doch empfinde ich den Zugriff mithilfe des Prop.Managers anhand folgender Klassen sehr viel angenehmer.
Tgame.Tobjectinspector.TBuilding[Integer].TPropertymanager.TProperylist |
da könntest du bei Tgame.Tobjectinspector einen streichen. und die TPropertylist könnte man eben gleich im TBuilding reinbauen. dann spart man sich 2 Ojekte und eine Menge schreibarbeit ;)
kai_lamers hat folgendes geschrieben : |
| Performanter und sinnvoller geht es immer - am grundlegenden Klassenkonzept werde ich auch erstmal nichts mehr großartig ändern - Da auf diesem Konzept alle meine Planungen, derzeit noch auf Papier, aufgebaut sind. |
auch klar, dass da dran rütteln sich fast nicht mehr lohnt. wollt nur mal sehen, was die leute (außer uns beiden) zu den beiden techniken sagen. so, vor- und nachteile abwägen. lernen für weiteres programmieren. oder vielleicht aussagen von profis, dies wissen, welche methode mehr vor-/nachteile hat.
nachdem sie aber dazu überhaupt nix sagen, war das eh umsonst (vielleicht wirds jetzt was :roll: ).
kai_lamers hat folgendes geschrieben : |
| Jetzt wo ich mir deinen Beitrag das 2. mal durchgelesen habe: Quasi genau so habe ich es doch gemacht?! |
ich hoff jetzt is klarer auf was ich hinaus will ;)
kai_lamers hat folgendes geschrieben : |
| Es gibt eine Klasse Tgame, die besitzt einen Objectmanager, welcher ein Array des Typs TBuilding besitzt. Jedes TBuilding besitzt dann halt einen Objectmanager, aber dazu: s.o. |
ja und da dran hängt wieder was dran. aber dazu: s.o. ;)
wurstuk - Di 14.10.08 13:58
WOW!!! Die neuste Version ist ja schon voll cool! :D
Aber bei mir ist immer noch das Netz^^ aber egal^^
Mir sind bloß noch ein paar Idee gekommen, wie wäre es wenn jedes Gebäude eine Bauzeit hätte?
Gibt es später eig. vllt noch Menüs von den Gebäuden also so das mann z.B. bei einer Schmiede einstellen kann ob sie Schwerter oder Äxte produziert^^
Soll mann Später Gebäude aufwerten können? also das sich dann pro lvl Produktion usw. steigert und wenn sollte mann die Gebäude dann per Hand aufwerten oder automatisch wenn sie eine bestimmte Zeit stehen?
hmmm das sind jetzt eher fragen aber ich hoffe es hilft ein bisschen^^
passiv - Di 14.10.08 19:15
gebäudeaufwerten find ich im caesar IV ganz cool. da gehts darum, dass nur wohnhäuser und märkte, theater und andere luxusdinger die in wohngebieten stehen aufwerten. dabei wird die umgebung bewertet, wie ruhig, schön, oä es ist. und jedes industrie-ding zieht die attraktivität des gebiets in einem bestimmten radius runter.
DelphiMarkus - Mi 15.10.08 14:06
Ich würde das Aufwerten von Gebäuden auch mit reinnehmen. Bei Siedler 5 und 6 gibt es das ja auch und ich finde es gut. :) Das kostet was, aber es macht Sinn, weil man keinen weiteren Platz mehr verschwendet und trotzdem z.B. mehr Bewohner in einem Haus wohnen können.
Ansonsten ist das Spiel schon wirklich gut geworden, man kann zwar noch fast nichts machen (oder irre ich mich da??), aber es sieht schonmal sehr gut aus und ist bestimmt eine gute Grundlage. :wink:
Das die Gebäude eine Bauzeit haben fände ich gut, das Spiel ist dann "gemütlicher", weil nicht sofort alles da ist, sondern erst seine Zeit braucht bis es fertig ist. Am schönsten wäre es, wenn man beim Bauen zusehen kann, aber das ist für den Anfang vielleicht nicht so ganz wichtig und außerdem wäre es nochmal mehr Arbeit als so schon. :D
Ich finde es Spitze! Nur weiter so!! :zustimm:
passiv - Do 16.10.08 07:30
nagut, das mit den wohnhäusern hab ich vergessen zu erwähnen: wenn die aufleveln, passen mehr leute rein. und wenn märkte aufleveln (das tun sie, wenn die wohnhäuser rundherum das auch tun), dann passen mehr rohstoffe rein.
kai_lamers - Sa 18.10.08 12:30
Hey,
die Woche über gab es nix neues, da ich während der Schule und aufgrund von Training einfach nicht dazu komme mich länger vor den Rechner zu setzen und was zu machen.
Erstmal danke für die weiteren Anregungen, dass die Gebäude eine Bauzeit bekommen, find ich gut - werde ich auch heute noch in die Klasse mit einpflanzen.
Zusätzlich werde ich jetzt endgültig dem Zugriffsfehler auf die Pelle rücken,
in ca. einer Stunde wird's dann was neues von mir geben.
Lg,
Kai
kai_lamers - Sa 18.10.08 14:38
Titel: Hilfeeeeeeeeeeee
Hey,
ich habe da jetzt ein Problem und finde die Lösung einfach nicht.
Ich habe meine Infomessage Struktur nochmal komplett überarbeitet, sodass jetzt nicht mehr mit einem dynamischen String Array gearbeitet wird, sondern mit einem Stapel, den ich irgendwann mal für die Schule schreiben musste, der ist folgendermaßen aufgebaut:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
| Tbox=class(Tobject) private o,r:Tobject; head:Tbox; public constructor create(o0:Tobject; r0:Tbox); virtual; property obj:Tobject read o write o; property right: Tobject read r write r; end;
Tstapel=class(Tobject) private head:Tbox; help:tbox; public destructor destroy; function isempty:boolean; procedure push(o: Tobject); function top: Tobject; function pop: Tobject; end; |
und so implementiert:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44:
| constructor tbox.create(o0:Tobject; r0:Tbox); begin r:=r0; o:=o0; end;
destructor tstapel.destroy; begin while head <> nil do begin help:=head; head:=tbox(head.right); help.destroy; end; end;
function tstapel.isempty:boolean; begin result:=head=nil; end;
function tstapel.top:tobject; begin if head=nil then result:=nil else result :=head.obj; end;
function tstapel.pop:tobject; begin if head=nil then result:=nil else begin result:=head.obj; help:=head; head:=tbox(head.right); help.destroy; end; end;
procedure tstapel.push(o:tobject); begin head:=tbox.create(o,head); end; |
Das ganze wende ich nun folgendermaßen an:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| procedure Tgame.informplayer; var i:integer; begin eventwindow.delete_texts; eventwindow.text[0]:=' STATUS'; i:=0; while not spieler.infostapel.isempty do begin if not spieler.infostapel.isempty then begin inc(i); b_akt_message:=TMessage(spieler.infostapel.pop); b_akt_message.time:=b_akt_message.time+1; eventwindow.text[i]:=b_akt_message.gmessage; if b_akt_message.time<=3 then b_help_stapel.push(b_akt_message); end; end; while not b_help_stapel.isempty do begin if not b_help_stapel.isempty then spieler.infostapel.push(b_help_stapel.pop); end; end; |
Problem ist folgendes:
Prinzipiell klappt alles soweit, also nach 3 Spielzyklen wird die Nachricht nicht weiter im Staque mit aufgenommen, alles wunderbar.
Nur habe ich ein Problem, wenn ich 3 Gebäude baue, dann steht dort:
"Gebäude erfolgreich gebaut
Gebäude erfolgreich gebaut
Gebäude erfolgreich gebaut"
Soweit also richtig, nur wenn ich jetzt versuche eines zu bauen, dies aber aufgrund fehlender Ressourcen nicht möglich ist:
"Gebäude konnte aufgrund fehlender Ressourcen nicht gebaut werden!
Gebäude konnte aufgrund fehlender Ressourcen nicht gebaut werden!
Gebäude konnte aufgrund fehlender Ressourcen nicht gebaut werden!
Gebäude konnte aufgrund fehlender Ressourcen nicht gebaut werden!"
Meint also, das b_akt_message nur einmal gelesen wird und dann entsprechend häufig in den Staque gepackt wird.
In den Staque füge ich folgendermaßen ein:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| if result=-1 then begin object_array[object_id].Free; spieler.gamemessage.gmessage:='Gebäude konnte aufgrund fehlender Ressourcen nicht gebaut werden!'; spieler.gamemessage.time:=0; spieler.infostapel.push(spieler.gamemessage); end; |
Ich weiß echt nicht, woran es liegt.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!