I am trying to use a simple Server/Client socket to control the paddle in the game. The idea is to make the client able to control the paddle by sending directions to a server which will pass this directions to the game. so i have created to threads one to be listening for client's directions and storing them in a varibale, and the other thread is for running the game. The problem is that when the client send the lettre "z" (to move the paddle up) the game starts but he send another lettre the game crushes.
I don't know if i have explained enough the problem, I'm new in python and i'll appriciate your help to tell me how to fix the problem !
Here is my code :
import socket
import threading
from threading import RLock
import pygame
from pygame.locals import *
class Pong(object):
def __init__(self, screensize):
self.screensize = screensize
self.centerx = int(screensize[0]*0.5)
self.centery = int(screensize[1]*0.5)
self.radius = 8
self.rect = pygame.Rect(self.centerx-self.radius,
self.centery-self.radius,
self.radius*2, self.radius*2)
self.color = (100,100,255)
self.direction = [1,1]
self.speedx = 2
self.speedy = 5
self.hit_edge_left = False
self.hit_edge_right = False
def update(self, player_paddle, ai_paddle):
self.centerx += self.direction[0]*self.speedx
self.centery += self.direction[1]*self.speedy
self.rect.center = (self.centerx, self.centery)
if self.rect.top <= 0:
self.direction[1] = 1
elif self.rect.bottom >= self.screensize[1]-1:
self.direction[1] = -1
if self.rect.right >= self.screensize[0]-1:
self.hit_edge_right = True
elif self.rect.left <= 0:
self.hit_edge_left = True
if self.rect.colliderect(player_paddle.rect):
self.direction[0] = -1
if self.rect.colliderect(ai_paddle.rect):
self.direction[0] = 1
def render(self, screen):
pygame.draw.circle(screen, self.color, self.rect.center, self.radius, 0)
pygame.draw.circle(screen, (0,0,0), self.rect.center, self.radius, 1)
class AIPaddle(object):
def __init__(self, screensize):
self.screensize = screensize
self.centerx = 5
self.centery = int(screensize[1]*0.5)
self.height = 100
self.width = 10
self.rect = pygame.Rect(0, self.centery-int(self.height*0.5), self.width, self.height)
self.color = (255,100,100)
self.speed = 3
def update(self, pong):
if pong.rect.top < self.rect.top:
self.centery -= self.speed
elif pong.rect.bottom > self.rect.bottom:
self.centery += self.speed
self.rect.center = (self.centerx, self.centery)
def render(self, screen):
pygame.draw.rect(screen, self.color, self.rect, 0)
pygame.draw.rect(screen, (0,0,0), self.rect, 1)
class PlayerPaddle(object):
def __init__(self, screensize):
self.screensize = screensize
self.centerx = screensize[0]-5
self.centery = int(screensize[1]*0.5)
self.height = 100
self.width = 10
self.rect = pygame.Rect(0, self.centery-int(self.height*0.5), self.width, self.height)
self.color = (100,255,100)
self.speed = 3
self.direction = 0
def update(self):
self.centery += self.direction*self.speed
self.rect.center = (self.centerx, self.centery)
if self.rect.top < 0:
self.rect.top = 0
if self.rect.bottom > self.screensize[1]-1:
self.rect.bottom = self.screensize[1]-1
def render(self, screen):
pygame.draw.rect(screen, self.color, self.rect, 0)
pygame.draw.rect(screen, (0,0,0), self.rect, 1)
class _Directions(object):
data = ""
def __init__(self):
_Directions.data = ""
def set_Data(self, data_Val):
_Directions.data = data_Val
def get_Data(self):
return _Directions.data
def pongGame(Direct_Data):
pygame.init()
screensize = (640,480)
screen = pygame.display.set_mode(screensize)
clock = pygame.time.Clock()
pong = Pong(screensize)
ai_paddle = AIPaddle(screensize)
player_paddle = PlayerPaddle(screensize)
running = True
while running:
#fps limiting/reporting phase
clock.tick(64)
#event handling phase
for event in pygame.event.get():
if event.type == QUIT:
running = False
if(Direct_Data.get_Data() == "z"):
player_paddle.direction = -1
elif(Direct_Data.get_Data() == "s"):
player_paddle.direction = 1
#object updating phase
ai_paddle.update(pong)
player_paddle.update()
pong.update(player_paddle, ai_paddle)
if pong.hit_edge_left:
print ("You Won")
pong = Pong(screensize)
ai_paddle = AIPaddle(screensize)
player_paddle = PlayerPaddle(screensize)
elif pong.hit_edge_right:
print ("You Lose")
pong = Pong(screensize)
ai_paddle = AIPaddle(screensize)
player_paddle = PlayerPaddle(screensize)
#rendering phase
screen.fill((100,100,100))
ai_paddle.render(screen)
player_paddle.render(screen)
pong.render(screen)
pygame.display.flip()
pygame.quit()
def get_Directions(Direct_Data, client):
data = client.recv(1024).decode()
Direct_Data.set_Data(data)
client.send(data.encode())
def gameStart():
verrou = RLock()
Direct_Data = _Directions()
server = socket.socket()
host = '127.0.0.1'
port = 1234
server.bind((host, port))
server.listen(1)
print ("[*] Server started !")
client, addr = server.accept()
print("[*] Got connection from ip: ", addr[0])
while True:
with verrou:
t = threading.Thread(target=get_Directions, args=[Direct_Data, client])
t1 = threading.Thread(target=pongGame, args=[Direct_Data])
t.start()
t1.start()
client.close()
if __name__ == '__main__':
gameStart()
You are waiting for 1024 bytes of data, and it doesn't arrive, so the thread hangs. Either change that to 1, if you are sending key-by-key, or use non-blocking sockets.
You also don't use new socket to connect to the listening one. You need two of them. One is server, one is client.
Here is what you want, a little bit simplified. It only changes the window background. You should stick with threading module if you are seriously planning a networking game. It gives you more flexibility than low-level threads. But this code is good enough to see how to do what you want. Also, there is no timestamping and synchronization. When using this on localhost and local ethernet it'll work fine.
Code:
from thread import start_new_thread as thread
from time import sleep
from collections import deque
import pygame
import socket
running = 1
done = 0
evt_queue = deque() # deque() is thread safe with fast memory access of end items
def Quit ():
global running
print "Quitting"
running = 0
while done!=2:
sleep(0.001)
def sender ():
"""Runs in thread and sends all valid events through socket."""
global done
print "Starting sender..."
s = socket.socket()
s.connect(("127.0.0.1", 1234))
print "Sender connected!"
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
s.send("Q")
break
elif event.type == pygame.KEYDOWN:
if event.unicode:
# Ensure only one byte is always sent:
k = event.unicode.encode("UTF-8")[0].upper()
s.send(k)
if k=="Q": break
s.close()
done += 1
print "Sender done!"
def listener (client):
"""Thread that waits for events from client and puts them on queue."""
global done
print "Listening!"
while running:
try: e = client.recv(1) # Breaks when sender closes the connection
except: break
evt_queue.append(e)
done += 1
print "Listener done!"
# Dictionary with events and their associated functions
actions = {
"W":
lambda: screen.fill((255, 255, 255)),
"K":
lambda: screen.fill((0, 0, 0)),
"R":
lambda: screen.fill((255, 0, 0)),
"G":
lambda: screen.fill((0, 255, 0)),
"B":
lambda: screen.fill((0, 0, 255)),
"Q": Quit,
None: lambda: None}
def MainLoop ():
"""Manages the game. This example only changes window colours."""
clock = pygame.time.Clock()
while running:
try: e = evt_queue.popleft()
except: e = None
action = actions.get(e, actions[None])
action()
clock.tick(64)
pygame.display.flip()
pygame.init()
screen = pygame.display.set_mode((640, 480))
s = socket.socket()
s.bind(("127.0.0.1", 1234))
s.listen(1)
thread(sender,())
print "Waiting for connection..."
client, address = s.accept()
print "Connection from", address
thread(listener,(client,))
MainLoop()
s.close()
pygame.quit()