Avatar billede mr-kill Nybegynder
07. marts 2007 - 17:01 Der er 13 kommentarer og
1 løsning

LAN i 3D spil?

Hejsa

Jeg har lavet et 3D spil der kører i XNA framework. Spillet fungere fint og kører godt, men jeg vil gerne lave så man kan spille over lan i det. Jeg har tænkt lidt over det og kan ikke lige komme på hvordan man gør det bedst. Jeg har lavet et server-client system via TCP, som fungere fint til chat, men problemet kommer når jeg vil sende større ting som f.eks. en opdatering fra serveren når der spilles.

Den måde jeg bruger nu er hvor, når der trykkes start på serveren, så sender serveren den bane der er lavet til clienten, som så gør den klar. Bagefter og hver gang mit gameloop kører så sender jeg alle objecters posision til alle clienter og de skal så tegne dem. Det går alt for langsomt, men jeg kan ikke lige komme på hvordan det ellers skal gøres.

Når et object sendes, så er det kun typen og posisionen der sendes.

eksempel:
line += "o";
            foreach (Player a in game.players)
                line += "x" + a.Felt.X + "y" + a.Felt.Y + "z" + a.Felt.Z + "r" + a.Vinkel + "|";

Det modtager clienten så og laver om til et nyt player object og tegner det.

Det jeg mangler er altså en idé til hvordan det skal gøres. Hvis i ikke forstår hvad jeg mener, så sig til så poster jeg mere kode.

På forhånd tak!
Avatar billede mh6000 Nybegynder
08. marts 2007 - 08:31 #1
Hvad med at bruge UDP pakker til at sende posisionen.
Avatar billede bjering Nybegynder
08. marts 2007 - 08:33 #2
Sender du hele banen eller kun banens navn?

Hvis du sender det hele og den er forholdsvis stor, kan det evt være et buffer problem.

Ved self ikke hvordan du sender/modtager, men jeg gør altid sådan her med pakker.


4 byte, størrelse.
1 byte, opcode
Resten data.

Så modtager jeg en pakke og ved total størrelse af pakken.


Hvad angår ting der flytter sig sender jeg normalt en pakke per. Person.


F.eks, 1 flytter sig, så sender jeg en pakke med ny x,y,z osv per spiller.
Avatar billede bjering Nybegynder
08. marts 2007 - 08:36 #3
F.eks


Foreach......
//Skip din egen spiller
a.send(new playermove(x,y,z));

Hvis det giver mening..:)
Avatar billede mr-kill Nybegynder
08. marts 2007 - 09:17 #4
Tak for respons :)

Banen som jeg sender er meget lille så det gør ingen forskel hvis jeg kun sendte navnet.. Den skal jo også kun sendes én gang. Der er også nogle ting i banen som laves random, så serveren skal lave den så det bliver den samme bane alle clienter får. Jeg sender bare min opdatering som string: WriteLine. Gør det virklig en stor forskelv hvis jeg sendte det som byte istedet? Jeg kan ikke gøre så jeg sender et "player move" da spillere ikke er de eneste objecter der kan flytte sig, der er f.eks. gravity på næsten alle objecter.
Avatar billede bjering Nybegynder
08. marts 2007 - 19:45 #5
my bad, havde helt glemt at kigge ind igen.

min pakke ser f.eks sådan her ud

[0E 00] [01] [00 00 00 00 10 10 20 20 30 30 40]

dette siger pakkens totalle størelse er 14 bytes, 01 = flyt object

objectets id er 00000000, flyt til x 1010, y2020, z3030, angle 40

bare et eksempel.

jeg bruger disse pakker til ALT der kan flytte sig.

hver "ting" med AI, f.eks spillere, objecter osv har hver deres "knownObjects".

så, f.eks en spiller flytter sig..

foreach(Spiller a in this.KnownSpillere)
{
  a.send(new packet(alt data));
}

og så er der noget distance calculation til at fjerne og indsætte nye spiller (spillere behøver ikke objecter, for alle objecter har deres egen array af kendte spillere).

men det er lidt svært når jeg ikke ved hvor komplex du vil have det, og hvor komplex det er nødvendigt at være.
Avatar billede bjering Nybegynder
08. marts 2007 - 19:48 #6
det positive ved dette er (med mere) at du kun sender lidt pakker per spiller, pakkerne har en kontroleret størrelse.
Avatar billede mr-kill Nybegynder
08. marts 2007 - 21:56 #7
Jeg synes det lyder som en god løsning. Jeg prøvede pakker først, men kunne ikke få det til at virke. Jeg prøver lige igen i aften og ser om jeg kan få det til at virke nu..
Avatar billede mr-kill Nybegynder
08. marts 2007 - 22:19 #8
Jeg har lige et spørgsmål mere... Den måde jeg gør det på nu er at jeg kører dette i mine clienters loop:

line = sr.ReadLine();

