Autor Beitrag
IhopeonlyReader
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: Do 11.07.13 22:00 
guten tag,
www.entwickler-ecke....ewtopic.php?t=111794
Stream oder String?

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
Mr_Emre_D
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 114
Erhaltene Danke: 14



BeitragVerfasst: Fr 12.07.13 10:04 
IhopeonlyReader hat folgendes geschrieben:

ausblenden Delphi-Quelltext
1:
2:
ZuSendenderText := IntToStr( Zahl ) + #13#10 + IntToStr(Punkt.X) + #13#10 + IntToStr( Punkt.Y ) 
#13#10+ Zeichen +#13#10 +  IntToStr( UndRest ) + #13#10 + Text;



Kommt ganz drauf an - wenn es um Geschwindigkeit geht - als Stream, sonst String.
Warum?
IntToStr(Zahl) wandelt die Zahl in einen String.
Dieser String kann eine maximale Länge von 11 ("-2147483648") haben (Integer = [-2^31,2^31]).
Wir nehmen den schlimmsten Fall an:
Du schickst nun entweder 11 Bytes (als String - String besteht aus (Ansi)Chars wobei ein AnsiChar = 1 Byte)
oder nur 4 Bytes als Integer / Stream...

Ich habe bisher solche Sachen nie über String gelöst! Es ist jedoch nicht unüblich, dass Spiele das auch mal über Strings lösen!
Beispiel: Call of Duty 1.
(Du kannst gerne mal die Pakete analysieren! Sind Strings - sofern ich das richtig in Erinnerung habe).

Edit:
Im anderen Thread gibts du ein Beispiel für das Versenden über Streams an - das ist aber so nicht korrekt!
Du kannst keine dynamischen Typen so verschicken (dyn. im Sinne von - Größe nicht bekannt --> Strings)
Wenn du einen beliebigen String verschicken willst, so musst du eine Länge davor packen:
<LängeVonA><StringA>

Das ganze ginge, wenn es sich um einen Shortstring handelt:
Str: String[10]; // bei der ist die Länge konstant (siehe SizeOf())
Im Speicher befindet sich eine Byte-Zahl, die angibt, wie lang so ein String ist:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
var
  a: string[10];

begin
  a := 'A1234';
  writeln('Laenge: ', pByte(@a)^, ' - erstes Zeichen: ', pAnsiChar(integer(@a) + 1)^);
  writeln(SizeOf(A));
  a := 'B234512345';
  writeln('Laenge: ', pByte(@a)^, ' - erstes Zeichen: ', pAnsiChar(integer(@a) + 1)^);
  writeln(SizeOf(A));
IhopeonlyReader Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: Sa 13.07.13 23:17 
ok, aber wie soll ich die länge anhängen?
mit sizeof() bestimmen und das alt 32-bit variable anhängen?

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
Mr_Emre_D
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 114
Erhaltene Danke: 14



BeitragVerfasst: So 14.07.13 07:09 
Joa, muss aber ned eine 32 Bit Zahl sein - mit 32 bit kannste 2^32 Zahlen darstellen, du wirst aber wohl kaum einen 2^32 Zeichen langen String verschicken..
Ich schätz, dass da ein Word (2^16 - 65536) auch aussreicht. Du könntest noch weiter runtergehen, wenn du weißt, dass z.B. der String nicht länger sein kann. Damit sparst du Bandbreite, was bei Spielen, die Pakete "spammen" sehr wichtig ist.
IhopeonlyReader Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: So 14.07.13 16:20 
mhh... aber dann müsste das doch an den Anfang vom Stream oder?
Weil ein Stream wird normalerweise ja partweise geschickt.. oder?

also sozusagen wird aus
0110 0110 0001 0001 1010 0101
0000 0000 0000 0000 0000 0000 0000 0011 0110 0110 0001 0001 1010 0101

oder? dann muss 0011 (3 Byte) + 4 Byte von der SizeÜbergabe addiert werden und dann hat man die Gesamtgröße des streams..
Wenn man sich aber auch nur ein bisschen dabei vertut, liest mal die falschen werte als Größe aus, und das hätte böse Konsequenzen

