Multiplayer Project (Updated) by Nigel _Okgo25th Oct 2006 10:45
|
---|
Summary VR House Multiplayer Project with Movement (Updated) Description load an .X model into the code and then walk around in a multiplayer online environment Code ` This code was downloaded from The Game Creators ` It is reproduced here with full permission ` http://www.thegamecreators.com randomize timer() dim mpgot(10) dim zchat$(20) sync on : sync rate 32 backdrop on color backdrop 0 autocam off draw to front set text font "arial" set text size 12 set text transparent hide mouse color backdrop rgb(0,0,0) cls rgb(0,0,0) rem create stars image for i = 1 to 50 e = rnd(255) dot rnd(255),rnd(255),rgb(e,e,e) next f get image 1, 0, 0, 256, 256 for t=2 to 28 cls rgb(rnd(255),rnd(255),rnd(255)) get image t,0,0,256,256 next t rem Load House Model load object "objects/housemodel.x",1 set object 1,1,0,0,0,0,0,0 scale object 1,20000,20000,20000 rem scale object 1,20000,20000,20000 set object texture 1,1,1 position object 1,0,0,0 for t=1 to 10000 rem if limb exist(1,t) then texture limb 1,t,rnd(20)+1 next t rem Objects set light range 0, 100000 make object sphere 2,400 color object 2,rgb(255,255,0) position object 2,0,0,5000 texture object 2,2 cls rgb(0,0,0) rem Sky Box ink rgb(255,255,0),rgb(255,255,0) dim sx(100) dim sy(100) make object sphere 4, 40000, 20, 20 position object 4, camera position x(0), camera position y(0), camera position z(0) texture object 4, 1 scale object texture 4, 8, 8 set object 4, 1, 0, 0, 0, 0, 0, 0 rem Detection Sphere make object box 3,50,50,50 set camera range 1,20000 `give the camera a position point camera 0,0,0 position camera 0,0,0 `this is just an important variable o# = 0 Point camera 0,0,0 rem Position Characters for i = 0 to 7 make object cone 10+i,5 color object 10+i,rgb(i*30,0,210-(i*30)) xrotate object 10+i,90 fix object pivot 10+i rem make sure to hide player objects not in use hide object 10+i next i make object cone 8,5 color object 8,rgb(0,0,255) xrotate object 8,90 fix object pivot 8 position object 8,0,-50,500 goto start rem **** FIND THE TCP/IP CONNECTION TYPE rem sample code to setup a net connection perform checklist for net connections sync:sleep 50 netsel=0 nettotal=checklist quantity() for a = 1 to nettotal if checklist string$(a)="Internet TCP/IP Connection For DirectPlay" then netsel=a next a if netsel=0 then netsel=nettotal if netsel=0 then end chat$="" add$="IP Address Here" goto gotip rem **** USE WHATEVER ENTRY ROUTINE TO LET THE PLAYER SELECT THE IP ADDRESS rem now let the player enter the IP address they want to use ask4ip: ky$=entry$() if ky$="" then goto msync0 clear entry buffer if right$(ky$,1)=chr$(13) then add$=chat$:chat$="":goto gotip if right$(ky$,1)=chr$(8) then chat$=left$(chat$,len(chat$)-1):ky$="" if len(chat$)>30 then ky$="":goto msync0 chat$=chat$+ky$ ky$="" msync0: ink rgb(255,255,255),0 text 10,10,"Enter IP address to connect to: "+chat$+"_" sync goto ask4ip gotip: sleep 500 ky$="" rem now let the player select the name they want to use ask4name: ky$=entry$() if ky$="" then goto msync1 clear entry buffer if right$(ky$,1)=chr$(13) then goto gotname if right$(ky$,1)=chr$(8) then playername$=left$(playername$,len(playername$)-1):ky$="" if len(playername$)>10 then ky$="":goto msync1 playername$=playername$+ky$ ky$="" msync1: ink rgb(255,255,255),0 rem text 10,10,"IP Address selected: "+add$ text 10,20,"Enter the name you want to use: "+playername$+"_" sync goto ask4name gotname: rem **** ESTABLISH MULTIPLAYER CONNECTION for i = 0 to 5 text 10,50,"Establishing connection to: "+add$ sync next i set net connection netsel,add$ for i = 0 to 5 text 10,70,"Connection established..." sync next i rem **** NOW SCAN THE CONNECTION FOR EXISTING GAMES perform checklist for net sessions if checklist quantity()<1 then game$="None":goto nogame game$=checklist string$(1) nogame: host=0 if game$="None" then host=1:goto setashost rem if a game doesn't already exit, let the player host (host = 1) if game$="None" then goto setashost for i = 0 to 30 text 10,85,"Active session detected on this IP..." text 10,100,"Joining active session as client..." sync next i join net game 1,playername$ rem now send a greeting message that a new player has joined for i = 0 to 2 send net message string 0,"MESSAGE="+playername$+" has joined the game!" sync next i cls rem get general timer for exchange rate tmm=timer() oldtmm=tmm goto multimain setashost: rem if game$="None" then this section starts a new game on this IP address rem The 8 is the maximum number of players, 1 is for peer-to-peer rem client/server is another connection option which routes all data rem traffic through the host's computer instead of letting each player's rem system talk directly to every other player's system for i = 0 to 70 text 10,85,"No session detected on this IP..." text 10,100,"Creating multiplayer session as host..." sync next i create net game "Multiplayer Game #1",playername$,8,1 cls tmm=timer() oldtmm=tmm start: multimain: ink rgb(255,255,255),0 text 300,0,"Use Arrow keys to move around..." text 300,20,"Type text messages and press enter to send..." rem get a continuous list of all players text 10,10,"Current players:" perform checklist for net players totalplayers=checklist quantity() for i = 1 to totalplayers rem now save each player's unique ID number to the MPGOT array rem to help keep track of each specific player more accurately mpgot(i-1)=checklist value b(i) rem grab the name of each player in the session name$=checklist string$(i) rem if name on the list matches this player, get the unique ID number as rem we'll need it later for transmitting packets if name$=playername$ then playernum=checklist value b(i) rem display each name in the upper left of the screen text 10,10+(i*10),name$ next i rem display any messages in the chatbox queue for i = 0 to 13 text 10,200+(i*10),zchat$(i) next i rem rpackets is how many packets we're receiving this cycle, if we receive rem a packet, we want to skip sending a packet for this sync. this helps rem reduce packet overload and the resulting lag. rpackets=0 rem check for disconnect, exit as needed if net game lost()=1 then for i = 0 to 90:text 10,450,"Connection lost...":sync:next i:end rem search/scan for new messages keepchecking: get net message message$=net message string$() rem if no net message received, then leave scan routine if message$="" then goto scrappacket rem if a message is detected, apply it to the chatbox array line by line if left$(message$,8)<>"MESSAGE=" then goto notamessage mess$=right$(message$,len(message$)-8) rem if it is a duplicate message, just discard if zchat$(13)=mess$ then goto scrappacket rem if it's a new message, scroll the chatbox and add the message for i = 0 to 12:zchat$(i)=zchat$(i+1):next i zchat$(13)=mess$ rem add one to the received packets variable to indicate we got one rpackets=rpackets+1 goto baddata notamessage: rem **** DATA PACKET RECEIVE ROUTINE rem lets assign this data packet to a shorter variable, pc$ pc$=message$ rem DECODE MULTIPLAYER PACKET rem we'll use decod for the character position when analyzing the packet rem start at the first character decod=1 rem we'll use plyr$ for the player ID number rem mx$, my$, and mz$ will be used to store the player's position rem max$, may$, and maz$ will be used to store the player's rotation angles rem angle Z is included in this example, but isn't required rem reset variables to null values every time a packet is received plyr$="":mx$="":my$="":mz$="":max$="":may$="":maz$="" rem this routine will scan each packet character until the seperator rem character is encountered. Once the seperator is encountered, the rem variable has been stored and is ready for use. We'll use "|" as rem the seperator in our packet structure. The first step is rem to get the player ID number this packet is for: getplayernum: mpp$=mid$(pc$,decod) if mpp$="|" then goto setmvplyr else goto nomvplyr setmvplyr: decod=decod+1 rem we'll use mvplyr to indentify which player slot this packet is for mvplyr=-1 for i = 1 to totalplayers rem now compare the plyr$ result with the numbers we stored in the rem mpgot array. Find the one is matches, then identify who the rem packet is for using the mvplyr variable (will be in the 0-7 range) rem make sure to stick to string values, if you try to convert the rem plyr$ variable to a number using val(), you will encounter mismatches rem because the result can get reduced by several digits. You can convert rem large numbers stored in non-string variables to strings, but you rem can't go the other way without risking inaccurate results. if plyr$=str$(mpgot(i-1)) then mvplyr=i-1 next i rem since we received a data packet, add one to our rpackets counter rpackets=rpackets+1 rem now that we have the player number, continue analyzing the rest of the rem packet starting with the X position (saved to mx$) of the player goto getmx nomvplyr: plyr$=plyr$+mpp$ decod=decod+1 goto getplayernum getmx: mpp$=mid$(pc$,decod) if mpp$="|" then decod=decod+1:goto getmy mx$=mx$+mpp$ decod=decod+1 goto getmx getmy: mpp$=mid$(pc$,decod) if mpp$="|" then decod=decod+1:goto getmz my$=my$+mpp$ decod=decod+1 goto getmy getmz: mpp$=mid$(pc$,decod) if mpp$="|" then decod=decod+1:goto getmax mz$=mz$+mpp$ decod=decod+1 goto getmz getmax: mpp$=mid$(pc$,decod) if mpp$="|" then decod=decod+1:goto getmay max$=max$+mpp$ decod=decod+1 goto getmax getmay: mpp$=mid$(pc$,decod) if mpp$="|" then decod=decod+1:goto getmaz may$=may$+mpp$ decod=decod+1 goto getmay getmaz: mpp$=mid$(pc$,decod) if mpp$="|" then decod=decod+1:goto gotvariables maz$=maz$+mpp$ decod=decod+1 goto getmaz gotvariables: rem Now position the identified player's object where it needs to be if mvplyr=-1 then goto baddata mppx#=val(mx$) mppy#=val(my$) mppz#=val(mz$) mpmx#=val(max$) mpmy#=val(may$) mpmz#=val(maz$) position object 10+mvplyr,mppx#,mppy#,mppz# rotate object 10+mvplyr,mpmx#,mpmy#,mpmz#:scale object 10+mvplr,200,200,200 rem if we receive a packet for a player not currently visible, show object rem if a player leaves, you can detect that event and hide the object if object visible(10+mvplyr)=0 then show object 10+mvplyr baddata: rem then check for any remaining messages if net message exists()=1 then goto keepchecking scrappacket: rem monitor any chat messages the player enters to broadcast to other players text 10,400,">"+chat$+"_" ky$=entry$() if ky$="" then goto msync2 clear entry buffer if right$(ky$,1)=chr$(13) then chatb$=chat$:chat$="":broadcast=3:goto msync2 if right$(ky$,1)=chr$(8) then chat$=left$(chat$,len(chat$)-1):ky$="" if len(chat$)>55 then ky$="":goto msync2 chat$=chat$+ky$ ky$="" msync2: if broadcast=0 or rpackets>0 then goto skipbroad tmm=timer() if tmm<oldtmm+packetrate then goto nodatapacket rem send message packet 3 times to make sure it gets delivered send net message string 0,"MESSAGE="+chatb$ rem now on the last send, add this message to the chatbox as needed if broadcast=1 then for i = 0 to 12:zchat$(i)=zchat$(i+1):next i:zchat$(13)=chatb$ broadcast=broadcast-1 oldtmm=timer() goto nodatapacket skipbroad: rem **** SEND DATA PACKET ROUTINE rem if no message is being sent, send data packet instead rem you can also just send a data packet right after a message packet, rem just wait until after the next sync before doing so. rem this also runs a slightly higher risk of causing lag, but maintains rem gamestate data a little better at low exchange rates tmm=timer() rem if the packetrate time hasn't been reached yet, delay sending data rem to prevent overloading the connection and causing lag if tmm<oldtmm+packetrate or rpackets>0 then goto nodatapacket rem now generate a data packet with this player's position and rem rotation using the | character as a seperator for the variables pc$=str$(playernum)+"|" pc$=pc$+str$(object position x(8))+"|" pc$=pc$+str$(object position y(8))+"|" pc$=pc$+str$(object position z(8))+"|" pc$=pc$+str$(object angle x(8))+"|" pc$=pc$+str$(object angle y(8))+"|" pc$=pc$+str$(object angle z(8))+"|" send net message string 0,pc$ oldtmm=timer() nodatapacket: `move the object s#=1 a#=1 dist#=50 : ` distance camera sohuld be behind player height#=20 : ` height above player that camera should be smooth=10 : ` smoothing value if upkey() then move object 8,s# if downkey() then move object 8,-s# if leftkey() then yrotate object 8,wrapvalue(object angle y(8)-a#) if rightkey() then yrotate object 8,wrapvalue(object angle y(8)+a#) set camera to follow object position x(8),object position y(8),object position z(8),object angle y(8),dist#,height#,smooth,0 set object 8,1,0,0,0,0,0,0 rem recenter sky sphere position object 4,camera position x(),camera position y(),camera position z() rem now we're ready to update the gamestate and refresh the screen sync goto multimain |