if (line[0] == 'c') //chat
{
    callBack.AddChat(line.Substring(1));
}
else if (line[0] == 'i') //info 1
{
    callBack.MakeInfo(line.Substring(1), true);
}
else if (line[0] == 'j') //info 2
{
    callBack.MakeInfo(line.Substring(1), false);
}
else if (line[0] == 's') //start game
{
    callBack.game = new GameMaker();
    callBack.game.loadWorld();

    callBack.StartGame();
}
else if (line[0] == 'o') // opdater
{
    loadWorld(line);
}
else if (line[0] == 'p') // ping
{
    Send("p");
}

Hvordan skal jeg så gøre hvis jeg vil sende byte? Kan det ikke komme til at blive tolket som noget andet hvis nu en byte står for et bogstav? Jeg vil self. læse bytes direkte fra min NetworkStream og ikke igennem en StreamReader, men det er jo samme Stream? Jeg jo f.eks. også en ping der kører i sit eget loop og den kan vel godt smutte ind imellem to pakker og så ødelægge noget? Håber du haren idé der gør at jeg ikke skal skrive det hele om ;)

Det skal lige siges at det både er mit første 3D spil og mit første forsøg på at lave noget der kører via TCP, så undskyld hvis jeg ikke fatter det helt :P
Avatar billede Syska Mester
09. marts 2007 - 01:15 #9
Nej, ping komemr ikke ind ... da det er en ICMP pakke ... dvs hverken UDP eller TCP, så jeg er ret sikker på den ikke vil forstyre noget ...

// ouT
Avatar billede bjering Nybegynder
09. marts 2007 - 06:39 #10
jeg gætter på sr er din pakke læser.

byte OpCode = sr.ReadByte();

if(OpCode == 0x01)
{
  string Chat = sr.ReadString();
  callBack.AddChat(Chat);
}
else if(OpCode == 0x02)
{
    osv.....
}

det du vil bruge er nok en binaryreader, jeg smider lige lidt eksempler op på hvordan du kan gøre det lidt senere (med noget mere kode), arbejdet kalder :)
Avatar billede bjering Nybegynder
09. marts 2007 - 06:42 #11
min packet reader :

using System;
using System.IO;
using System.Collections.Generic;
using System.Text;

    public class PacketReader
    {
        private MemoryStream memStream;
        private BinaryReader binReader;

        private ushort packetLength;
        private byte packetType;

        public byte PacketType { get { return packetType; } }
        public ushort PacketSize { get { return packetLength; } }

        public PacketReader(byte[] packetBuffer)
        {
            //packetBuffer = Coder.DecodeString(packetBuffer, packetKey);
            memStream = new MemoryStream(packetBuffer);
            binReader = new BinaryReader(memStream);

            packetLength = Convert.ToUInt16( packetBuffer.Length );//binReader.ReadUInt16();
            packetType = binReader.ReadByte();
        }

        public byte ReadByte()
        {
            byte readByte;

            readByte = binReader.ReadByte();
            return readByte;
        }

        public sbyte ReadSByte()
        {
            sbyte readSByte;

            readSByte = binReader.ReadSByte();
            return readSByte;
        }

        public ushort ReadUShort()
        {
            ushort readUShort;

            readUShort = binReader.ReadUInt16();
            return readUShort;
        }

        public uint ReadUInt32()
        {
            uint readInt;

            readInt = binReader.ReadUInt32();
            return readInt;
        }

        public string ReadString()
        {
            byte[] readString = new byte[1024];
            byte c;
            int charCount = 0;

            // Read from the stream until \0 is read
            while ((c = binReader.ReadByte()) != 0x00)
            {
                try
                {
                    readString[charCount] = c;
                    charCount++;
                }
                catch (ArgumentOutOfRangeException)
                {
                    //Console.WriteLine("Received string was longer than 1024 byte!");
                    break;
                }
            }

            string returnString;
            try
            {
                returnString = Encoding.ASCII.GetString(readString, 0, charCount);
            }
            catch (Exception)
            {
                //Console.WriteLine("There was an error while converting data to a string!");
                returnString = " ";
            }
            return returnString;
        }
    }




og så bruges den

PacketReader read = new PacketReader(Data);

read.ReadByte();  (læser en byte, og hopper 1 byte frem i stream).
Avatar billede bjering Nybegynder
09. marts 2007 - 06:43 #12
forresten, glem denne

//packetBuffer = Coder.DecodeString(packetBuffer, packetKey);

bare noget jeg bruger, encryptions :)
Avatar billede mr-kill Nybegynder
09. marts 2007 - 16:26 #13
Mange tak for hjælpen...

Jeg har fået det til at virke. Der skulle dog en del omskrivning til ;)

bjering >> Smid et svar hvis du vil ha point :)
Avatar billede bjering Nybegynder
09. marts 2007 - 22:13 #14
okay :)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester