;====== FPSNet: A NETWORKED FIRST PERSON SHOOTER EXAMPLE ==================
;====== UTILIZING ONLY BUILT IN BLITZ3D FEATURES ==========================
;====== A CODESKETCH BY JEREMY ALESSI =====================================
;====== THANKS MARK SIBLY FOR GNET ========================================
;====== WASD OR CURSORS MOVE, MOUSE LOOKS, LEFT MOUSE BUTTON SHOOTS =======
;====== SPACE BAR OR 0 ON NUMPAD JUMPS ====================================
;====== PRESS 2 TO UNLOCK MOUSE FROM CENTER (USEFUL TO PLAY ===============
;====== AND ALSO BE ABLE TO MULTITASK IF NEED BE) PRESS 1 TO RELOCK =======
;====== MOUSE BACK TO CENTER OF SCREEN ====================================
;====== YEAH EVERYONE HAS THE SOURCE ... DON'T CHEAT! =====================
;====== INCLUDES ==========================================================
;Include "gnet_inc.bb" This is included at the bottom of this source!
;==========================================================================
;====== GRAPHICS ==========================================================
Graphics3D(640, 480, 16, 2)
SetBuffer BackBuffer()
HidePointer
;==========================================================================
;====== COLLISIONS ========================================================
Global BODY = 1
Global SCENE = 2
Collisions(BODY,SCENE, 2, 2)
Collisions(BODY,BODY, 2, 2)
;==========================================================================
;====== GLOBALS ===========================================================
Global gameState$ = "Title Screen"
;Mousehit Vars
Global mb1pressed, mb2pressed
;Keyhit Vars
Global upKeyPressed, downKeyPressed, leftKeyPressed, rightKeyPressed, enterKeyPressed, spaceKeyPressed
;Font Vars
Global font, bigFont
;Menu Var
Global menuCount
;Server Vars
Global serverCount
Global serverPointer
;Local Player Network Vars
Global localPlayerName$, localPlayerPointer
;Scenery Vars
Global level,copySprite
;Camera Var
Global camera
;Player Gameplay Vars
Global health#, shot, shotTimer#, positionUpdateTimer#, serverRefreshTimer#, hosting
Global vY#,centerMouse = True
;==========================================================================
;====== INCOMING ==========================================================
Dim incoming$(100)
;==========================================================================
;====== TYPES =============================================================
Type Player
Field iD, name$, mesh[10], score
End Type
Type particle
Field mesh, name$, alpha#
Field vX#, vY#, vZ#
End Type
;==========================================================================
;====== INITIAL SETUP =====================================================
Setup("Title Screen")
;==========================================================================
;==========================================================================
.Main
;====== RUN ===============================================================
period=1000 / 30
tweentime = MilliSecs()-period
While 1
;====== CALCULATE TWEEN ===================================================
Repeat
elapsed = MilliSecs() - tweentime
Until elapsed
ticks = elapsed/period
tween# = Float(elapsed Mod period) / Float(period)
;==========================================================================
;====== MAIN LOOP =========================================================
For k=1 To ticks
tweentime = tweentime+period
If k = ticks Then CaptureWorld
If KeyDown(1)
If Not GNET_RemoveServer("FPSNet")
If hosting = True
RuntimeError "Failed to remove server"
EndIf
EndIf
ClearWorld()
End
EndIf
UpdateLogic()
UpdateWorld
Next
RenderWorld(tween#)
Draw()
Flip
Wend
;===========================================================================
;====== UPDATE LOGIC =======================================================
Function UpdateLogic()
Select gameState$
Case "Title Screen"
UpdateInput()
UpdateTitleScreen()
Case "Game"
UpdateLights()
UpdateCamera()
UpdatePlayerMovement()
UpdateParticles()
UpdateNetwork()
UpdateCenterMouse()
End Select
End Function
;===========================================================================
;====== DRAW ===============================================================
Function Draw()
Select gameState$
Case "Title Screen"
DrawTitleScreen()
Case "Game"
DrawGamePlay()
End Select
End Function
;===========================================================================
;====== UPDATE INPUT =======================================================
Function UpdateInput()
mb1pressed = MouseHit(1)
mb2pressed = MouseHit(2)
upKeyPressed = KeyHit(17) Or KeyHit(200)
downKeyPressed = KeyHit(31) Or KeyHit(208)
leftKeyPressed = KeyHit(30) Or KeyHit(203)
rightKeyPressed = KeyHit(32) Or KeyHit(205)
enterKeyPressed = KeyHit(28)
spaceKeyPressed = KeyHit(57)
End Function
;===========================================================================
;====== UPDATE CENTER MOUSE ================================================
Function UpdateCenterMouse()
If centerMouse = True
MoveMouse(CorrectX(320), CorrectY(240))
EndIf
If KeyHit(2)
centerMouse = True
EndIf
If KeyHit(3)
centerMouse = False
EndIf
End Function
;===========================================================================
;====== UPDATE TITLE SCREEN ================================================
Function UpdateTitleScreen()
If upKeyPressed And menuCount > 0
menuCount = menuCount - 1
EndIf
If downKeyPressed And menuCount < serverCount - 1
menuCount = menuCount + 1
EndIf
If enterKeyPressed
gns.GNET_Server = Object.GNET_Server(serverPointer)
If JoinNetGame(gns\server$, gns\ip$)
FlushKeys
Color(255,0,0)
Locate(200,130)
localPlayerName$ = Input("Name - ")
Delay(500)
FlushKeys
p.Player = New Player
localPlayerPointer = Handle(p.Player)
p\iD = CreateNetPlayer(localPlayerName$)
Setup("Game")
hosting = False
EndIf
EndIf
If spaceKeyPressed
FlushKeys
Color(255,0,0)
Locate(200,130)
localPlayerName$ = Input("Name - ")
Delay(500)
FlushKeys
If HostNetGame(localPlayerName$) = 2
If GNET_AddServer("FPSNet", localPlayerName$)
p.Player = New Player
localPlayerPointer = Handle(p.Player)
p\iD = CreateNetPlayer(localPlayerName$)
Setup("Game")
hosting = True
serverRefreshTimer# = MilliSecs()
Else
RuntimeError("Failed to Add Server!")
EndIf
Else
RuntimeError("Failed to Create Net Game!")
EndIf
EndIf
End Function
;===========================================================================
;====== UPDATE PLAYER MOVEMENT =============================================
Function UpdatePlayerMovement()
p.Player = Object.Player(localPlayerPointer)
If KeyDown(17) Or KeyDown(200)
MoveEntity(p\mesh[1], 0, 0, .5)
EndIf
If KeyDown(31) Or KeyDown(208)
MoveEntity(p\mesh[1], 0, 0, -.5)
EndIf
If KeyDown(30) Or KeyDown(203)
MoveEntity(p\mesh[1], -.5, 0, 0)
EndIf
If KeyDown(32) Or KeyDown(205)
MoveEntity(p\mesh[1], .5, 0, 0)
EndIf
numColls = CountCollisions(p\mesh[1])
If (KeyDown(57) Or KeyDown(82)) And numColls > 0
vY# = .2
TranslateEntity(p\mesh[1],0, vY#, 0)
EndIf
If numColls = 0
TranslateEntity(p\mesh[1],0, vY#, 0)
vY# = vY# - .01
EndIf
RotateEntity(p\mesh[1], 0, EntityYaw(p\mesh[1]) - MouseXSpeed(), 0)
End Function
;===========================================================================
;====== UPDATE LIGHTS ======================================================
Function UpdateLights()
TurnEntity(FindChild(level,"Light Pivot"), 0, 10, 0)
End Function
;===========================================================================
;====== UPDATE CAMERA ======================================================
Function UpdateCamera()
shot = 0
If MouseDown(1)
If shotTimer# + 200 < MilliSecs()
shot = CameraPick(camera, CorrectX(320), CorrectY(240))
shotTimer# = MilliSecs()
If shot
CreateSomeParticles(PickedX(), PickedY(), PickedZ(), 50, 50, 50, 10)
p.Player = Object.Player(localPlayerPointer)
SendNetMsg(4,PickedX() + "," + PickedY() + "," + PickedZ() + "-",p\iD,0,0)
EndIf
EndIf
EndIf
RotateEntity(camera,EntityPitch(camera) + MouseYSpeed(),0,0)
If EntityPitch(camera) > 90
RotateEntity(camera, 90, 0, 0)
EndIf
If EntityPitch(camera) < - 90
RotateEntity(camera, -90, 0, 0)
EndIf
End Function
;===========================================================================
;====== UPDATE NETWORK =====================================================
Function UpdateNetwork()
While RecvNetMsg()
Select NetMsgType()
Case 1
For p.Player = Each Player
If p\iD = NetMsgFrom()
DecodeIncomingMessage(NetMsgData$())
PositionEntity(p\mesh[1], incoming$(1), incoming$(2), incoming$(3))
RotateEntity(p\mesh[1], incoming$(4), incoming$(5), 0)
If incoming$(6) <> ""
p\score = incoming$(6)
EndIf
EndIf
Next
Case 2
p.Player = Object.Player(localPlayerPointer)
CreateSomeParticles(EntityX(p\mesh[1]), EntityY(p\mesh[1]), EntityZ(p\mesh[1]), 255, 0, 0, 10)
health = health - 5
If health <= 0
health = 100
PositionEntity(p\mesh[1],5,1,Rand(0, 50))
SendNetMsg(3, "1", p\iD, NetMsgFrom(), 1)
CreateSomeParticles(EntityX(p\mesh[1]), EntityY(p\mesh[1]), EntityZ(p\mesh[1]), 255, 0, 0, 100)
SendNetMsg(5, "1",p\iD, 0, 0)
EndIf
Case 3
p.Player = Object.Player(localPlayerPointer)
p\score = p\score + 1
Case 4
DecodeIncomingMessage(NetMsgData$())
CreateSomeParticles(incoming$(1), incoming$(2), incoming$(3), 50, 50, 50, 10)
Case 5
For p.Player = Each Player
If p\iD = NetMsgFrom()
CreateSomeParticles(EntityX(p\mesh[1]), EntityY(p\mesh[1]), EntityZ(p\mesh[1]), 255, 0, 0, 100)
EndIf
Next
Case 100
p.Player = New Player
p\iD = NetMsgFrom()
p\mesh[1] = CreateSphere(8)
p\name$ = NetPlayerName$(p\iD)
EntityColor(p\mesh[1], 0, 255, 0)
PositionEntity(p\mesh[1], 5, 1.5, Rand(50,100))
EntityType(p\mesh[1],BODY)
EntityRadius(p\mesh[1], 1.5)
EntityPickMode(p\mesh[1], 2)
p\mesh[2] = CreateCube(p\mesh[1])
PositionEntity(p\mesh[2], 1, -.5, 1)
ScaleEntity(p\mesh[2], .1, .1, .4)
EntityColor(p\mesh[2], 20, 20, 20)
Case 101
For p.Player = Each Player
If p\iD = NetMsgFrom()
FreeEntity(p\mesh[1])
Delete(p)
EndIf
Next
Case 102
GNET_AddServer("FPSNet", localPlayerName$)
hosting = True
End Select
Wend
p.Player = Object.Player(localPlayerPointer)
If positionUpdateTimer# + 50 < MilliSecs()
SendNetMsg(1, EntityX(p\mesh[1]) + "," + EntityY(p\mesh[1]) + "," + EntityZ(p\mesh[1]) + "," + EntityPitch(camera) + "," + EntityYaw(p\mesh[1]) + "," + p\score + "-", p\iD, 0, 0)
positionUpdateTimer# = MilliSecs()
EndIf
For op.Player = Each Player
If shot = op\mesh[1]
CreateSomeParticles(PickedX(), PickedY(), PickedZ(), 255, 0, 0, 10)
SendNetMsg(2, "", p\iD, op\iD, 0)
EndIf
Next
If hosting = True
If serverRefreshTimer# + 250000 < MilliSecs()
GNET_RefreshServer( "FPSNet",localPlayerName$ )
serverRefreshTimer# = MilliSecs()
EndIf
EndIf
End Function
;===========================================================================
;====== UPDATE PARTICLES ===================================================
Function UpdateParticles()
For p.particle = Each particle
If p\alpha# <= 0
FreeEntity(p\mesh)
Delete(p)
Else
p\vY# = p\vY# - .01
TranslateEntity(p\mesh,p\vX#, p\vY#, p\vZ#)
p\alpha# = p\alpha# - .02
EntityAlpha(p\mesh, p\alpha#)
EndIf
Next
End Function
;===========================================================================
;====== DRAW TITLE SCREEN ==================================================
Function DrawTitleScreen()
Cls
FPSNetText(font, 320, 0, String$("+",80), 1, 1, 100, 100, 100)
FPSNetText(font, 320, 480, String$("+",80), 1, 1, 100, 100, 100)
For i = 0 To 640 Step 640
For j = 10 To 470 Step 10
FPSNetText(font, i, j, "+", 1, 1, 100, 100, 100)
Next
Next
FPSNetText(bigFont, 320, 30, "FPSNet:", 1, 1, 255, 0, 0)
FPSNetText(font, 320, 60, "A NETWORKED First Person Shooter Example", 1, 1, 100, 100, 100)
FPSNetText(font, 320, 80, "Press Up/Down to Select a Game to Join!", 1, 1, 100, 100, 100)
FPSNetText(font, 320, 100, "Press Space to Host a New Game!", 1, 1, 100, 100, 100)
FPSNetText(font, 320, 120, "Games In Progress:" , 1, 1, 200, 255, 150)
serverCount = 0
For gns.GNET_Server = Each GNET_Server
Select serverCount
Case menuCount
FPSNetText(font, 320, 160 + 20 * serverCount, gns\server$ + " - Press Enter to Join ...", 1, 1, 255, 255, 255)
serverPointer = Handle(gns)
Default
FPSNetText(font, 320, 160 + 20 * serverCount, gns\server$, 1, 1, 100, 100, 100)
End Select
serverCount = serverCount + 1
Next
End Function
;===========================================================================
;====== DRAW GAMEPLAY ======================================================
Function DrawGamePlay()
FPSNetText(font, 320, 240, "+", 1, 1, 255, 255, 255)
p.Player = Object.Player(localPlayerPointer)
FPSNetText(font, 0, 0, "Your Score - " + p\score, 0, 0, 255, 0, 0)
For p.Player = Each Player
If Handle(p.Player) <> localPlayerPointer
CameraProject(camera, EntityX(p\mesh[1]), EntityY(p\mesh[1]), EntityZ(p\mesh[1]))
FPSNetText(font, ProjectedX(), ProjectedY() - 20, p\name$ + " - " + p\score, 1, 1, 255, 255, 255)
EndIf
Next
End Function
;===========================================================================
;====== CREATE SOME PARTICLES ==============================================
Function CreateSomeParticles(x, y, z, r, g, b, numParticles)
For i = 1 To numParticles
p.Particle = New Particle
p\mesh = CopyEntity(copySprite)
PositionEntity(p\mesh,x, y, z)
EntityColor(p\mesh, r, g, b)
p\vX# = Rnd(-.2, .2)
p\vY# = Rnd(.2)
p\vZ# = Rnd(-.2, .2)
p\alpha = 1
Next
End Function
;===========================================================================
;====== SETUP ==============================================================
Function Setup(mode$)
Select mode$
Case "Title Screen"
font = LoadFont("Arial",20,1)
bigFont = LoadFont("Arial",50,1)
GNET_ListServers()
Case "Game"
gameState$ = "Game"
p.Player = Object.Player(localPlayerPointer)
p\mesh[1] = CreatePivot()
PositionEntity(p\mesh[1], 5, 1.5, Rand(0, 50))
EntityType(p\mesh[1],BODY)
EntityRadius(p\mesh[1], 1.5)
health = 100
p\score = 0
p\name$ = localPlayerName$
camera = CreateCamera(p\mesh[1])
CameraRange(camera,.1, 500)
p\mesh[2] = CreateCube(camera)
PositionEntity(p\mesh[2], 1, -.5, 1)
ScaleEntity(p\mesh[2], .1, .1, .4)
EntityColor(p\mesh[2], 20, 20, 20)
LoadLevel()
PointEntity(p\mesh[1], level)
MoveMouse(CorrectX(320), CorrectY(240))
End Select
End Function
;===========================================================================
;====== LOAD LEVEL =========================================================
Function LoadLevel()
copySprite = CreateSprite()
ScaleSprite(copySprite, .1, .1)
EntityFX(copySprite, 1+8)
HideEntity(copySprite)
level = CreatePlane(16)
EntityPickMode(level, 2)
For i = -1 To 1 Step 2
For j = -4 To 4
cube = CreateCube(level)
EntityType(cube, SCENE)
EntityPickMode(cube, 2)
EntityColor(cube, 100, 100, 100)
PositionEntity(cube, i * 10, 1, j * 10)
Next
Next
For i = 1 To 8
cube = CreateCube(level)
EntityType(cube, SCENE)
EntityPickMode(cube, 2)
EntityColor(cube,100,100,100)
PositionEntity(cube, 0, i * 2, i * 5)
Next
For i = 1 To 8
cube = CreateCube(level)
EntityType(cube, SCENE)
EntityPickMode(cube, 2)
EntityColor(cube,100,100,100)
PositionEntity(cube, 0, i * 2, i * -5)
Next
EntityType(level,SCENE)
lightPivot = CreatePivot(level)
NameEntity(lightPivot,"Light Pivot")
light = CreateLight(3,lightPivot)
NameEntity(light, "light1")
PositionEntity(light,25, 25, 0)
RotateEntity(light, 90, 0, 0)
LightRange(light, 500)
LightColor(light, 255, 0, 0)
light = CreateLight(3,lightPivot)
NameEntity(light, "light2")
PositionEntity(light,-25, 25, 0)
RotateEntity(light, 90, 0, 0)
LightRange(light, 500)
LightColor(light, 0, 0, 255)
light = CreateLight(3,lightPivot)
NameEntity(light, "light3")
PositionEntity(light,0, 25, 25)
RotateEntity(light, 90, 0, 0)
LightRange(light, 500)
LightColor(light, 0, 255, 0)
End Function
;===========================================================================
;====== FPSNET TEXT ========================================================
Function FPSNetText(fontType, X, Y, theText$, centerX = 0, centerY = 0,r = 255, g = 255, b = 255)
Color(r, g, b)
SetFont(fontType)
Text(CorrectX(X), CorrectY(Y), theText$, centerX, centerY)
End Function
;==========================================================================
;====== CORRECTX ==========================================================
Function CorrectX(pixel)
Return (pixel * GraphicsWidth() / 640)
End Function
;==========================================================================
;====== CORRECTY ==========================================================
Function CorrectY(pixel)
Return (pixel * GraphicsHeight() / 480)
End Function
;==========================================================================
;====== DECODE INCOMING MESSAGE ===========================================
Function DecodeIncomingMessage(message$)
For i = 1 To 100
incoming$(i) = ""
Next
i = 1
part = 1
incoming$(part) = Mid(message$, i, 1)
i = i + 1
While Mid(message$, i, 1)<>"-"
While Mid(message$, i, 1)<>","
incoming$(part)=incoming$(part)+Mid(message$, i, 1)
i = i + 1
If Mid(message$, i, 1)="-"
Exit
EndIf
Wend
If Mid(message$, i, 1)=","
i = i + 1
part = part + 1
incoming$(part) = Mid(message$, i, 1)
i = i + 1
EndIf
Wend
End Function
;==========================================================================
;====== GNET SOURCE CODE ==================================================
Const GNET_HOST$="www.blitzbasic.com"
Const GNET_PORT=80
Const GNET_GET$="/gnet/gnet.php"
Type GNET_Server
Field game$,server$,ip$
End Type
Function GNET_Esc$( t$ )
t$=Replace$( t$,"&","" )
t$=Replace$( t$,"%","" )
t$=Replace$( t$,"'","" )
t$=Replace$( t$,Chr$(34),"" )
t$=Replace$( t$," ","_" )
Return t$
End Function
Function GNET_Open( opt$ )
t=OpenTCPStream( GNET_HOST$,GNET_PORT )
If Not t Return 0
WriteLine t,"GET "+GNET_GET$+"?opt="+opt$+" HTTP/1.0"
WriteLine t,"HOST: "+GNET_HOST$
WriteLine t,""
While ReadLine$(t)<>""
Wend
Return t
End Function
Function GNET_Exec( opt$,game$,server$ )
opt$=opt$+"&game="+GNET_Esc$(game$)
If server$<>"" opt$=opt$+"&server="+GNET_Esc$(server$)
t=GNET_Open( opt$ )
If Not t Return 0
ok=False
If( ReadLine$(t)="OK" ) ok=True
CloseTCPStream t
Return ok
End Function
Function GNET_Ping$()
t=GNET_Open( "ping" )
If Not t Return 0
ip$=ReadLine$(t)
CloseTCPStream t
Return ip$
End Function
Function GNET_AddServer( game$,server$="" )
Return GNET_Exec( "add",game$,server$ )
End Function
Function GNET_RefreshServer( game$,server$="" )
Return GNET_Exec( "ref",game$,server$ )
End Function
Function GNET_RemoveServer( game$ )
Return GNET_Exec( "rem",game$,"" )
End Function
Function GNET_ListServers( game$="" )
Delete Each GNET_Server
t=GNET_Open( "list" )
If Not t Return 0
Repeat
t_game$=ReadLine$(t)
If t_game$="" Exit
t_server$=ReadLine$(t)
t_ip$=ReadLine(t)
If game$="" Or game$=t_game$
p.GNET_Server=New GNET_Server
p\game$=t_game$
p\server$=t_server$
p\ip$=t_ip$
EndIf
Forever
CloseTCPStream t
Return 1
End Function
;========================================================================== |