Reputation:
I have a pygame/socket program that is basically a maze game where you have to 'tag' the other player, but when i added a send code the program has slowed down drastically, the program is fullscreen, I added another socket send line to make shure the seekers are the same then it stopped running fast. Hears my code:
My first end:
import pygame
import time
import random
import socket
import struct
pygame.init()
s = socket.socket()
port = 12345
s.bind(('', port))
s.listen(5)
c, addr = s.accept()
print ("Socket Up and running with a connection from",addr)
screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
blocks = [(50, 50, 200, 25), (200, 50, 25, 250), (300, 200, 200, 25), (50, 200, 25, 200), (250, 100, 25, 200),
(300, 250, 25, 200), (350, 225, 25, 200), (75, 325, 200, 25), (25, 150, 150, 25), (100, 200, 75, 100),
(100,375,175,25), (250, 425,25,75),(250,500,175,25),(300,450,100,25),
(100,425,25,150),(150,425,75,100),(100,550,300,25),(50,425,25,175),(50,600,150,25),
(0,100,175,25),(0,200,25,200),(0,425,25,200),(0,0,25,100),(0,0,250,25),(50,400,25,25),
(0,650,100,25),(125,625,25,100),(0,750,10000,28),(1350,0,16,10000),(225,600,25,125),
(175,650,25,100),(25,700,100,25),(275,0,10000,25),(275,50,200,25),(300,75,175,25),
(275,125,225,50),(500,200,25,300),(400,250,25,225),(425,450,25,25),(450,250,25,275),
(425,550,100,25), (500,500,25,25),(500,0,25,500),(275,25,25,25),(550,50,25,475),
(275,575,25,175), (325,600,25,125),(350,600,25,25),(375,600,25,150),(425,575,25,150),
(475,600,25,150), (525,550,50,175), (600,525,25,225),(650,575,175,25),(650,525,175,25),
(850,475,25,250), (650,625,200,25), (650,600,25,25),(650,675,175,25),(650,700,25,50),
(700,725,125,25), (900,500,25,300),(850,450,200,25),(950,500,100,25),(950,225,25,200),
(800,300,125,25),(850,300,25,100),(900,325,25,100),(800,250,125,25),(800,200,200,25),
(600,475,225,25), (600,300,25,200),(650,275,25,175),(700,300,25,225),(550,250,200,25),
(750,250,25,200), (600,200,175,25),(550,150,300,25),(875,0,25,200),(800,350,25,100),
(600,100,500,25),(575,50,275,25),(925,150,100,25),(1025,150,25,200),(1050,150,100,25),(1125,50,25,375),
(1075,200,25,200),(1025,350,25,75),(1050,450,275,25),(1075,400,25,50),(1175,200,250,25),(1150,150,175,25),
(1175,100,175,25), (1150,50,175,25),(925,50,200,25),(1150,250,175,25),(1300,275,25,150),(1250,300,25,150),(1175,300,50,125),
(1075,500,250,25),(950,500,25,225),(1000,550,25,225),(1050,450,25,275),(1100,550,25,275),
(1150,525,25,200),(1150,700,175,25),(1200,650,175,25),(1150,600,175,25),(1200,550,175,25)
]
walls = [pygame.Rect(r) for r in blocks]
Svel = 5
Hvel = 5
red = pygame.Rect(225, 225, 25, 25)
blue = pygame.Rect(1100, 300, 25, 25)
SeekChoice = random.randint(1,2)
if SeekChoice == 1:
seeker = "red"
Snum = 2
if SeekChoice == 2:
seeker = "blue"
Snum = 1
Num = 0
c.send(struct.pack("2i", SeekChoice, Num))
RedScore = 0
BlueScore = 0
RTime = 0
BTime = 0
running = True
font = pygame.font.Font(None, 60)
RedWin = font.render("RED IS WINNER!", 100,(255,0,0))
BlueWin = font.render("BLUE IS WINNER!", 100,(0,0,255))
while running:
buf = c.recv(8, socket.MSG_WAITALL)
struct.unpack("2i", buf)
x, y = struct.unpack("2i", buf)
red = pygame.Rect(x,y,25,25)
if RedScore >= 20:
screen.fill([255,255,255])
screen.blit(RedWin, [500,250])
pygame.display.flip()
time.sleep(10)
pygame.quit()
running = False
if BlueScore >= 20:
screen.fill([255,255,255])
screen.blit(BlueWin, [500,250])
pygame.display.flip()
time.sleep(10)
pygame.quit()
running = False
RTime += 1
BTime += 1
x1 = red.x
y1 = red.y
x2 = blue.x
y2 = blue.y
if seeker == "red":
RTime = 0
elif RTime >= 2000:
RTime = 0
RedScore += 1
if seeker == "blue":
BTime = 0
elif BTime >= 2000:
BTime = 0
BlueScore += 1
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
blue.x = max(blue.x - Svel, 0)
for wall in walls:
if blue.colliderect(wall):
blue.left = max(blue.left, wall.right)
if keys[pygame.K_RIGHT]:
blue.x = min(blue.x + Svel, 1341)
for wall in walls:
if blue.colliderect(wall):
blue.right = min(blue.right, wall.left)
if keys[pygame.K_UP]:
blue.y = max(blue.y - Svel, 0)
for wall in walls:
if blue.colliderect(wall):
blue.top = max(blue.top, wall.bottom)
if keys[pygame.K_DOWN]:
blue.y = min(blue.y + Svel, 743)
for wall in walls:
if blue.colliderect(wall):
blue.bottom = min(blue.bottom, wall.top)
screen.fill([0,0,0])
#pygame.draw.circle(screen,[255,255,255],(x1+12,y1+12),125)
pygame.draw.circle(screen,[255,255,255],(x2+12,y2+12),125)
for wall in walls:
pygame.draw.rect(screen, [0,0,0], wall)
#pygame.draw.rect(screen, [255,0,0], red)
pygame.draw.rect(screen, [0,0,255], blue)
if seeker == "red":
pygame.draw.rect(screen,[0,0,0],(red.x+7,red.y+7,10,10))
if seeker == "blue":
pygame.draw.rect(screen,[0,0,0],(blue.x+7,blue.y+7,10,10))
pygame.display.flip()
if red.colliderect(blue):
if seeker == "red":
print ("red/blue")
seeker = "blue"
Snum = 1
BTime = 0
RedScore += 2
BlueScore -= 3
red = pygame.Rect(225, 225, 25, 25)
blue = pygame.Rect(1166, 334, 25, 25)
elif seeker == "blue":
print ("blue/red")
Snum = 2
RTime = 0
seeker = "red"
BlueScore += 2
RedScore -= 3
red = pygame.Rect(225, 225, 25, 25)
blue = pygame.Rect(1166, 334, 25, 25)
seeker2 = seeker.encode()
c.send(seeker2)
c.send(struct.pack("2i", blue.x, blue.y))
my second end:
import pygame
import time
import random
import socket
import struct
pygame.init()
s = socket.socket()
s.connect(('192.168.43.188',12345))
screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
blocks = [(50, 50, 200, 25), (200, 50, 25, 250), (300, 200, 200, 25), (50, 200, 25, 200), (250, 100, 25, 200),
(300, 250, 25, 200), (350, 225, 25, 200), (75, 325, 200, 25), (25, 150, 150, 25), (100, 200, 75, 100),
(100,375,175,25), (250, 425,25,75),(250,500,175,25),(300,450,100,25),
(100,425,25,150),(150,425,75,100),(100,550,300,25),(50,425,25,175),(50,600,150,25),
(0,100,175,25),(0,200,25,200),(0,425,25,200),(0,0,25,100),(0,0,250,25),(50,400,25,25),
(0,650,100,25),(125,625,25,100),(0,750,10000,28),(1350,0,16,10000),(225,600,25,125),
(175,650,25,100),(25,700,100,25),(275,0,10000,25),(275,50,200,25),(300,75,175,25),
(275,125,225,50),(500,200,25,300),(400,250,25,225),(425,450,25,25),(450,250,25,275),
(425,550,100,25), (500,500,25,25),(500,0,25,500),(275,25,25,25),(550,50,25,475),
(275,575,25,175), (325,600,25,125),(350,600,25,25),(375,600,25,150),(425,575,25,150),
(475,600,25,150), (525,550,50,175), (600,525,25,225),(650,575,175,25),(650,525,175,25),
(850,475,25,250), (650,625,200,25), (650,600,25,25),(650,675,175,25),(650,700,25,50),
(700,725,125,25), (900,500,25,300),(850,450,200,25),(950,500,100,25),(950,225,25,200),
(800,300,125,25),(850,300,25,100),(900,325,25,100),(800,250,125,25),(800,200,200,25),
(600,475,225,25), (600,300,25,200),(650,275,25,175),(700,300,25,225),(550,250,200,25),
(750,250,25,200), (600,200,175,25),(550,150,300,25),(875,0,25,200),(800,350,25,100),
(600,100,500,25),(575,50,275,25),(925,150,100,25),(1025,150,25,200),(1050,150,100,25),(1125,50,25,375),
(1075,200,25,200),(1025,350,25,75),(1050,450,275,25),(1075,400,25,50),(1175,200,250,25),(1150,150,175,25),
(1175,100,175,25), (1150,50,175,25),(925,50,200,25),(1150,250,175,25),(1300,275,25,150),(1250,300,25,150),(1175,300,50,125),
(1075,500,250,25),(950,500,25,225),(1000,550,25,225),(1050,450,25,275),(1100,550,25,275),
(1150,525,25,200),(1150,700,175,25),(1200,650,175,25),(1150,600,175,25),(1200,550,175,25)
]
walls = [pygame.Rect(r) for r in blocks]
Svel = 5
Hvel = 5
red = pygame.Rect(225, 225, 25, 25)
blue = pygame.Rect(1100, 300, 25, 25)
buf = s.recv(8, socket.MSG_WAITALL)
SeekChoice, Num = struct.unpack("2i", buf)
if SeekChoice == 1:
seeker = "red"
Snum = 1
if SeekChoice == 2:
seeker = "blue"
Snum = 2
RedScore = 0
BlueScore = 0
RTime = 0
BTime = 0
running = True
font = pygame.font.Font(None, 60)
RedWin = font.render("RED IS WINNER!", 100,(255,0,0))
BlueWin = font.render("BLUE IS WINNER!", 100,(0,0,255))
screen.fill([255,255,255])
pygame.draw.circle(screen,[255,255,255],(red.x+12,red.y+12),75)
pygame.draw.circle(screen,[255,255,255],(blue.x+12,blue.y+12),75)
for wall in walls:
pygame.draw.rect(screen, [0,0,0], wall)
pygame.draw.rect(screen, [255,0,0], red)
pygame.draw.rect(screen, [0,0,255], blue)
if seeker == "red":
pygame.draw.rect(screen,[0,0,0],(red.x+7,red.y+7,10,10))
if seeker == "blue":
pygame.draw.rect(screen,[0,0,0],(blue.x+7,blue.y+7,10,10))
pygame.display.flip()
while running:
if Snum == 1:
seeker = "red"
if Snum == 2:
seeker = "blue"
s.send(struct.pack("2i", red.x, red.y))
if RedScore >= 20:
screen.fill([255,255,255])
screen.blit(RedWin, [500,250])
pygame.display.flip()
time.sleep(10)
pygame.quit()
running = False
if BlueScore >= 20:
screen.fill([255,255,255])
screen.blit(BlueWin, [500,250])
pygame.display.flip()
time.sleep(10)
pygame.quit()
running = False
RTime += 1
BTime += 1
if seeker == "red":
RTime = 0
elif RTime >= 2000:
RTime = 0
RedScore += 1
if seeker == "blue":
BTime = 0
elif BTime >= 2000:
BTime = 0
BlueScore += 1
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
red.x = max(red.x - Svel, 0)
for wall in walls:
if red.colliderect(wall):
red.left = max(red.left, wall.right)
if keys[pygame.K_RIGHT]:
red.x = min(red.x + Svel, 1341)
for wall in walls:
if red.colliderect(wall):
red.right = min(red.right, wall.left)
if keys[pygame.K_UP]:
red.y = max(red.y - Svel, 0)
for wall in walls:
if red.colliderect(wall):
red.top = max(red.top, wall.bottom)
if keys[pygame.K_DOWN]:
red.y = min(red.y + Svel, 743)
for wall in walls:
if red.colliderect(wall):
red.bottom = min(red.bottom, wall.top)
screen.fill([0,0,0])
pygame.draw.circle(screen,[255,255,255],(red.x+12,red.y+12),125)
#pygame.draw.circle(screen,[255,255,255],(blue.x+12,blue.y+12),125)
for wall in walls:
pygame.draw.rect(screen, [0,0,0], wall)
pygame.draw.rect(screen, [255,0,0], red)
#pygame.draw.rect(screen, [0,0,255], blue)
if seeker == "red":
pygame.draw.rect(screen,[0,0,0],(red.x+7,red.y+7,10,10))
if seeker == "blue":
pygame.draw.rect(screen,[0,0,0],(blue.x+7,blue.y+7,10,10))
pygame.display.flip()
seeker = s.recv(1024)
seeker = seeker.decode()
buf = s.recv(8, socket.MSG_WAITALL)
x, y = struct.unpack("2i", buf)
blue = pygame.Rect(x,y,25,25)
red = pygame.Rect(red.x,red.y,25,25)
Any help is appreciated.
Upvotes: 2
Views: 150
Reputation: 14924
Your socket handling code is (probably) responsible for the slowdown. The socket.recv()
is waiting for data to arrive. Sure you can just set the socket to non-blocking read, but you still have the issue of whether a full data-packet has arrived.
I would convert your code to use fixed packet sizes. Instead of sending a variable-length colour name, why not just send a colour tuple. It's much quicker to send [ 250 250 210 ], then "light goldenrod yellow" ;) I guess you could just use [red ]
and [blue]
.
Once you have fixed packet sizes, then you can know exactly when a new packet has arrived, versus say half a packet. Sure for tiny packets on the local network (where there isn't so much fragmentation) it's not really an issue. But data sizes grow, network topologies change, fragmentation occurs.
I like to use the select
module (which closely models the C system-function of the same name) to know if any data has arrived on the socket, and if there's nothing then simply return the the main program loop. But if data is available, read whatever there is into a buffer. This gives you a program model where you read whatever-has-arrived (most of the time nothing), and if there's enough bytes in the "arrived" buffer, then take enough bytes out to form a full-packet. It's simple, robust and works well.
So given the function:
import socket
import select
def socketReadIfAvailable( read_socket:socket.socket, packet_buffer:bytearray, amount:int=1, timeout:float=0 ):
""" Given an open socket, and a packet-buffer, return a packet if one is available.
Returns a tuple of:
None - if no packet is available
data-packet - (of <amount> bytes) if data is available (of <amount> bytes length)
-1 - if the socket has closed
AND the current packet-buffer """
result = None
# If we already have enough data buffered, don't re-fetch
if ( len( packet_buffer ) >= amount ):
bytes_read = packet_buffer[0:amount]
packet_buffer = packet_buffer[amount:]
result = bytes_read
else:
# There's not enough data, so try to read some, but only for <timeout> seconds
# if timeout is zero, just read whatever is sitting in the socket buffer already
read_events_on = [ read_socket ]
(read_list, write_list, except_list) = select.select( read_events_on, [], [], timeout )
if ( len( read_list ) > 0 ):
# New data arrived, read it
incoming = read_socket.recv( 8192 )
if ( len( incoming ) == 0 ):
# No data arrived, meaning the socket has closed
result = -1
else:
#print("%d bytes Rx'd" % ( len( incoming ) ) )
#print("%d bytes buffered" % ( len( packet_buffer ) ) )
packet_buffer += incoming # new bytes arrived, is there enough data now?
if ( len( packet_buffer ) >= amount ):
bytes_read = packet_buffer[0:amount]
packet_buffer = packet_buffer[amount:]
result = bytes_read
return result, packet_buffer
And a fixed-sized packet of 11 bytes ( 3 bytes for the RGB colour, and 4 bytes for each co-ordinate ) your reading code could be something like:
packet_buffer = bytearray()
...
pygame.display.flip()
packet, packet_buffer = socketReadIfAvailable( s, packet_buffer, 11 )
if ( packet != None ):
if ( packet == -1 ):
# TODO: handle Socket has closed
packet_buffer = bytearray() # clear buffer
else:
colour = struct.unpack( "!BBB", packet[0:3] ) # use network byte-order
x,y = struct.unpack( "!2i", packet[3:11] )
Of course if you don't want to use fixed sizes, you can just see if any data has arrived, and try:
to unpack (or unpickle) it and hope for the best. That's relatively inefficient though.
EDIT
Normally I try not to be an unpaid code-writing service, but I was convinced by an interesting looking proto-game ;)
Ok, I'm not really sure how your game is supposed to work. I found the whole red
and blue
variable set confusing. I think you should re-engineer your code to have a single server that has no GUI, and simply shunts updated positions between clients. Then you can have a single game-code where both players (or N players) connect to that server. This would also remove the red
Vs blue
from your code, leaving "local" and "others" (or whatever you want to call them).
I modified your code to only send positions when the x
and y
co-ordinates have changed. There's no need to spam the network with the same unchanged co-ordinates 60 times a second.
Also consider adding comments, and maybe the occasional blank line to your code, it makes it much easier to follow. I added this to one of the files.
Server:
import pygame
import time
import random
import socket
import struct
import select
network_buffer = bytearray()
def socketReadIfAvailable( read_socket:socket.socket, packet_buffer:bytearray, amount:int=1, timeout:float=0 ):
""" Given an open socket, and a packet-buffer, return a packet if one is available.
Returns a tuple of:
None - if no packet is available
data-packet - (of <amount> bytes) if data is available (of <amount> bytes length)
-1 - if the socket has closed
AND the current packet-buffer """
result = None
# If we already have enough data buffered, don't re-fetch
if ( len( packet_buffer ) >= amount ):
bytes_read = packet_buffer[0:amount]
packet_buffer = packet_buffer[amount:]
result = bytes_read
else:
# There's not enough data, so try to read some, but only for <timeout> seconds
# if timeout is zero, just read whatever is sitting in the socket buffer already
read_events_on = [ read_socket ]
(read_list, write_list, except_list) = select.select( read_events_on, [], [], timeout )
if ( len( read_list ) > 0 ):
# New data arrived, read it
incoming = read_socket.recv( 8192 )
if ( len( incoming ) == 0 ):
# No data arrived, meaning the socket has closed
result = -1
else:
#print("%d bytes Rx'd" % ( len( incoming ) ) )
#print("%d bytes buffered" % ( len( packet_buffer ) ) )
packet_buffer += incoming # new bytes arrived, is there enough data now?
if ( len( packet_buffer ) >= amount ):
bytes_read = packet_buffer[0:amount]
packet_buffer = packet_buffer[amount:]
result = bytes_read
return result, packet_buffer
pygame.init()
s = socket.socket()
port = 12345
s.bind(('', port))
s.listen(5)
c, addr = s.accept()
print ("Socket Up and running with a connection from",addr)
screen = pygame.display.set_mode( ( 1200, 960 ) )
pygame.display.set_caption("Maze Server")
blocks = [(50, 50, 200, 25), (200, 50, 25, 250), (300, 200, 200, 25), (50, 200, 25, 200), (250, 100, 25, 200),
(300, 250, 25, 200), (350, 225, 25, 200), (75, 325, 200, 25), (25, 150, 150, 25), (100, 200, 75, 100),
(100,375,175,25), (250, 425,25,75),(250,500,175,25),(300,450,100,25),
(100,425,25,150),(150,425,75,100),(100,550,300,25),(50,425,25,175),(50,600,150,25),
(0,100,175,25),(0,200,25,200),(0,425,25,200),(0,0,25,100),(0,0,250,25),(50,400,25,25),
(0,650,100,25),(125,625,25,100),(0,750,10000,28),(1350,0,16,10000),(225,600,25,125),
(175,650,25,100),(25,700,100,25),(275,0,10000,25),(275,50,200,25),(300,75,175,25),
(275,125,225,50),(500,200,25,300),(400,250,25,225),(425,450,25,25),(450,250,25,275),
(425,550,100,25), (500,500,25,25),(500,0,25,500),(275,25,25,25),(550,50,25,475),
(275,575,25,175), (325,600,25,125),(350,600,25,25),(375,600,25,150),(425,575,25,150),
(475,600,25,150), (525,550,50,175), (600,525,25,225),(650,575,175,25),(650,525,175,25),
(850,475,25,250), (650,625,200,25), (650,600,25,25),(650,675,175,25),(650,700,25,50),
(700,725,125,25), (900,500,25,300),(850,450,200,25),(950,500,100,25),(950,225,25,200),
(800,300,125,25),(850,300,25,100),(900,325,25,100),(800,250,125,25),(800,200,200,25),
(600,475,225,25), (600,300,25,200),(650,275,25,175),(700,300,25,225),(550,250,200,25),
(750,250,25,200), (600,200,175,25),(550,150,300,25),(875,0,25,200),(800,350,25,100),
(600,100,500,25),(575,50,275,25),(925,150,100,25),(1025,150,25,200),(1050,150,100,25),(1125,50,25,375),
(1075,200,25,200),(1025,350,25,75),(1050,450,275,25),(1075,400,25,50),(1175,200,250,25),(1150,150,175,25),
(1175,100,175,25), (1150,50,175,25),(925,50,200,25),(1150,250,175,25),(1300,275,25,150),(1250,300,25,150),(1175,300,50,125),
(1075,500,250,25),(950,500,25,225),(1000,550,25,225),(1050,450,25,275),(1100,550,25,275),
(1150,525,25,200),(1150,700,175,25),(1200,650,175,25),(1150,600,175,25),(1200,550,175,25)
]
x,y = 0, 0
sent_x, sent_y = -1, -1
walls = [pygame.Rect(r) for r in blocks]
Svel = 5
Hvel = 5
red = pygame.Rect(225, 225, 25, 25)
blue = pygame.Rect(1100, 300, 25, 25)
SeekChoice = random.randint(1,2)
if SeekChoice == 1:
seeker = "red"
Snum = 2
if SeekChoice == 2:
seeker = "blue"
Snum = 1
Num = 0
c.send(struct.pack("2i", SeekChoice, Num))
RedScore = 0
BlueScore = 0
RTime = 0
BTime = 0
running = True
font = pygame.font.Font(None, 60)
RedWin = font.render("RED IS WINNER!", 100,(255,0,0))
BlueWin = font.render("BLUE IS WINNER!", 100,(0,0,255))
while running:
### Receive a fixed-size packet from the client (if any)
### Client only sends us an x, y
#buf = c.recv(8, socket.MSG_WAITALL)
buf, network_buffer = socketReadIfAvailable( s, network_buffer, 8 ) # 8 bytes in a full packet
if ( buf != None ): # *IF* a packet was received
if ( buf == -1 ):
print( "Client disconnected" )
network_buffer = bytearray()
# TODO
else:
# A packet was received, unpack it
x, y = struct.unpack( "2i", buf ) # unpack the co-ordinates
print( "Rx: (%d, %d)" % ( x, y ) )
red = pygame.Rect(x,y,25,25)
if RedScore >= 20:
screen.fill([255,255,255])
screen.blit(RedWin, [500,250])
pygame.display.flip()
time.sleep(10)
pygame.quit()
running = False
if BlueScore >= 20:
screen.fill([255,255,255])
screen.blit(BlueWin, [500,250])
pygame.display.flip()
time.sleep(10)
pygame.quit()
running = False
RTime += 1
BTime += 1
x1 = red.x
y1 = red.y
x2 = blue.x
y2 = blue.y
if seeker == "red":
RTime = 0
elif RTime >= 2000:
RTime = 0
RedScore += 1
if seeker == "blue":
BTime = 0
elif BTime >= 2000:
BTime = 0
BlueScore += 1
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
blue.x = max(blue.x - Svel, 0)
for wall in walls:
if blue.colliderect(wall):
blue.left = max(blue.left, wall.right)
if keys[pygame.K_RIGHT]:
blue.x = min(blue.x + Svel, 1341)
for wall in walls:
if blue.colliderect(wall):
blue.right = min(blue.right, wall.left)
if keys[pygame.K_UP]:
blue.y = max(blue.y - Svel, 0)
for wall in walls:
if blue.colliderect(wall):
blue.top = max(blue.top, wall.bottom)
if keys[pygame.K_DOWN]:
blue.y = min(blue.y + Svel, 743)
for wall in walls:
if blue.colliderect(wall):
blue.bottom = min(blue.bottom, wall.top)
screen.fill([0,0,0])
#pygame.draw.circle(screen,[255,255,255],(x1+12,y1+12),125)
pygame.draw.circle(screen,[255,255,255],(x2+12,y2+12),125)
for wall in walls:
pygame.draw.rect(screen, [0,0,0], wall)
#pygame.draw.rect(screen, [255,0,0], red)
pygame.draw.rect(screen, [0,0,255], blue)
# if seeker == "red":
# pygame.draw.rect(screen,[0,0,0],(red.x+7,red.y+7,10,10))
# if seeker == "blue":
# pygame.draw.rect(screen,[0,0,0],(blue.x+7,blue.y+7,10,10))
pygame.draw.rect(screen,[0,0,0],(red.x+7,red.y+7,10,10))
pygame.draw.rect(screen,[0,0,0],(blue.x+7,blue.y+7,10,10))
pygame.display.flip()
if red.colliderect(blue):
if seeker == "red":
print ("red/blue")
seeker = "blue"
Snum = 1
BTime = 0
RedScore += 2
BlueScore -= 3
red = pygame.Rect(225, 225, 25, 25)
blue = pygame.Rect(1166, 334, 25, 25)
elif seeker == "blue":
print ("blue/red")
Snum = 2
RTime = 0
seeker = "red"
BlueScore += 2
RedScore -= 3
red = pygame.Rect(225, 225, 25, 25)
blue = pygame.Rect(1166, 334, 25, 25)
### Pack and send the fixed-size data to the client
### But only if the position x,y has changed
if ( sent_x != blue.x or sent_y != blue.y ):
seeker_name = "%-12s" % ( seeker ) # pad to 12 spaces, this never changes, move outside loop
seeker_name = seeker_name.encode() # this too
c.send( bytes( seeker_name ) ) # send the colour-name padded to 12 letters
c.send( struct.pack("2i", blue.x, blue.y ) ) # send the x, y
sent_x = blue.x
sent_y = blue.y
print( "Tx: [%s], (%d, %d)" % ( seeker, sent_x, sent_y ) )
Client:
import pygame
import time
import random
import socket
import struct
pygame.init()
import select
network_buffer = bytearray()
def socketReadIfAvailable( read_socket:socket.socket, packet_buffer:bytearray, amount:int=1, timeout:float=0 ):
""" Given an open socket, and a packet-buffer, return a packet if one is available.
Returns a tuple of:
None - if no packet is available
data-packet - (of <amount> bytes) if data is available (of <amount> bytes length)
-1 - if the socket has closed
AND the current packet-buffer """
result = None
# If we already have enough data buffered, don't re-fetch
if ( len( packet_buffer ) >= amount ):
bytes_read = packet_buffer[0:amount]
packet_buffer = packet_buffer[amount:]
result = bytes_read
else:
# There's not enough data, so try to read some, but only for <timeout> seconds
# if timeout is zero, just read whatever is sitting in the socket buffer already
read_events_on = [ read_socket ]
(read_list, write_list, except_list) = select.select( read_events_on, [], [], timeout )
if ( len( read_list ) > 0 ):
# New data arrived, read it
incoming = read_socket.recv( 8192 )
if ( len( incoming ) == 0 ):
# No data arrived, meaning the socket has closed
result = -1
else:
#print("%d bytes Rx'd" % ( len( incoming ) ) )
#print("%d bytes buffered" % ( len( packet_buffer ) ) )
packet_buffer += incoming # new bytes arrived, is there enough data now?
if ( len( packet_buffer ) >= amount ):
bytes_read = packet_buffer[0:amount]
packet_buffer = packet_buffer[amount:]
result = bytes_read
return result, packet_buffer
s = socket.socket()
s.connect(('127.0.0.1',12345))
screen = pygame.display.set_mode( ( 1200, 960 ) )
pygame.display.set_caption("Maze Client")
blocks = [(50, 50, 200, 25), (200, 50, 25, 250), (300, 200, 200, 25), (50, 200, 25, 200), (250, 100, 25, 200),
(300, 250, 25, 200), (350, 225, 25, 200), (75, 325, 200, 25), (25, 150, 150, 25), (100, 200, 75, 100),
(100,375,175,25), (250, 425,25,75),(250,500,175,25),(300,450,100,25),
(100,425,25,150),(150,425,75,100),(100,550,300,25),(50,425,25,175),(50,600,150,25),
(0,100,175,25),(0,200,25,200),(0,425,25,200),(0,0,25,100),(0,0,250,25),(50,400,25,25),
(0,650,100,25),(125,625,25,100),(0,750,10000,28),(1350,0,16,10000),(225,600,25,125),
(175,650,25,100),(25,700,100,25),(275,0,10000,25),(275,50,200,25),(300,75,175,25),
(275,125,225,50),(500,200,25,300),(400,250,25,225),(425,450,25,25),(450,250,25,275),
(425,550,100,25), (500,500,25,25),(500,0,25,500),(275,25,25,25),(550,50,25,475),
(275,575,25,175), (325,600,25,125),(350,600,25,25),(375,600,25,150),(425,575,25,150),
(475,600,25,150), (525,550,50,175), (600,525,25,225),(650,575,175,25),(650,525,175,25),
(850,475,25,250), (650,625,200,25), (650,600,25,25),(650,675,175,25),(650,700,25,50),
(700,725,125,25), (900,500,25,300),(850,450,200,25),(950,500,100,25),(950,225,25,200),
(800,300,125,25),(850,300,25,100),(900,325,25,100),(800,250,125,25),(800,200,200,25),
(600,475,225,25), (600,300,25,200),(650,275,25,175),(700,300,25,225),(550,250,200,25),
(750,250,25,200), (600,200,175,25),(550,150,300,25),(875,0,25,200),(800,350,25,100),
(600,100,500,25),(575,50,275,25),(925,150,100,25),(1025,150,25,200),(1050,150,100,25),(1125,50,25,375),
(1075,200,25,200),(1025,350,25,75),(1050,450,275,25),(1075,400,25,50),(1175,200,250,25),(1150,150,175,25),
(1175,100,175,25), (1150,50,175,25),(925,50,200,25),(1150,250,175,25),(1300,275,25,150),(1250,300,25,150),(1175,300,50,125),
(1075,500,250,25),(950,500,25,225),(1000,550,25,225),(1050,450,25,275),(1100,550,25,275),
(1150,525,25,200),(1150,700,175,25),(1200,650,175,25),(1150,600,175,25),(1200,550,175,25)
]
sent_x, sent_y = -1, -1
walls = [pygame.Rect(r) for r in blocks]
Svel = 5
Hvel = 5
red = pygame.Rect(225, 225, 25, 25)
blue = pygame.Rect(1100, 300, 25, 25)
buf = s.recv(8, socket.MSG_WAITALL)
SeekChoice, Num = struct.unpack("2i", buf)
if SeekChoice == 1:
seeker = "red"
Snum = 1
if SeekChoice == 2:
seeker = "blue"
Snum = 2
RedScore = 0
BlueScore = 0
RTime = 0
BTime = 0
running = True
font = pygame.font.Font(None, 60)
RedWin = font.render("RED IS WINNER!", 100,(255,0,0))
BlueWin = font.render("BLUE IS WINNER!", 100,(0,0,255))
#screen.fill([255,255,255])
#pygame.draw.circle(screen,[255,255,255],(red.x+12,red.y+12),75)
#pygame.draw.circle(screen,[255,255,255],(blue.x+12,blue.y+12),75)
#for wall in walls:
# pygame.draw.rect(screen, [0,0,0], wall)
#pygame.draw.rect(screen, [255,0,0], red)
#pygame.draw.rect(screen, [0,0,255], blue)
#if seeker == "red":
# pygame.draw.rect(screen,[0,0,0],(red.x+7,red.y+7,10,10))
#if seeker == "blue":
# pygame.draw.rect(screen,[0,0,0],(blue.x+7,blue.y+7,10,10))
#pygame.display.flip()
while running:
# if Snum == 1:
# seeker = "red"
# if Snum == 2:
# seeker = "blue"
### Send the x,y position only if it's changed
if ( sent_x != red.x or sent_y != red.y ):
s.send(struct.pack("2i", red.x, red.y))
sent_x = red.x
sent_y = red.y
print( "Tx: (%d, %d)" % ( sent_x, sent_y ) )
if RedScore >= 20:
screen.fill([255,255,255])
screen.blit(RedWin, [500,250])
pygame.display.flip()
time.sleep(10)
pygame.quit()
running = False
if BlueScore >= 20:
screen.fill([255,255,255])
screen.blit(BlueWin, [500,250])
pygame.display.flip()
time.sleep(10)
pygame.quit()
running = False
RTime += 1
BTime += 1
if seeker == "red":
RTime = 0
elif RTime >= 2000:
RTime = 0
RedScore += 1
if seeker == "blue":
BTime = 0
elif BTime >= 2000:
BTime = 0
BlueScore += 1
# Handle Events
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
running = False
# Handle movement keys
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
red.x = max(red.x - Svel, 0)
for wall in walls:
if red.colliderect(wall):
red.left = max(red.left, wall.right)
if keys[pygame.K_RIGHT]:
red.x = min(red.x + Svel, 1341)
for wall in walls:
if red.colliderect(wall):
red.right = min(red.right, wall.left)
if keys[pygame.K_UP]:
red.y = max(red.y - Svel, 0)
for wall in walls:
if red.colliderect(wall):
red.top = max(red.top, wall.bottom)
if keys[pygame.K_DOWN]:
red.y = min(red.y + Svel, 743)
for wall in walls:
if red.colliderect(wall):
red.bottom = min(red.bottom, wall.top)
# Paint the screen
screen.fill([0,0,0])
pygame.draw.circle(screen,[255,255,255],(red.x+12,red.y+12),125)
#pygame.draw.circle(screen,[255,255,255],(blue.x+12,blue.y+12),125)
for wall in walls:
pygame.draw.rect(screen, [0,0,0], wall)
pygame.draw.rect(screen, [255,0,0], red)
#pygame.draw.rect(screen, [0,0,255], blue)
# if seeker == "red":
# pygame.draw.rect(screen,[0,0,0],(red.x+7,red.y+7,10,10))
# if seeker == "blue":
# pygame.draw.rect(screen,[0,0,0],(blue.x+7,blue.y+7,10,10))
pygame.draw.rect(screen,[0,0,0],(red.x+7,red.y+7,10,10))
pygame.draw.rect(screen,[0,0,0],(blue.x+7,blue.y+7,10,10))
pygame.display.flip()
#seeker = s.recv(1024)
#seeker = seeker.decode()
#buf = s.recv(8, socket.MSG_WAITALL)
#x, y = struct.unpack("2i", buf)
### Receive a fixed-size packet from the server (if any)
### Server sends a 12-letter name, and x,y
buf, network_buffer = socketReadIfAvailable( s, network_buffer, 20 ) # 20 bytes in a full packet
if ( buf != None ): # *IF* a packet was received
if ( buf == -1 ):
print( "Client disconnected" )
network_buffer = bytearray()
# TODO
else:
# A packet was received, unpack it
seeker = buf[0:12].decode( "utf-8" ) # unpack the 12-letter (padded) name
seeker = seeker.strip()
x, y = struct.unpack( "2i", buf[12:20] ) # unpack the co-ordinates
blue = pygame.Rect(x,y,25,25)
print( "Rx: [%s] at (%d, %d)" % ( seeker, x, y ) )
red = pygame.Rect(red.x,red.y,25,25)
Obviously you could move the socketReadIfAvailable()
into a common file, probably also blocks
too.
Upvotes: 1