Somit müsste ich:
- Die Größe SICHER am Anfang übergeben
Nachteil: Jedes packet (Datenpaket) wäre größer
- Jedes Datenpacket gleichgroß halten (wenn es nur Koordinaten (also Integer Variablen) sind, dann wären sie ja wirklich immer konstant)
Nachteil: Strings und Arrays müssen "eingeschränkt" oder auf Server und Client parallel laufen

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
Mr_Emre_D
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 114
Erhaltene Danke: 14



BeitragVerfasst: Mo 15.07.13 10:19 
user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
mhh... aber dann müsste das doch an den Anfang vom Stream oder?
Weil ein Stream wird normalerweise ja partweise geschickt.. oder?

also sozusagen wird aus
0110 0110 0001 0001 1010 0101
0000 0000 0000 0000 0000 0000 0000 0011 0110 0110 0001 0001 1010 0101

oder? dann muss 0011 (3 Byte) + 4 Byte von der SizeÜbergabe addiert werden und dann hat man die Gesamtgröße des streams..
Wenn man sich aber auch nur ein bisschen dabei vertut, liest mal die falschen werte als Größe aus, und das hätte böse Konsequenzen


Ja, das stimmt so ca. schon, jedoch musst du nicht als Größenangabe eine 32 Bit Zahl nehmen, wie bereits zuvor geschildert!
(0000 0000 0000 0000 0000 0000 0000 0011 = 4 * 8 = 32 Bits)

Du kannst statt 4, auch 1 (=Byte statt DWORD) z.b. nehmen, WENN du weißt, dass die Daten, die folgen, sowieso nie größer 2^(1*8 ) sein werden können!

Eine Größenangabe muss nicht an den Anfang des Streams sondern vor einem dynamischen Typ:
Beispiel, du willst folgendes Record verschicken:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
TMyRec = packed record
  SomeNr: Integer;
  SomeOtherNr: Single;
  FirstDynamicField: Array of Byte;
  SecondDynamicField: String;
end;

Der Stream dazu würde wie folgt aussehen:
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
<SomeNr|4 Bytes>
<SomeOtherNr|4 Bytes>
<Length(FirstDynamicField)|2 Bytes>
<FirstDynamicField|x Bytes>
<Length(SecondDynamicField)|2 Bytes>
<SecondDynamicField|y Bytes>


Beschreibung der Zeilen:
1. Integer ist 4 Byte (4*8 Bits) groß
2. Single (Fließkommatyp) auch 4 Byte
3. Längenangabe über dyn. Array - hier habe ich 2 Byte verwendet, kommt aber drauf an - wenn das Array größer sein kann als 2^(2 * 8 ) = 2^16 = 65536, dann müsste man das vergrößern
4. FirstDynamicField - hier stehen nun x Bytes
5. ~ #3
6. ~ #4

Erst dann, wenn du das so machst, kann der Empfänger die Daten auch richtig "aufnehmen".
Er kriegt nämlich einen Stream mit Nullen udn Einsen (Zahlen, Bytes eig.)
Er weiß, dass die ersten zwei Felder eine konstante Größe haben, da kann er direkt 2 * 4 Bytes auslesen und in seinen Record speichern.
Bei den dyn. Feldern muss er nun wissen, wie groß die sind, damit er zuerst die Größe des Arrays/Strings setzen und dann die Daten "aufnehmen" kann.

Das Datenpaket ist nur geringfügig größer!

Zitat:

Wenn man sich aber auch nur ein bisschen dabei vertut, liest mal die falschen werte als Größe aus, und das hätte böse Konsequenzen

Jup, du darfst dich nicht vertun.
IhopeonlyReader Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: Mo 15.07.13 15:04 
ok, du verwendest packed record, warum kein normales record?
Den Aufbau versteh ich jetzt, DANKE :)

