Mam taką oto klasę:
unit connections;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, blcksock, Ships, Fields, Worlds;
Type
TConnection = class
private
server : TTCPBlockSocket;
server_cl : TTCPBlockSocket;
client : TTCPBlockSocket;
IP, PortNr : String;
IsServer : Boolean;
public
constructor Create(IPc, portc : string; p : byte);
function Connect : boolean;
procedure SendData(var World : TWorld);
procedure RecvData(var World : TWorld);
procedure SendCheck(check : Byte);
function RecvCheck : Byte;
function Waiting : Boolean;
procedure Ready;
destructor ShutDown;
end;
implementation
{=== Klasa TConnection ========================================================}
constructor TConnection.Create(IPc,portc : string; p : byte);
begin
case p of
1 : IsServer := true;
2 : IsServer := false;
end;
IP := IPc;
PortNr := portc;
if IsServer Then
Begin
Server := TTCPBlockSocket.Create;
Server.Bind (IP,PortNr);
Server.Listen;
Server_cl := TTCPBlockSocket.Create;
end
else
client := TTCPBlockSocket.Create;
end;
{------------------------------------------------------------------------------}
function TConnection.Connect : boolean;
var
Error : Integer;
begin
Error := 100;
If IsServer Then
begin
If Server.CanRead (1) Then
begin
Server_cl.Socket := Server.Accept;
Server.CloseSocket;
Error := Server.LastError;
end;
end
else
begin
Client.Connect (IP,PortNr);
Error := Client.LastError;
end;
If Error = 0 Then result := true
else result := false;
end;
{------------------------------------------------------------------------------}
procedure TConnection.SendData(var World : TWorld);
begin
{*** Kod nieistotny ***}
end;
{------------------------------------------------------------------------------}
procedure TConnection.RecvData(var World : TWorld);
begin
{*** Kod nieistotny ***}
end;
{------------------------------------------------------------------------------}
procedure TConnection.SendCheck(check : Byte);
begin
{*** Kod nieistotny ***}
end;
{------------------------------------------------------------------------------}
function TConnection.RecvCheck : Byte;
begin
{*** Kod nieistotny ***}
end;
{------------------------------------------------------------------------------}
function TConnection.Waiting : Boolean;
begin
{*** Kod nieistotny ***}
end;
{------------------------------------------------------------------------------}
procedure TConnection.Ready;
begin
{*** Kod nieistotny ***}
end;
{------------------------------------------------------------------------------}
destructor TConnection.ShutDown;
begin
If IsServer then server_cl.CloseSocket
else client.CloseSocket;
end;
{==============================================================================}
end.
Używam jej w swojej grze by dwóch graczy mogło grać ze sobą. Testowałem sobie jak działa połączenie i przerywanie oczekiwania na połączenie. I samo przerwanie oczekiwania działa bez zarzutu. Jednak gdy tworzę nową grę jako serwer (patrz konstruktor) następnie przerwę oczekiwanie na połączenie (patrz destruktor) to klient i tak się podłączy i wystartuje. Nie wiem czemu tak się dzieje. Może mi to ktoś wyjaśnić?
Poniżej podaję 2 procedury w których pokazane jest jak wykorzystuję klasę:
procedure TForm1.FormKeyPress(Sender: TObject; var Key: char);
var
maxy : Byte;
begin
If not EndTurn Then
begin
if MoveMode or AttackMode or PutMine or DestroyMine then
begin
case Key of
'w' : if y2 > 0 then Dec(y2);
's' : if y2 < 17 then Inc(y2);
'a' : if x2 > 0 then Dec(x2);
'd' : if x2 < 11 then Inc(x2);
#27 : begin
MoveMode := false;
AttackMode := false;
PutMine := false;
DestroyMine := false;
end;
#13 : begin
If MoveMode Then
begin
If World.Move(x1, y1, x2, y2) Then
begin
MoveMode := False;
MoveDone := True;
end;
end
else If AttackMode Then
begin
if World.Attack (x1, y1, x2, y2) Then
Begin
AttackMode := False;
AttackDone := True;
end;
end
else If PutMine Then
begin
If World.PutMine(x1, y1, x2, y2) then PutMine := False
end
else If DestroyMine Then
begin
If World.DestroyMine(x1, y1, x2, y2) then DestroyMine := False
end;
end;
end;
end
else if PutMode Then
begin
case Key of
'w' : if y1 > 0 then Dec(y1);
's' : if y1 < 17 then Inc(y1);
'a' : if x1 > 0 then Dec(x1);
'd' : if x1 < 11 then Inc(x1);
#13 : begin
case World.GetPlayer of
1 : begin
If y1 <= 3 then
If World.PutShip (x1, y1, ShipPut) Then Inc(ShipPut);
end;
2 : begin
If y1 >= 14 then
If World.PutShip (x1, y1, ShipPut) Then Inc(ShipPut);
end;
end;
end;
end;
end
else If MainMenu Then
begin
case Key of
'1' : my := 0;
'2' : my := 1;
'3' : my := 2;
'w' : If my > 0 then Dec(my);
's' : If my < 2 then Inc(my);
#13 : begin
case my of
0 : begin
MainMenu := False;
GameMenu := True;
end;
1 : begin
OptionsMenu := True;
MainMenu := False;
end;
2 : begin
Form1.Close;
end;
end;
end;
end;
end
else if OptionsMenu then
begin
case Key of
'1' : my := 0;
'2' : my := 1;
'w' : If my > 0 then Dec(my);
's' : If my < 1 then Inc(my);
#13 : begin
case my of
0 : begin
OptionsMenu := False;
IPChange := True;
end;
1 : begin
OptionsMenu := False;
MainMenu := True;
end;
end;
end;
end;
end
else if IPChange Then
begin
case Key of
'0' : IP := IP + Key;
'1' : IP := IP + Key;
'2' : IP := IP + Key;
'3' : IP := IP + Key;
'4' : IP := IP + Key;
'5' : IP := IP + Key;
'6' : IP := IP + Key;
'7' : IP := IP + Key;
'8' : IP := IP + Key;
'9' : IP := IP + Key;
'.' : IP := IP + Key;
'c' : IP := '';
end;
If Key = #13 Then
begin
IPChange := False;
OptionsMenu := False;
PortChange := True;
end;
end
else if PortChange Then
begin
case Key of
'0' : Port := Port + Key;
'1' : Port := Port + Key;
'2' : Port := Port + Key;
'3' : Port := Port + Key;
'4' : Port := Port + Key;
'5' : Port := Port + Key;
'6' : Port := Port + Key;
'7' : Port := Port + Key;
'8' : Port := Port + Key;
'9' : Port := Port + Key;
'c' : Port := '';
end;
If Key = #13 Then
begin
IPChange := False;
OptionsMenu := False;
PortChange := False;
MainMenu := True;
end;
end
else If GameMenu Then
begin
case Key of
'1' : my := 0;
'2' : my := 1;
'3' : my := 2;
'w' : If my > 0 then Dec(my);
's' : If my < 2 then Inc(my);
#13 : begin
case my of
0 : begin
World := TWorld.Create(1);
Connection := TConnection.Create (IP, Port, 1);
Connect := 1;
EndTurn := False;
GameMenu := False;
end;
1 : begin
World := TWorld.Create(2);
Connection := TConnection.Create (IP, Port, 2);
Connect := 1;
EndTurn := False;;
GameMenu := False;
end;
2 : begin
GameMenu := False;
MainMenu := True;
end;
end;
end;
end;
end
else If ShipMenu Then
begin
case World.ShipType(x1, y1) of
Pancernik : maxy := 2;
Rakietowy : maxy := 2;
Krazownik : maxy := 2;
Niszczyciel : maxy := 2;
Podwodny : maxy := 2;
Eskortowiec : maxy := 2;
Tralowiec : maxy := 4;
Desantowy : maxy := 1;
Bateria : maxy := 1;
Mina : maxy := 0;
end;
case Key of
'1' : If 0 <= maxy Then my := 0;
'2' : If 1 <= maxy Then my := 1;
'3' : If 2 <= maxy Then my := 2;
'4' : If 3 <= maxy Then my := 3;
'5' : If 4 <= maxy Then my := 4;
'w' : If my > 0 then Dec(my);
's' : If my < maxy then Inc(my);
#27 : ShipMenu := False;
#13 : Begin
If (my = 0) and
(World.ShipType(x1, y1) <> Desantowy) and
(World.ShipType(x1, y1) <> Mina) and
(not AttackDone) Then
begin
AttackMode := True;
ShipMenu := False;
x2 := x1;
y2 := y1;
end
else if (my = 1) and
(World.ShipType(x1, y1) <> Desantowy) and
(World.ShipType(x1, y1) <> Bateria) and
(World.ShipType(x1, y1) <> Mina) and
(not MoveDone) Then
begin
MoveMode := True;
ShipMenu := False;
x2 := x1;
y2 := y1;
end
else if (my = 0) and (World.ShipType(x1, y1) = Desantowy) and (not MoveDone) Then
begin
MoveMode := True;
ShipMenu := False;
x2 := x1;
y2 := y1;
end
else if (my = 0) and (World.ShipType(x1, y1) = Bateria) and (not AttackDone) Then
begin
AttackMode := True;
ShipMenu := False;
x2 := x1;
y2 := y1;
end
else if (my = 0) and (World.ShipType(x1, y1) = Mina) Then
ShipMenu := False
else if (my = 1) and
(World.ShipType(x1, y1) = Desantowy) and
(World.ShipType(x1, y1) = Bateria) Then
ShipMenu := False
else if (my = 2) and (World.ShipType(x1, y1) = Tralowiec) Then
Begin
ShipMenu := False;
PutMine := True;
x2 := x1;
y2 := y1;
end
else if (my = 3) and (World.ShipType(x1, y1) = Tralowiec) Then
Begin
ShipMenu := False;
DestroyMine := True;
x2 := x1;
y2 := y1;
end
else if (my = 4) and (World.ShipType(x1, y1) = Tralowiec) Then
ShipMenu := False;
end;
end;
end
else If connect = 1 Then
begin
If Key = #27 Then
Begin
PutMode := False;
AttackMode := False;
MoveMode := False;
PutMine := False;
DestroyMine := False;
AttackDone := False;
MoveDone := False;
ShipMenu := False;
Win := False;
Loose := false;
Connect := 0;
GameRunning := False;
MainMenu := True;
OptionsMenu := False;
IPChange := False;
PortChange := False;
GameMenu := False;
ShipPut := 0;
World.Destroy;
Connection.Shutdown;
end;
end
else
begin
case Key of
'w' : if y1 > 0 then Dec(y1);
's' : if y1 < 17 then Inc(y1);
'a' : if x1 > 0 then Dec(x1);
'd' : if x1 < 11 then Inc(x1);
'k' : begin
check := World.Check;
Connection.Ready;
Connection.SendCheck(check);
Connection.SendData(World);
EndTurn := true;
If Check = World.GetPlayer Then
begin
Win := True;
Loose := False;
end
else If (Check <> World.GetPlayer) and (check <> 0) then
begin
Win := False;
Loose := True;
end;
end;
#13 : Begin
If (World.ShipType(x1, y1) <> Nothing) and
(World.GetShipPlayer(x1, y1) = World.GetPlayer) and
(not PutMode) Then ShipMenu := True;
end;
end;
end;
If ShipPut = 30 Then PutMode := False;
end;
If Loose or win Then
begin
PutMode := False;
AttackMode := False;
MoveMode := False;
PutMine := False;
DestroyMine := False;
AttackDone := False;
MoveDone := False;
ShipMenu := False;
Win := False;
Loose := False;
Connect := 0;
GameRunning := False;
MainMenu := True;
OptionsMenu := False;
IPChange := False;
PortChange := False;
GameMenu := False;
EndTurn := False;
World.Destroy;
Connection.ShutDown;
ShipPut := 0;
end;
end;
oraz
procedure TForm1.OpenGLControl1Paint(Sender: TObject);
begin
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, Width, Height, 0, 0, 0);
glMatrixMode(GL_MODELVIEW);
glDisable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT);
If not GEngine.TextureGen then GEngine.InitTxt;
If (GameRunning) and (Connect = 2) then
Begin
GEngine.DrawGame(World);
GEngine.DrawRect(x1, y1);
GEngine.DrawInfo(x1, y1, World);
If AttackMode or PutMine Then
Begin
GEngine.DrawAttackRect(x2, y2);
GEngine.DrawInfo(x2, y2, World);
end;
If MoveMode or DestroyMine Then
Begin
GEngine.DrawMoveRect(x2, y2);
GEngine.DrawInfo(x2, y2, World);
end;
end;
If MainMenu Then
begin
GEngine.DrawMainMenu;
GEngine.DrawMenuRect(my);
end;
If OptionsMenu Then
begin
GEngine.DrawOptions;
GEngine.DrawMenuRect(my);
end;
If IPChange Then
begin
GEngine.DrawIPChange(IP);
end;
If PortChange Then
begin
GEngine.DrawPortChange(Port);
end;
If GameMenu Then
begin
GEngine.DrawGameMenu;
GEngine.DrawMenuRect(my);
end;
If ShipMenu Then
begin
GEngine.DrawShipMenu(World.ShipType(x1, y1));
GEngine.DrawShipMenuRect(my);
end;
If EndTurn Then
Begin
GEngine.DrawMessage('Tura drugiego gracza');
If Connection.Waiting then
Begin
Check := Connection.RecvCheck;
If Check = 0 then
Begin
Connection.RecvData(World);
EndTurn := false;
AttackDone := False;
MoveDone := False;
end
else If Check = World.GetPlayer Then
begin
Win := True;
Loose := False;
end
else If (Check <> World.GetPlayer) and (check <> 0) then
begin
Win := False;
Loose := True;
end;
end;
end;
If Win then GEngine.DrawMessage('WYGRALES!!!');
If Loose then GEngine.DrawMessage('PRZEGRALES!!!');
If Connect = 1 Then
Begin
GEngine.DrawMessage('Oczekiwanie na polaczenie...');
If Connection.Connect Then
Begin
Connect := 2;
GameMenu := False;
GameRunning := True;
PutMode := True;
If World.GetPlayer = 2 Then EndTurn := True;
end;
end;
OpenGLControl1.SwapBuffers;
end;
Co niektórzy stwierdzą, że kod woła o pomstę do nieba. Ale jest on w fazie testów i optymalizacji więc to nie jest jego końcowa forma :)