I am making a beginner online multiplayer Tic Tac Toe game which runs on local server. I am having 2 issues with my code.I have divided my game folder into 6 python files:
Client1.py:- This file is the Output file which the client will have.I am having some issues in this file. when the player is waiting for other players move which is in while loop if this client has played it will send PLAYED to the server and if the server is waiting for the other players move it will send W to this client else it will send The player move number.While this .py file is waiting for reply the msg its getting from the server is W and then the window shows Not Responding. Both the Clients take reference from Clientsupport.py and Network.py. These both files are just for support of clients
import pygame
from Network import network
from clientSupport import GameHelp
n=network()
pt=n.getpos()
g=GameHelp()
g.Display_Start_Up(pt)
if pt==0:
run1=True
run2=False
elif pt==1:
run1 = False
run2 = True
while True:
while run1:
num = None
num=g.Input()
out=n.send(num)
print(out,"hrl")
if out =='Y':
print(num,pt,'hey')
g.Placing(num,pt)
run2=True
break
else:
pass
while run2:
opp=n.send('PLAYED')
print(opp,'loop2')
if opp=='W':
pygame.time.delay(500)
else:
print('here is',opp)
if pt==0:
op=1
elif pt==1:
op=0
g.Placing(opp, op)
print(opp,op,'hello')
run1=True
break
Client2.py:-This file is the exact copy of Client1.py.But these both files are having same problem. This is second problem when Both the clients connect the X and O images gets blit only on the 1st client which joins server. for the second client its blank window with just board but the input and every thing else works fine.
Server.py:- This takes the reference from the other file Game.py. This file is used by the server to check who won whats score and other parameters. Pt variable in server is basically playertag send 0 and 1.the player who joins first gets 0 and is X player otherwise player is O player.
import socket
from _thread import *
import sys
import pickle
import game
server = "192.168.1.107"
port = 34262
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.bind((server,port))
except socket.error as e:
print(str(e),'hey')
brain=game.Brain()
setup=game.Setup()
s.listen(2)
print("waiting for connection,Server connected")
p=0
setup.p2played=True
lastplayed=[0,0]
def thread_client(conn,playertag):
conn.send(pickle.dumps(playertag))
reply = ""
Run=True
while Run:
try:
try:
data = pickle.loads(conn.recv(2048))
except EOFError as e:
print(e)
pass
if not data:
print('disconnect')
break
elif data=='PLAYED':
if playertag==0:
if lastplayed[1]==0:
reply='W'
else:
reply=lastplayed[1]
lastplayed[1]=0
elif playertag==1:
if lastplayed[0]==0:
reply='W'
else:
reply=lastplayed[0]
lastplayed[0]=0
else:
if playertag==0 and setup.p2played==True:
if brain.Player_move(playertag,data):
reply='Y'
lastplayed[0]=int(data)
setup.p2played = False
setup.p1played = True
else:
reply='N'
if brain.Board_full_check():
reply='T'
Run=False
if brain.Winner_check(1):
reply='X'
Run=False
elif brain.Winner_check(-1):
reply='O'
Run=False
print(f'Recieved: {data}')
print(f'Sending {reply}')
elif playertag==1 and setup.p1played==True:
if brain.Player_move(playertag, data):
reply = 'y'
lastplayed[1] = int(data)
setup.p2played = True
setup.p1played = False
else:
reply = 'N'
if brain.Board_full_check():
reply = 'T'
Run = False
if brain.Winner_check(1):
reply = 'X'
Run = False
elif brain.Winner_check(-1):
reply = 'O'
Run = False
print(f'Recieved: {data}')
print(f'Sending {reply}')
else:
reply='W'
conn.sendall(pickle.dumps(reply))
except socket.error as e:
print(e,'ji')
break
print(f'Disconnected from {addr}')
while True:
print(game.BoardList)
conn, addr= s.accept()
print('connected to ', addr)
start_new_thread(thread_client ,(conn,p,))
p+=1
Clientsupport.py:-So this file does all the client support like pygame displays and blitting X and O.
import pygame
class GameHelp():
def __init__(self):
self.screen=pygame.display.set_mode((600, 600))
xplayer=pygame.image.load('x.png')
self.xplayer = pygame.transform.scale(xplayer, (50, 50))
oplayer = pygame.image.load('o.png')
self.oplayer = pygame.transform.scale(oplayer, (50, 50))
def Display_Start_Up(self,playertag):
caption='Tic Tac Toe '+str(playertag)
pygame.display.set_caption(caption)
self.BOARD(self.screen)
pygame.display.update()
def BOARD(self,sc):
sc.fill((225, 200, 225))
board = pygame.image.load('TransparentImage.png')
board = pygame.transform.scale(board, (375, 375))
sc.blit(board, (100, 200))
def Input(self,):
run=True
while run:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_1:
print('1')
run=False
return 1
elif event.key == pygame.K_2:
print('2')
run=False
return 2
elif event.key == pygame.K_3:
print('3')
run=False
return 3
elif event.key == pygame.K_4:
print('4')
run=False
return 4
elif event.key == pygame.K_5:
print('5')
run=False
return 5
elif event.key == pygame.K_6:
print('6')
run=False
return 6
elif event.key == pygame.K_7:
print('7')
run=False
return 7
elif event.key == pygame.K_8:
print('8')
run=False
return 8
elif event.key == pygame.K_9:
print('9')
run=False
return 9
elif event.key == pygame.K_ESCAPE or event.type==pygame.QUIT:
pygame.quit()
def Placing(self,pos,playertag):
if playertag==0:
if pos == 1:
self.screen.blit(self.xplayer, (108, 215))
elif pos == 2:
self.screen.blit(self.xplayer, (249, 222))
elif pos == 3:
self.screen.blit(self.xplayer, (376, 213))
elif pos == 4:
self.screen.blit(self.xplayer, (122, 360))
elif pos == 5:
self.screen.blit(self.xplayer, (253, 346))
elif pos == 6:
self.screen.blit(self.xplayer, (379, 346))
elif pos == 7:
self.screen.blit(self.xplayer, (118, 486))
elif pos == 8:
self.screen.blit(self.xplayer, (261, 492))
elif pos == 9:
self.screen.blit(self.xplayer, (375, 476))
elif playertag==1:
if pos == 1:
self.screen.blit(self.oplayer, (108, 215))
elif pos == 2:
self.screen.blit(self.oplayer, (249, 222))
elif pos == 3:
self.screen.blit(self.oplayer, (376, 213))
elif pos == 4:
self.screen.blit(self.oplayer, (122, 360))
elif pos == 5:
self.screen.blit(self.oplayer, (253, 346))
elif pos == 6:
self.screen.blit(self.oplayer, (379, 346))
elif pos == 7:
self.screen.blit(self.oplayer, (118, 486))
elif pos == 8:
self.screen.blit(self.oplayer, (261, 492))
elif pos == 9:
self.screen.blit(self.oplayer, (375, 476))
pygame.display.update()
Network.py:-Nothing much to say about this fil this file only connects and sends msg to server and works perfectly fine.
Final Debug Help:- There are 2 problems:
A Pygame window expects that its event queue is always being processed. A typical PyGame program looks like:
### Do some initialisation
[...]
### Main Loop
while not exiting:
### handle every event in the queue
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
exiting = True
elif ( event.type == [ ... ] ):
### Update all the game logic, sprites, network comms, whatever
if ( networkDataArrived( server_socket, server_rx_buffer ) ):
handleNetworkData( server_rx_buffer )
game_sprites.update()
### paint the screen
window.fill( WHITE )
paintGameBoard( window )
game_sprites.draw( window )
### Hopefully do nothing for the rest of the frame-time
clock.tick( FPS )
It's not OK to just be stopped for more than a split-second. If you're waiting for socket data to arrive, you need to check to see if any data has arrived, if not continue immediately. If you're waiting for keyboard entry, you can't call just input()
... it breaks the event-model.
To handle network comms, you must do non-blocking reads. One way to do this is with the select.select()
function. This allows you to "peek" at the socket buffer to see if anything has arrived. If data has arrived, you can read the exact amount held without blocking. Otherwise you just drop back to your main loop. Note that there are other ways to do this, but select()
is available on all operating systems (at least for sockets), and is in most programming languages, so it's a good function to know.
Please consider this quasi~pseudo-code for networkDataArrived()
:
def networkDataArrived( server_socket, socket_buffer ):
""" Read from the socket, stuffing data into the buffer.
Returns True when a full packet has been read into the buffer """
result = False
socks = [ server_socket ]
input,output,excep = select.select( socks, [], [], 0.01 ) # tiny read-timeout
### has any data arrived?
if ( input.count( server_socket ) > 0 ):
socket_buffer.append( server_socket.recv( MAX_PACKET_SIZE ) )
### do we have a full packet?
if ( len( socket_buffer ) >= MAX_PACKET_SIZE ):
result = True
return result