Nun überlege ich, dass ganze noch "optional" zu trennen, da ich z.B. am Anfang die Map übermittle, falls sie nicht vorhanden ist, später Spielerpositionen austausche, und ggf. neue Spieler hinzufüge, muss ich natürlich jeden Stream "erkenntlich" machen...
ich würde also IMMER eine bestimme 8-Bitfolge als "Erkennung" nehmen...

Vom Server zum Client:
0000 0001 (Map kontrolle)
0000 0101 (Länge des Strings (Name der Map) =5 Zeichen = 5*8Bit = 5 Byte)
0100 0001 ('A') 0100 0010 ('B') 0100 0100 ('C') 0000 0001 (' ') 0010 0001 ('!') (= 'ABC !') (String an sich)
0000 0100 0101 0111 (=1111) (Dateigröße zur Kontrolle ob richtige Map mit richtigem Namen vorhanden)

Als Antwort vom Client:
1000 0001 (Antwort: Mapkontrolle)
0000 0001 (True (vorhanden))

Server weiß nun bescheid und antwortet:
0000 0010 (Spieler namen)
0000 0010 (Spieleranzahl (2)(Empfänge zählt mit))
0000 0001 (Länge des Spielernamens Nr 1 -> 1 Zeichen -> 1 Byte)
0100 0001 (Spielername 'A')
0000 0001 (Team 1)
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001 0001 (Position X [Integer] = 17)
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001 0000 0000 (Position Y [Integer] = 256)
0000 0001 (Länge des Spielernamens Nr 1 -> 1 Zeichen -> 1 Byte)
0100 0010 (Spielername 'B')
0000 0010 (Team 2)
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001 (Position X [Integer] = 1)
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001 (Position Y [Integer] = 1)


und so weiter...

Ich würde also immer einen "flag" (ist das richtig?) am Anfang setzten (1 Byte), dieser besteht immer aus den selben Bestandteilen,
der Positionsaustausch z.B. Spielernamen als Flag, Spieleranzahl, und dann pro Spieler -> Länge des Namens, Array of Char (String), Team, Position (sollte ich ggf. als SmallInt und nicht als Integer wie normale TPoint Koordinaten behandeln)

Wäre das ein "gutes" Komunikationsverhältnis zwischen Server und Client?
Du kann man auch einzelne Bits in einen Stream einfügen (vorallem bei Booleans hilfreich)?, wenn ja wie?

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
Gerd Kayser
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 632
Erhaltene Danke: 121

Win 7 32-bit
Delphi 2006/XE
BeitragVerfasst: Mo 15.07.13 15:22 
user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
ok, du verwendest packed record, warum kein normales record?

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
type TMyRec1 = record
  a : Word;
  b : integer;
end;

type TMyRec2 = packed record
  a : Word;
  b : integer;
end;

[ ... ]

procedure TForm1.Button2Click(Sender: TObject);
var
  X : TMyRec1;
  Y : TMyRec2;
begin
  ShowMessage(IntToStr(SizeOf(X)));
  ShowMessage(IntToStr(SizeOf(Y)));
end;


Hängt mit der Ausrichtung der Variablen im Speicher zusammen (Ausrichtung an Adressen, die durch 4 teilbar sind).
IhopeonlyReader Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: Mo 15.07.13 15:41 
Ein Packet record besitzt also die Größe aller beinhalteten Variablen und ein "normales" record die nächstgrößere ByteAnzahl, die durch 4 teilbar ist.
Danke für die Info, wusste ich nicht :oops:

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
OlafSt
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 486
Erhaltene Danke: 99

Win7, Win81, Win10
Tokyo, VS2017
BeitragVerfasst: Mo 15.07.13 15:43 
Ich glaub, den Cursor auf "packed" zu stellen und F1 zu drücken hätte dir das peinliche Erlebnis erspart ;)

_________________
Lies, was da steht. Denk dann drüber nach. Dann erst fragen.
IhopeonlyReader Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: Mo 15.07.13 15:47 
Nein :D ich weiß nicht warum, aber die PE von Delphi 7, die ich besitzte kann das nicht unter F1..
Mit Strg+Leertaste kann ich immerhin die "möglichen" Proceduren/Variablen.. ansehen, aber eine "eingebaute"-Delphi-Hilfe habe ich bei mir noch nicht gefunden

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
Gerd Kayser
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 632
Erhaltene Danke: 121

