Miksi tässä koodissani tapahtuu seuraava virhe:
Jos kolme tai useampi pelaaja liittyy peliini, ja poistuu satunnaisessa järjestyksessä sovellus kaatuu. Uskoisin, että ongelma sijaitsenee pelaajan luonti ja/tai poisto -tapahtumissa.
Pelaaja on liittynyt:
procedure TGame.addPlayer(Player: TWSocketClient); begin inc(loginCount); inc(playerCount); //increase playercount setLength(Players, PlayerCount + 1); Players[playercount] := TPlayer.Create; // And then create new Players[playerCount].socket := Player; // create identifier to player. Players[playerCount].socket.OnDataAvailable := Players[playerCount].ReceiveData; Players[playerCount].NthLogger := loginCount; Players[playerCount].NickName := ''; Players[playerCount].PassWord := ''; Player.SendStr(SendLine('Please enter you nickname and something else seperated by space.')); Player.SendStr(SendLine('It may not contain whitespaces.')); end;
Ja kun pelaaja poistuu:
procedure TGame.removePlayer(Player: TWSocketClient); var i : integer; begin // loop through players until match is found for i := 0 to playerCount do begin if (Player = Players[i].socket) then begin // Because we are using dynamic player handle handling, // we kick list's last player to currently opened place, and destroy last place. Players[i] := Players[playerCount]; Players[playerCount].Free; inc(playerCount, -1); // decrease playercount if (playerCount > -1) then // if we try to set array length of zarro, exception is thrown. begin setLength(Players, playerCount + 1); // Should this be only "setLength(Players, playerCount);" ?? end; exit; end; end; end;
Varsinainen ongelmasi on poistumisessa. Vapautat väärän henkilön. Teet nyt näin (A pitäisi potkia ja B on taulun viimeinen, ehkä säilytettävä):
var A, B: TPelaaja; A := B; {A:n luulet potkivasi.} B.Free; {A = B, joten myös A.Free;}
Pitäisi tehdä näin:
var A, B: TPelaaja; A.Free; {A potkitaan.} A := B; {Siirretään B:stä A:han, jolloin B:tä ei tarvitse enää huomioida.}
Kyse ei siis ole taulukon paikoista vaan niistä olioista, joihin taulukon paikat osoittavat. Jos A := B, niin A.Free on sama kuin B.Free.
Kommenteistasi näkyy, ettet ole aivan varma taulukon käytöstä. Kun se kerran alkaa nollasta, kannattaisi myös tehdä koodi sen mukaan:
procedure Liity(...); var PlayerNum: Integer; begin PlayerNum := PlayerCount; Inc(PlayerCount); { Pelaajia on yksi enemmän. } SetLength(Taulu, PlayerCount); {PlayerNum + 1; [0 .. PlayerNum];} Taulu[PlayerNum].X = Y; { Yms. } end;
procedure Poistu(...); var PlayerNum, LastPlayerNum: Integer; begin LastPlayerNum := PlayerCount - 1; { Edellisen perusteella viimeinen pelaaja } for PlayerNum := 0 to LastPlayerNum do begin if SamaPelaaja(Taulu[PlayerNum], Poistettava) then begin Taulu[PlayerNum].Free; {Poistetaan poistettava} Taulu[PlayerNum] := Taulu[LastPlayerNum]; {Laitetaan viimeinen tilalle} Dec(PlayerCount); {Taulua yhtä lyhemmäksi} SetLength(Taulu, PlayerCount); end end end;
for i := 0 to playerCount do
Yleensä lista käydään läpi joko 0..n-1 tai 1..n. Selkeyttää ajatuksena mutta tuokin voi toimia jos periaatetta käyttää läpi ohjelman. Playercount 3 tarkoittaisi että pelaajia on 4 tuollaisenaan.
Jos käytät n-1 systeemiä, voit myös käyttää
setLength(Players, playerCount); // (ilman +1)
inc(playerCount, -1); on muutekseen sama kuin dec(playerCount);
Ja sitten pahin... looppi joka poistaa elementtejä, täytyy käydä läpi käänteisessä järjestyksessä
for i := 0 to playerCount do muuttuu for i := playerCount downto 0 do
jos näin ei tee, looppi saattaa käsitellä aina vanhaan playerCount asti, ja skippaa viimeisen elementin, se kun aina siirtyy nykyisen tilalle.
edit: No tuossa tapauksessa toimii kyllä noinkin kun lopetat koko aliohjelman tuon 1 poiston jälkeen :p
User137 kirjoitti:
No tuossa tapauksessa toimii kyllä noinkin kun lopetat koko aliohjelman tuon 1 poiston jälkeen :p
Ei tuossa kai ole tarkoitus poistaakaan kuin se yksi, joka potkitaan t. ilmoittaa palvelimelle poistumisestaan. :) Jos olisi tarkoitus kaikki potkia, niin tuskinpa kukaan siinä välissä paikkaisi listaa, kaikille vain Free ja lopuksi merkitään määräksi nolla.
Kiitos vastauksista, pitääpä heti kotiin päästyä koittaa... Oliko koodissa muuta mikä ei olisi järkeenkäypää? Itse en ainakaan näe, mutta kun sitä tulee sokeaksi omalle koodille.
Jep. Hienosti toimii nyt, kiitos avusta. Pitää vielä miettiä tuota taulukonkäsittely hässäkkää, että tarvitseeko toimivaa korjata. Koska se kuitenkin toimii.
Aihe on jo aika vanha, joten et voi enää vastata siihen.