I learning by going through various tutorials, docs, and youtube, and I came across this presentation for learning how to use Panda3D with simple collision detection and multiplayer client/server networking:
- Develop Games with Panda3D and Python - YouTube - Develop Games with Panda3D and Python - Sep 2, 2012
This is referenced in the following post here:
The dropbox link to the source code is 404/not found, and I have done my best to resurrect the final server.py
/client.py
, but it is incomplete.
I would like to complete/clean it up and use it as a base for building/exploring various simple multiplayer game concepts - please let me know if you can help!
server.py
import direct.directbase.DirectStart
from direct.showbase import DirectObject
from direct.gui.OnscreenText import OnscreenText
# Warning: pandac.PandaModules is deprecated, import from panda3d.core instead
# from pandac.PandaModules import *
from panda3d.core import *
from direct.task import Task
import math, sys, random
from direct.distributed.PyDatagram import PyDatagram
from direct.distributed.PyDatagramIterator import PyDatagramIterator
PI = 4.0*math.atan(1.0)
DEGREEStoRADIANS = PI / 180.0
RADIANStoDEGREES = 100.0 / PI
MSG_NONE = 0
MSG_AUTH = 1
MSG_POS = 2
MSG_QUIT = 3
MSG_CQUIT = 4
MSG_CPOS = 5
# timeout for connecting attempts
timeout = 1000
# props = WindowProperties()
# props.setCursorHidden(True)
# base.win.requestProperties(props)
def addInstructions(pos, msg):
return OnscreenText(text=msg, style=1, fg=(1, 1, 1, 1),
pos=(-1.3, pos), align=TextNode.ALeft, scale=.05)
def addTitle(text):
return OnscreenText(text=text, style=1, fg=(1, 1, 1, 1),
pos=(-0.0, -0.95), align=TextNode.ACenter, scale = 0.07)
class PyOhio(DirectObject.DirectObject):
def __init__(self):
self.Clients = {}
self.PlayerList = {}
self.Models = {}
self.CollSpheres = {}
self.CollNodes = {}
self.speed = 0.25
self.myID = "server"
self.serverAddress = "192.168.0.7"
self.port = 10101
self.title = addTitle("SIMPLE GAME TESTING NETWORKS")
self.inst1 = addInstructions(0.95, "[ESC]: Quit")
self.inst2 = addInstructions(0.90, "[arrow_up]: Move Positive Y")
self.inst3 = addInstructions(0.85, "[arrow_down]: Move Negative Y")
self.inst4 = addInstructions(0.80, "[arrow_right]: Move Positive X")
self.inst5 = addInstructions(0.75, "[arrow_left]: Move Negative X")
base.setBackgroundColor(0, 0, 0)
self.parent = loader.loadModel("models/misc/sphere")
self.parent.setPos(0, 0, 0)
x = 0
for i in range(100):
theta = x;
self.placeholder2 = render.attachNewNode("Placeholder2")
self.placeholder2.setPos(50.0*math.cos(theta), 50.0*math.sin(theta), 0.0)
red = 0.6 + (random.random() * 0.4)
green = 0.6 + (random.random() * 0.4)
blue = 0.6 + (random.random() * 0.4)
self.placeholder2.setColorScale(red, green, blue, 1.0)
self.parent.instanceTo(self.placeholder2)
x = x + 0.06
self.chaser = loader.loadModel("models/misc/sphere")
self.chaser.reparentTo(render)
self.chaser.setPos(0, 0, 0)
self.chaser.setHpr(0, 0, 0)
self.chaser.setScale(1.0)
self.chaser.setColorScale(1.0, 0.0, 0.0, 1.0)
base.disableMouse()
base.camera.setPos(0.0, 0.0, 250.0)
base.camera.setHpr(0.0, -90.0, 0.0)
# create collision nodes for fighter and parent
self.chasercnode = self.chaser.attachNewNode(CollisionNode('cnode2'))
self.parentcnode = self.parent.attachNewNode(CollisionNode('cnode1'))
self.chasercnode.node().addSolid(CollisionSphere(0, 0, 0, 1.0))
self.parentcnode.node().addSolid(CollisionSphere(0, 0, 0, 2.0))
# Set a CollisionHandlerPusher()
self.pusher = CollisionHandlerPusher()
# Pass collisionNodePath and modelNodePath
self.pusher.addCollider(self.chasercnode, self.chaser)
# setup traverser for fromObjects
self.traverser = CollisionTraverser()
base.cTrav = self.traverser
# Any collision geometry under render that's not defined as 'fromObject' will be a 'toObject'
self.traverser.traverse(render)
# make collisionNode a 'fromObject' with the Handler
self.traverser.addCollider(self.chasercnode, self.pusher)
# self.parentcnode.show()
# self.fightercnode.show()
base.cTrav.showCollisions(render)
# set key bindings
# use the following to see all events:
# base.messenger.toggleVerbose()
self.accept('arrow_left', self.negX, [1])
self.accept('arrow_left-up', self.negX, [0])
self.accept('arrow_right', self.posX, [1])
self.accept('arrow_right-up', self.posX, [0])
self.accept('arrow_down', self.negY, [1])
self.accept('arrow_down-up', self.negY, [0])
self.accept('arrow_up', self.posY, [1])
self.accept('arrow_up-up', self.posY, [0])
self.accept('escape', self.quit)
self.initNetwork()
def negX(self, keyDown):
if keyDown:
taskMgr.add(self.mvNegX, 'moveNegX')
else:
taskMgr.remove('moveNegX')
self.acceptOnce('arrow_left', self.negX, [1])
self.acceptOnce('arrow_left-up', self.negX, [0])
def posX(self, keyDown):
if keyDown:
taskMgr.add(self.mvPosX, 'movePosX')
else:
taskMgr.remove('movePosX')
self.acceptOnce('arrow_right', self.posX, [1])
self.acceptOnce('arrow_right-up', self.posX, [0])
def negY(self, keyDown):
if keyDown:
taskMgr.add(self.mvNegY, 'moveNegY')
else:
taskMgr.remove('moveNegY')
self.acceptOnce('arrow_down', self.negY, [1])
self.acceptOnce('arrow_down-up', self.negY, [0])
def posY(self, keyDown):
if keyDown:
taskMgr.add(self.mvPosY, 'movePosY')
else:
taskMgr.remove('movePosY')
self.acceptOnce('arrow_up', self.posY, [1])
self.acceptOnce('arrow_up-up', self.posY, [0])
def mvNegX(self, task):
self.chaser.setX(self.chaser, -1 * self.speed)
X = self.chaser.getX()
Y = self.chaser.getY()
Z = self.chaser.getZ()
H = self.chaser.getH()
P = self.chaser.getP()
R = self.chaser.getR()
self.PlayerList[self.myID] = [X, Y, Z, H, P, R]
self.updateServer()
return Task.cont
def mvPosX(self, task):
self.chaser.setX(self.chaser, self.speed)
X = self.chaser.getX()
Y = self.chaser.getY()
Z = self.chaser.getZ()
H = self.chaser.getH()
P = self.chaser.getP()
R = self.chaser.getR()
self.PlayerList[self.myID] = [X, Y, Z, H, P, R]
self.updateServer()
return Task.cont
def mvNegY(self, task):
self.chaser.setY(self.chaser, -1 * self.speed)
X = self.chaser.getX()
Y = self.chaser.getY()
Z = self.chaser.getZ()
H = self.chaser.getH()
P = self.chaser.getP()
R = self.chaser.getR()
self.PlayerList[self.myID] = [X, Y, Z, H, P, R]
self.updateServer()
return Task.cont
def mvPosY(self, task):
self.chaser.setY(self.chaser, self.speed)
X = self.chaser.getX()
Y = self.chaser.getY()
Z = self.chaser.getZ()
H = self.chaser.getH()
P = self.chaser.getP()
R = self.chaser.getR()
self.PlayerList[self.myID] = [X, Y, Z, H, P, R]
self.updateServer()
return Task.cont
def quit(self):
sys.exit()
def initNetwork(self):
print(self.myID + " : Network INIT")
self.cManager = QueuedConnectionManager()
self.cListener = QueuedConnectionListener(self.cManager, 0)
self.cReader = QueuedConnectionReader(self.cManager, 0)
self.cWriter = ConnectionWriter(self.cManager, 0)
self.startServer()
def startServer(self):
self.tcpSocket = self.cManager.openTCPServerRendezvous(self.port, timeout)
self.cListener.addConnection(self.tcpSocket)
taskMgr.add(self.listenTask, 'serverListenTask', -40)
taskMgr.add(self.readTask, 'serverReadTask', -39)
# add yourself to the Player list
self.PlayerList[self.myID] = [0, 0, 0, 0, 0, 0]
taskMgr.add(self.updateWorld, 'updateWorldTask')
print(self.myID + " : Server Started")
def listenTask(self, task):
if self.cListener.newConnectionAvailable():
rendervous = PointerToConnection()
netAddress = NetAddress()
newConnection = PointerToConnection()
if self.cListener.getNewConnection(rendervous, netAddress, newConnection):
newConnection = newConnection.p()
# tell the reader that there's a new connection
self.cReader.addConnection(newConnection)
self.lastConnection = newConnection
print(self.myID + " : " + str(netAddress) + " : got a connection")
else:
print(self.myID + " : getNewConnection returned false")
return Task.cont
def readTask(self, task):
while 1:
(datagram, pkg, msgID) = self.nonBlockingRead(self.cReader)
if msgID == MSG_NONE:
break
else:
self.datagramhandler(pkg, msgID)
return task.cont
def nonBlockingRead(self, gcr):
if self.cReader.dataAvailable():
datagram = NetDatagram()
if self.cReader.getData(datagram):
pkg = PyDatagramIterator(datagram)
msgID = pkg.getUint16()
else:
pkg = None
msgID = MSG_NONE
else:
datagram = None
pkg = None
msgID = MSG_NONE
return (datagram, pkg, msgID)
def datagramhandler(self, pkg, msgID):
if (msgID == MSG_AUTH):
PlayerID = pkg.getString()
self.Clients[self.lastConnection] = PlayerID
X = pkg.getFloat64()
Y = pkg.getFloat64()
Z = pkg.getFloat64()
H = pkg.getFloat64()
P = pkg.getFloat64()
R = pkg.getFloat64()
StatList = [X, Y, Z, H, P, R]
self.PlayerList[PlayerID] = StatList
print(str(self.PlayerList))
print(str(self.Clients))
self.updateClients()
elif msgID == MSG_CPOS:
PlayerID = pkg.getString()
if PlayerID != self.myID:
X = pkg.getFloat64()
Y = pkg.getFloat64()
Z = pkg.getFloat64()
H = pkg.getFloat64()
P = pkg.getFloat64()
R = pkg.getFloat64()
StatList = [X, Y, Z, H, P, R]
self.PlayerList[PlayerID] = StatList
dta = PyDatagram()
dta.addUint16(MSG_CPOS)
dta.addString(PlayerID)
num = len(StatList)
for i in range(num):
dta.addFloat64(StatList[i])
for Client in self.Clients:
if (Client != PlayerID):
self.cWriter.send(dta, Client)
elif (msgID == MSG_QUIT):
PlayerID = pkg.getString()
self.Models[PlayerID].detachNode()
del self.Models[PlayerID]
del self.PlayerList[PlayerID]
dta = PyDatagram()
dta.addUint16(MSG_CQUIT)
dta.addString(PlayerID)
for Client in self.Clients:
self.cWriter.send(dta, Client)
else:
print("Don't understand the message id : " + str(msgID))
def updateServer(self):
# print(self.myID + " : updateServer()")
dta = PyDatagram()
dta.addUint16(MSG_CPOS)
dta.addString(self.myID)
stats = self.PlayerList[self.myID]
num = len(stats)
for i in range(num):
dta.addFloat64(stats[i])
for Client in self.Clients:
self.cWriter.send(dta, Client)
# print(self.myID + " : updateServer() Clients: " + str(self.Clients), "PList: " + str(self.PlayerList))
print(self.myID + " : updateServer() Clients: " + str(self.Clients), "PList: " + str(self.PlayerList))
def updateClients(self):
# print(self.myID + " : updateClients()")
dta = PyDatagram()
NUM = len(self.PlayerList)
dta.addUint16(MSG_POS)
dta.addUint16(NUM)
for s in self.PlayerList:
dta.addString(s)
stats = self.PlayerList[s]
num = len(stats)
for i in range(num):
dta.addFloat64(stats[i])
for Client in self.Clients:
self.cWriter.send(dta, Client)
print(self.myID + " : updateClients() Clients: " + str(self.Clients), "PList: " + str(self.PlayerList))
def updateWorld(self, task):
# print(self.myID + " : updateWorld()")
for i in self.PlayerList:
if i in self.Models:
if i != self.myID:
data = self.PlayerList[i]
self.Models[i].setX(data[0])
self.Models[i].setY(data[1])
self.Models[i].setZ(data[2])
self.Models[i].setH(data[3])
self.Models[i].setP(data[4])
self.Models[i].setR(data[5])
elif i.strip() != '':
if i != self.myID:
self.Models[i] = loader.loadModel("models/misc/sphere")
self.Models[i].setColorScale(0.0, 0.0, 1.0, 1.0)
self.CollSpheres[i] = CollisionSphere(0, 0, 0, 3.5)
self.CollNodes[i] = self.Models[i].attachNewNode(CollisionNode(i))
self.CollNodes[i].node().addSolid(self.CollSpheres[i])
self.Models[i].reparentTo(render)
data = self.PlayerList[i]
self.Models[i].setX(data[0])
self.Models[i].setY(data[1])
self.Models[i].setZ(data[2])
self.Models[i].setH(data[3])
self.Models[i].setP(data[4])
self.Models[i].setR(data[5])
self.updateServer()
return Task.cont
s = PyOhio()
base.run()
client.py
import direct.directbase.DirectStart
from direct.showbase import DirectObject
from direct.gui.OnscreenText import OnscreenText
# Warning: pandac.PandaModules is deprecated, import from panda3d.core instead
# from pandac.PandaModules import *
from panda3d.core import *
from direct.task import Task
import math, sys, random
from direct.distributed.PyDatagram import PyDatagram
from direct.distributed.PyDatagramIterator import PyDatagramIterator
PI = 4.0*math.atan(1.0)
DEGREEStoRADIANS = PI / 180.0
RADIANStoDEGREES = 100.0 / PI
MSG_NONE = 0
MSG_AUTH = 1
MSG_POS = 2
MSG_QUIT = 3
MSG_CQUIT = 4
MSG_CPOS = 5
# timeout for connecting attempts
timeout = 1000
# props = WindowProperties()
# props.setCursorHidden(True)
# base.win.requestProperties(props)
def addInstructions(pos, msg):
return OnscreenText(text=msg, style=1, fg=(1, 1, 1, 1),
pos=(-1.3, pos), align=TextNode.ALeft, scale=.05)
def addTitle(text):
return OnscreenText(text=text, style=1, fg=(1, 1, 1, 1),
pos=(-0.0, -0.95), align=TextNode.ACenter, scale = 0.07)
class PyOhio(DirectObject.DirectObject):
def __init__(self):
self.PlayerList = {}
self.Models = {}
self.CollSpheres = {}
self.CollNodes = {}
self.speed = 0.25
self.myID = "client"
self.serverAddress = "192.168.0.7"
self.port = 10101
self.title = addTitle("SIMPLE GAME TESTING NETWORKS")
self.inst1 = addInstructions(0.95, "[ESC]: Quit")
self.inst2 = addInstructions(0.90, "[arrow_up]: Move Positive Y")
self.inst3 = addInstructions(0.85, "[arrow_down]: Move Negative Y")
self.inst4 = addInstructions(0.80, "[arrow_right]: Move Positive X")
self.inst5 = addInstructions(0.75, "[arrow_left]: Move Negative X")
base.setBackgroundColor(0, 0, 0)
self.parent = loader.loadModel("models/misc/sphere")
self.parent.setPos(0, 0, 0)
x = 0
for i in range(100):
theta = x;
self.placeholder2 = render.attachNewNode("Placeholder2")
self.placeholder2.setPos(50.0*math.cos(theta), 50.0*math.sin(theta), 0.0)
red = 0.6 + (random.random() * 0.4)
green = 0.6 + (random.random() * 0.4)
blue = 0.6 + (random.random() * 0.4)
self.placeholder2.setColorScale(red, green, blue, 1.0)
self.parent.instanceTo(self.placeholder2)
x = x + 0.06
self.chaser = loader.loadModel("models/misc/sphere")
self.chaser.reparentTo(render)
# TODO add random starting position
self.chaser.setPos(5.0, 5.0, 0)
self.chaser.setHpr(0, 0, 0)
self.chaser.setScale(1.0)
self.chaser.setColorScale(1.0, 0.0, 0.0, 1.0)
base.disableMouse()
base.camera.setPos(0.0, 0.0, 250.0)
base.camera.setHpr(0.0, -90.0, 0.0)
# create collision nodes for fighter and parent
self.chasercnode = self.chaser.attachNewNode(CollisionNode('cnode2'))
self.parentcnode = self.parent.attachNewNode(CollisionNode('cnode1'))
self.chasercnode.node().addSolid(CollisionSphere(0, 0, 0, 1.0))
self.parentcnode.node().addSolid(CollisionSphere(0, 0, 0, 2.0))
# Set a CollisionHandlerPusher()
self.pusher = CollisionHandlerPusher()
# Pass collisionNodePath and modelNodePath
self.pusher.addCollider(self.chasercnode, self.chaser)
# setup traverser for fromObjects
self.traverser = CollisionTraverser()
base.cTrav = self.traverser
# Any collision geometry under render that's not defined as 'fromObject' will be a 'toObject'
self.traverser.traverse(render)
# make collisionNode a 'fromObject' with the Handler
self.traverser.addCollider(self.chasercnode, self.pusher)
# self.parentcnode.show()
# self.fightercnode.show()
base.cTrav.showCollisions(render)
# set key bindings
# use the following to see all events:
# base.messenger.toggleVerbose()
self.accept('arrow_left', self.negX, [1])
self.accept('arrow_left-up', self.negX, [0])
self.accept('arrow_right', self.posX, [1])
self.accept('arrow_right-up', self.posX, [0])
self.accept('arrow_down', self.negY, [1])
self.accept('arrow_down-up', self.negY, [0])
self.accept('arrow_up', self.posY, [1])
self.accept('arrow_up-up', self.posY, [0])
self.accept('escape', self.quit)
self.initNetwork()
taskMgr.add(self.updateWorld, 'updateWorldTask')
def negX(self, keyDown):
if keyDown:
taskMgr.add(self.mvNegX, 'moveNegX')
else:
taskMgr.remove('moveNegX')
self.acceptOnce('arrow_left', self.negX, [1])
self.acceptOnce('arrow_left-up', self.negX, [0])
def posX(self, keyDown):
if keyDown:
taskMgr.add(self.mvPosX, 'movePosX')
else:
taskMgr.remove('movePosX')
self.acceptOnce('arrow_right', self.posX, [1])
self.acceptOnce('arrow_right-up', self.posX, [0])
def negY(self, keyDown):
if keyDown:
taskMgr.add(self.mvNegY, 'moveNegY')
else:
taskMgr.remove('moveNegY')
self.acceptOnce('arrow_down', self.negY, [1])
self.acceptOnce('arrow_down-up', self.negY, [0])
def posY(self, keyDown):
if keyDown:
taskMgr.add(self.mvPosY, 'movePosY')
else:
taskMgr.remove('movePosY')
self.acceptOnce('arrow_up', self.posY, [1])
self.acceptOnce('arrow_up-up', self.posY, [0])
def mvNegX(self, task):
self.chaser.setX(self.chaser, -1 * self.speed)
X = self.chaser.getX()
Y = self.chaser.getY()
Z = self.chaser.getZ()
H = self.chaser.getH()
P = self.chaser.getP()
R = self.chaser.getR()
self.PlayerList[self.myID] = [X, Y, Z, H, P, R]
self.updateServer()
return Task.cont
def mvPosX(self, task):
self.chaser.setX(self.chaser, self.speed)
X = self.chaser.getX()
Y = self.chaser.getY()
Z = self.chaser.getZ()
H = self.chaser.getH()
P = self.chaser.getP()
R = self.chaser.getR()
self.PlayerList[self.myID] = [X, Y, Z, H, P, R]
self.updateServer()
return Task.cont
def mvNegY(self, task):
self.chaser.setY(self.chaser, -1 * self.speed)
X = self.chaser.getX()
Y = self.chaser.getY()
Z = self.chaser.getZ()
H = self.chaser.getH()
P = self.chaser.getP()
R = self.chaser.getR()
self.PlayerList[self.myID] = [X, Y, Z, H, P, R]
self.updateServer()
return Task.cont
def mvPosY(self, task):
self.chaser.setY(self.chaser, self.speed)
X = self.chaser.getX()
Y = self.chaser.getY()
Z = self.chaser.getZ()
H = self.chaser.getH()
P = self.chaser.getP()
R = self.chaser.getR()
self.PlayerList[self.myID] = [X, Y, Z, H, P, R]
self.updateServer()
return Task.cont
def quit(self):
# tell the server that we are disconnecting
pkg = PyDatagram()
pkg.addUint16(MSG_QUIT)
pkg.addString(self.myID)
self.cWriter.send(pkg, self.connection)
sys.exit()
def initNetwork(self):
print(self.myID + " : Network INIT")
self.cManager = QueuedConnectionManager()
self.cListener = QueuedConnectionListener(self.cManager, 0)
self.cReader = QueuedConnectionReader(self.cManager, 0)
self.cWriter = ConnectionWriter(self.cManager, 0)
self.connection = self.cManager.openTCPClientConnection(self.serverAddress, self.port, 1000)
self.cReader.addConnection(self.connection)
taskMgr.add(self.readTask, "serverReaderPollTask", -39)
print(self.myID + " : sending auth")
self.sendMsgAuth()
def readTask(self, task):
while 1:
(datagram, pkg, msgID) = self.nonBlockingRead(self.cReader)
if msgID == MSG_NONE:
break
else:
self.datagramhandler(pkg, msgID)
return task.cont
def nonBlockingRead(self, qcr):
if self.cReader.dataAvailable():
datagram = NetDatagram()
if self.cReader.getData(datagram):
pkg = PyDatagramIterator(datagram)
msgID = pkg.getUint16()
else:
pkg = None
msgID = MSG_NONE
else:
datagram = None
pkg = None
msgID = MSG_NONE
return (datagram, pkg, msgID)
def datagramhandler(self, pkg, msgID):
if msgID == MSG_POS:
num = pkg.getUint16()
for i in range(num):
PlayerID = pkg.getString()
X = pkg.getFloat64()
Y = pkg.getFloat64()
Z = pkg.getFloat64()
H = pkg.getFloat64()
P = pkg.getFloat64()
R = pkg.getFloat64()
StatList = [X, Y, Z, H, P, R]
self.PlayerList[PlayerID] = StatList
print(self.myID + " : datagramhandler(MSG_POS)" + str(self.PlayerList))
elif msgID == MSG_CPOS:
PlayerID = pkg.getString()
X = pkg.getFloat64()
Y = pkg.getFloat64()
Z = pkg.getFloat64()
H = pkg.getFloat64()
P = pkg.getFloat64()
R = pkg.getFloat64()
StatList = [X, Y, Z, H, P, R]
self.PlayerList[PlayerID] = StatList
print(self.myID + " : datagramhandler(MSG_CPOS)" + str(self.PlayerList))
elif msgID == MSG_CQUIT:
PlayerID = pkg.getString()
self.Models[PlayerID].detachNode()
del self.Models[PlayerID]
del self.PlayerList[PlayerID]
print(self.myID + " : datagramhandler(MSG_CQUIT)" + PlayerID)
else:
print("Don't understand the message id : " + str(msgID))
def sendMsgAuth(self):
pkg = PyDatagram()
pkg.addUint16(MSG_AUTH)
pkg.addString(self.myID)
pkg.addFloat64(self.chaser.getX())
pkg.addFloat64(self.chaser.getY())
pkg.addFloat64(self.chaser.getZ())
pkg.addFloat64(self.chaser.getH())
pkg.addFloat64(self.chaser.getP())
pkg.addFloat64(self.chaser.getR())
self.cWriter.send(pkg, self.connection)
def updateServer(self):
dta = PyDatagram()
dta.addUint16(MSG_CPOS)
dta.addString(self.myID)
stats = self.PlayerList[self.myID]
num = len(stats)
for i in range(num):
dta.addFloat64(stats[i])
self.cWriter.send(dta, self.connection)
# def updateClients(self):
# dta = PyDatagram()
# NUM = len(self.PlayerList)
# dta.addUint16(MSG_POS)
# dta.addUint16(NUM)
#
# for s in self.PlayerList:
# dta.addString(s)
# stats = self.PlayerList[s]
# num = len(stats)
# for i in range(num):
# dta.addFloat64(state[y])
# for Client in self.Clients:
# self.cWriter.send(dta, Client)
def updateWorld(self, task):
for i in self.PlayerList:
if i in self.Models:
if i != self.myID:
data = self.PlayerList[i]
self.Models[i].setX(data[0])
self.Models[i].setY(data[1])
self.Models[i].setZ(data[2])
self.Models[i].setH(data[3])
self.Models[i].setP(data[4])
self.Models[i].setR(data[5])
else:
data = self.PlayerList[i]
self.chaser.setX(data[0])
self.chaser.setY(data[1])
self.chaser.setZ(data[2])
self.chaser.setH(data[3])
self.chaser.setP(data[4])
self.chaser.setR(data[5])
elif i.strip() != '':
if i != self.myID:
self.Models[i] = loader.loadModel("models/misc/sphere")
self.Models[i].setColorScale(0.0, 0.0, 1.0, 1.0)
self.CollSpheres[i] = CollisionSphere(0, 0, 0, 3.5)
self.CollNodes[i] = self.Models[i].attachNewNode(CollisionNode(i))
self.CollNodes[i].node().addSolid(self.CollSpheres[i])
self.Models[i].reparentTo(render)
data = self.PlayerList[i]
self.Models[i].setX(data[0])
self.Models[i].setY(data[1])
self.Models[i].setZ(data[2])
self.Models[i].setH(data[3])
self.Models[i].setP(data[4])
self.Models[i].setR(data[5])
return Task.cont
s = PyOhio()
base.run()