Win 7 32-bit
Delphi 2006/XE
BeitragVerfasst: Mo 15.07.13 17:30 
user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
ein "normales" record die nächstgrößere ByteAnzahl, die durch 4 teilbar ist.

Nein, nicht ganz korrekt. Die Ausrichtung findet ggf. bei jeder Variablen im Record statt.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
type TMyRec = record
  a : word;
  b : word;
  c : word;
  d : int64;
end;

SizeOf gibt hier 16 zurück. Bei einem packed Record sind es hingegen nur 14. Hängt immer damit zusammen, wie der Record aufgebaut ist.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
type TMyRec = record
  a : word;
  b : word;
  d : int64;
  c : word;
end;

Hier sind es sogar 24.
Mr_Emre_D
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 114
Erhaltene Danke: 14



BeitragVerfasst: Mo 15.07.13 20:34 
user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
ok, du verwendest packed record, warum kein normales record?
Den Aufbau versteh ich jetzt, DANKE :)

Nun überlege ich, dass ganze noch "optional" zu trennen, da ich z.B. am Anfang die Map übermittle, falls sie nicht vorhanden ist, später Spielerpositionen austausche, und ggf. neue Spieler hinzufüge, muss ich natürlich jeden Stream "erkenntlich" machen...
ich würde also IMMER eine bestimme 8-Bitfolge als "Erkennung" nehmen...

*SNIP*

und so weiter...

Ich würde also immer einen "flag" (ist das richtig?) am Anfang setzten (1 Byte), dieser besteht immer aus den selben Bestandteilen,
der Positionsaustausch z.B. Spielernamen als Flag, Spieleranzahl, und dann pro Spieler -> Länge des Namens, Array of Char (String), Team, Position (sollte ich ggf. als SmallInt und nicht als Integer wie normale TPoint Koordinaten behandeln)

Wäre das ein "gutes" Komunikationsverhältnis zwischen Server und Client?
Du kann man auch einzelne Bits in einen Stream einfügen (vorallem bei Booleans hilfreich)?, wenn ja wie?


Ja, man nennt diese Werte/Variablen auch Paket-IDs
Im Grunde wirst du sehr viele Identifiers im Laufe der Zeit unterbringen, da es verschiedenste Arten von Requests/Responses zwischen Client <-> Server geben wird:
Spiel wird gestartet,
Spieler Position geändert (passiv - externer Event, aktiv - eigener Event)
ein Objekt wurde modifiziert (wie?),
Spiel terminiert (game over?!)

Das sind alles individuelle Pakete, die ihre unique ids haben müssen, womit dann die Kommunikation zwischen Client und Server funktionieren kann!


Zuletzt bearbeitet von Mr_Emre_D am Do 18.07.13 21:19, insgesamt 1-mal bearbeitet
IhopeonlyReader Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: Mo 15.07.13 21:48 
ok, vielen dank, somit wäre das jetzt "abgehakt"..

Weiter zum Thema Dauer-Senden habe ich noch die frage:
- Einzelne Bits anhängbar?
Soviel ich weiß, kann man nur Bytes anhängen, man könnte also mehrere Bits zusammenfassen, aber direkt nur 1 Bit anhängen geht nicht.... -> richtig?

- In welchen Abständen sollte soetwas gesendet werden (CLIENT)?
- jede Änderung (lags?!)
- alle x millisek
- nach jedem x-ten durchlauf

- In welchen Abständen sollte der Server etwas senden?
- bei jeder angekommen Änderung
- wenn jeder Spieler einmal gesendet hat
- alle x millisek

oder: wie kann der Server sozusagen auf "abruf" immer den aktuellsten Stream bereit haben.. das heißt, Client A sendet und fragt danach direkt den Stream ab.
Wenn das so aussäh
Client A sendet, Client A will "empfangen", Server sendet, Client B sendet, Server sendet, Client B will "empfangen"
Dann hätte Client B ja 2 Streams hintereinander weg zu bearbeiten oder? wie kann ich soetwas vermeiden?

Nachtrag: Sollte ich eine extra "schick mir Infos"-Packet-ID einrichten? also Client A schickt diese ID und Server schickt nur zu Client A....?

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 15.07.13 22:35 
user profile iconIhopeonlyReader hat folgendes geschrieben Zum zitierten Posting springen:
Nein :D ich weiß nicht warum, aber die PE von Delphi 7, die ich besitzte kann das nicht unter F1..
Du hast vermutlich WinHelp nicht installiert:
www.delphi-library.d...ewtopic.php?p=544403
(Das gibt es auch für Windows 8:
www.microsoft.com/de...etails.aspx?id=35449)
Mr_Emre_D
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 114
Erhaltene Danke: 14



BeitragVerfasst: Mo 15.07.13 22:58 
Zitat:
ok, vielen dank, somit wäre das jetzt "abgehakt"..

Weiter zum Thema Dauer-Senden habe ich noch die frage:
- Einzelne Bits anhängbar?
Soviel ich weiß, kann man nur Bytes anhängen, man könnte also mehrere Bits zusammenfassen, aber direkt nur 1 Bit anhängen geht nicht.... -> richtig?

Zu granular! Arbeite lieber im Byte Bereich (und höher). Wenn es sonst unbedingt sein muss, dann seh dich um nach Bit-Operationen:
SHL, SHR, AND, OR, NOT
Bits kannst du aber nicht einem Stream hinzufügen, da die kleinste Einheit ein Byte ist - du kannst immer Vielfache von 8 Bits haben, diese kannste du aber beliebig modifizieren..

Zitat:

- In welchen Abständen sollte soetwas gesendet werden (CLIENT)?
- jede Änderung (lags?!)
- alle x millisek
- nach jedem x-ten durchlauf

- In welchen Abständen sollte der Server etwas senden?
- bei jeder angekommen Änderung
- wenn jeder Spieler einmal gesendet hat
- alle x millisek


Um was für eine Art von Spiel handelt es sich? Es sind nämlich Welten zwischen verschiedenen Spiel-Typen - vergleich mal ein FPS Game mit einem Brettspiel!
Sofern es mehr in Richtung FPS geht (also sofern die Objekte zeitecht sich verändern), dann würd ich mit ca. 10-15 Paketen/sec (also 1000/15 = 66mSec Abstände) arbeiten.
10 ist ca die Hälfte von 24 (24 ist so ca die Anzahl der Bilder, die das menschliche Auge pro Sekunde unterscheiden/aufnehmen/sehen kann).
Ich habe irgendwo mal aufgeschnappt, dass man das so machen soll und den Rest einfach interpolieren soll! (ganz widersprüchlich zum Nyquist-Theorem)
Spiel dich rum und schau, welche Werte am besten passen.

Zitat:

oder: wie kann der Server sozusagen auf "abruf" immer den aktuellsten Stream bereit haben.. das heißt, Client A sendet und fragt danach direkt den Stream ab.
Wenn das so aussäh
Client A sendet, Client A will "empfangen", Server sendet, Client B sendet, Server sendet, Client B will "empfangen"
Dann hätte Client B ja 2 Streams hintereinander weg zu bearbeiten oder? wie kann ich soetwas vermeiden?

Nachtrag: Sollte ich eine extra "schick mir Infos"-Packet-ID einrichten? also Client A schickt diese ID und Server schickt nur zu Client A....?

Aktuellsten Stream? Meinst du den aktuellen Zustand aller Clients?
Ein gut design'tes Spiel hat sowieso die meiste Logik auf der Serverseite - dh. die ganzen Daten sind dem Server bekannt; braucht Client A die Positiondaten von allen anderen (Spiel neu gejoint z.B.),
so kann das der Server ganz einfach bereitstellen!
Ich schätze mal, du hast es andersrum - unterlass das, solche Spiele sind am einfachsten zu "hacken"..
Mr_Emre_D
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 114
Erhaltene Danke: 14



BeitragVerfasst: Mo 15.07.13 23:28 
Hier, dürfte sich für Unerfahrene als nützlich erweisen...

[OT]
Kann man den sich wiederholenden Teil eigentlich eleganter lösen? (Generics?)
[/OT]
Einloggen, um Attachments anzusehen!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 16.07.13 07:24 
user profile iconMr_Emre_D hat folgendes geschrieben Zum zitierten Posting springen:
[OT]
Kann man den sich wiederholenden Teil eigentlich eleganter lösen? (Generics?)
[/OT]
ausblenden volle Höhe 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:
  TBitSet<T, K: record> = record
  private
    function GetBit(const AIndex: Integer): Boolean;
    procedure SetBit(const AIndex: Integer; const AValue: Boolean);
  public
    class operator implicit(const AValue: T): TBitSet<T, K>;
    class operator implicit(const AValue: TBitSet<T, K>): T;
    property Bit[const AIndex: Integer]: Boolean read GetBit write SetBit; default;
    case Boolean of
      True:   (Value: T);
      False:  (Lo: K; Hi: K);
  end;

  TWordBitSet = TBitSet<Word, Byte>;
  TLongIntBitSet = TBitSet<LongInt, TWordBitSet>;

// ...
function TBitSet<T, K>.GetBit(const AIndex: Integer): Boolean;
begin
  Result := PInteger(@Value)^ or (1 shl AIndex) > 0;
end;

class operator TBitSet<T, K>.implicit(const AValue: T): TBitSet<T, K>;
begin
  Result.Value := AValue;
end;

class operator TBitSet<T, K>.implicit(const AValue: TBitSet<T, K>): T;
begin
  Result := AValue.Value;
end;

procedure TBitSet<T, K>.SetBit(const AIndex: Integer; const AValue: Boolean);
var
  ByteIndex: Integer;
  BytePointer: PByte;
begin
  ByteIndex := AIndex div 8;
  if SizeOf(T) > ByteIndex then
  begin
    BytePointer := @PByteArray(@Value)^[ByteIndex];
    if AValue then
      BytePointer^ := BytePointer^ or (1 shl (AIndex mod 8))
    else
      BytePointer^ := BytePointer^ and not (1 shl (AIndex mod 8));
  end
  else
    raise Exception.Create('Invalid bit index!');
end;
Beispiel:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
var
  a: TLongIntBitSet;
begin
  a := $12345678;
  ShowMessage('$' + IntToHex(a.Lo.Hi, 8)); // $00000056
  a.Bit[12] := False;
  ShowMessage('$' + IntToHex(a.Lo.Hi, 8)); // $00000046
Effizienter ist aber eine andere Umsetzung...
IhopeonlyReader Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 600
Erhaltene Danke: 23


Delphi 7 PE
BeitragVerfasst: Di 16.07.13 11:01 
ich habe auch mal eine "Bit-Boolean"-Unit erstellt (basierend auf Byte und eine auf 32-bit), diese würden ebenfalls dafür geeinget sein oder?...


Und zu der Spielart:
Zur Übung verwende ich 2 Arten
- Vier gewinnt -> denke ich mal sollte nach jeder Änderung an alle geschickt werden
- 2D Egoshooter -> sollte entweder auf Abfrage oder in einem 66ms-Interval

was ist sinnvoller? Abfrage oder Interval

_________________
Sucht "neueres" Delphi :D
Wer nicht brauch was er hat, brauch auch nicht was er nicht hat!
Mr_Emre_D
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 114
Erhaltene Danke: 14



BeitragVerfasst: Di 16.07.13 11:25 
Zitat:

was ist sinnvoller? Abfrage oder Interval


Zum 2d-Shooter:
Warum nicht..?

Also du schickst im 66ms Interval die Pakete, sofern etwas verlangt wird, sonst niks (damit beseitigst du unnötigen traffic)
Am einfachsten ne Queue verwenden, wo du die zu abschickenden Pakete draufpusht, und im 66ms Interval abschickst!~