I'm building a game client in Pygame, that connects to a server which returns a list of entities(players, monsters, npc, items etc). The Pygame window then draws that info on the screen and updates according to the changes received from the server. For some reason the Pygame Window stops responding when I click on it with the mouse, and I'm not sure what to do to fix it.[text](
import pygame
import requests
import threading
import time
from emptyjsonerror import EmptyJSONError
server_url = "localhost:5000"
global username
username = None
class GameClient:
"""A class that represents a game client that communicates with a server and displays the game state using pygame."""
def __init__(self, server_url, screen_size, tile_size, color):
"""Create a GameClient object with the given server URL, screen size, tile size and color."""
self.server_url = server_url
self.screen_size = screen_size
self.tile_size = tile_size
self.color = color
pygame.init()
self.screen = pygame.display.set_mode(screen_size)
pygame.display.set_caption("Simple Client")
self.entities = []
self.images = {}
self.lock = threading.Lock()
def get_tile_map(self):
"""Get the tile map from the server as a list of dictionaries."""
response = requests.get(self.server_url + "/map")
if not response.content or response.headers.get("Content-Type") != "application/json":
raise EmptyJSONError("Empty or invalid JSON response from server", response.url)
return response.json()
def draw_tile_map(self, tile_map):
"""Draw the tile map on the screen using green squares."""
for tile in tile_map:
x = tile["x"]
y = tile["y"]
pixel_x = x * self.tile_size[0]
pixel_y = y * self.tile_size[1]
rect = pygame.Rect(pixel_x, pixel_y, self.tile_size[0], self.tile_size[1])
pygame.draw.rect(self.screen, self.color, rect)
def get_entities(self, debug=False):
"""Get and update and draw the entities from the server as a list of dictionaries."""
if debug:
dummy_entity = {
"type": "Player",
"id": 0,
"x": 5,
"y": 5,
"level": 1,
"health": 100
}
existing_entity = next((e for e in self.entities if e.get("type") == dummy_entity.get("type") and e.get("id") == dummy_entity.get("id")), None)
if not existing_entity:
#self.lock.acquire()
self.entities.append(dummy_entity)
#self.lock.release()
else:
response = requests.get(self.server_url + "/entities", params={"username": username})
print(f"Entities: {response.json()}") # Print statement added for debugging
if not response.content or response.headers.get("Content-Type") != "application/json":
raise EmptyJSONError("Empty or invalid JSON response from server", response.url)
new_entities = response.json()
if not self.entities:
#self.lock.acquire()
self.entities = new_entities
#self.lock.release()
else:
for new_entity in new_entities:
type = new_entity.get("type")
id = new_entity.get("id")
old_entity = next((e for e in self.entities if e.get("type") == type and e.get("id") == id), None)
if not old_entity:
#self.lock.acquire()
self.entities.append(new_entity)
#self.lock.release()
else:
old_entity.update(new_entity)
for old_entity in self.entities:
type = old_entity.get("type")
id = old_entity.get("id")
new_entity = next((e for e in new_entities if e.get("type") == type and e.get("id") == id), None)
if not new_entity:
#self.lock.acquire()
self.entities.remove(old_entity)
#self.lock.release()
time.sleep(1/60)
def draw_entities(self):
"""Draw the entities on the screen using different colors and shapes."""
for entity in self.entities:
type = entity.get("type")
id = entity.get("id")
x = entity.get("x")
y = entity.get("y")
level = entity.get("level")
health = entity.get("health")
pixel_x = x * self.tile_size[0] + self.tile_size[0] // 2
pixel_y = y * self.tile_size[1] + self.tile_size[1] // 2
if type not in self.images:
image_file = f"{type}.png" # Assume that there is an image file for each entity type with its name as filename
image = pygame.image.load(image_file) # Load the image using pygame.image.load function
self.images[type] = image # Store the image in the images dictionary with its type as key
image = self.images[type]
print("drawing at (" + str(pixel_x) + ', ' + str(pixel_y) + ')')
self.screen.blit(image, (pixel_x - image.get_width() // 2, pixel_y - image.get_height() // 2))
def draw_loop(self):
while True:
self.screen.fill((0, 0, 0))
tile_map = self.get_tile_map()
self.draw_tile_map(tile_map)
#print("debug draw_loop lock")
#self.lock.acquire()
self.draw_entities()
#print("debug draw_loop release")
#self.lock.release()
pygame.display.update()
fps_limit = 1/60
time.sleep(fps_limit)
def client_loop(self):
"""Run a client loop that gets and draws the tile map until the user quits."""
try:
entity_thread = threading.Thread(target=self.entity_loop)
draw_thread = threading.Thread(target=self.draw_loop)
entity_thread.start()
draw_thread.start()
run = True
while run:
events = pygame.event.get()
for event in events:
if event.type == pygame.quit:
run = False
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
print("mouse button pressed")
elif event.type == pygame.KEYDOWN:
print("keyboard button pressed")
#draw_loop()
#time.sleep(1/60)
except EmptyJSONError as e:
print(f"Error: {e} from {e.request_url}")
def get_and_print_events(self):
events = pygame.event.get()
for event in events:
print(event)
def entity_loop(self):
"""Run an entity loop that gets and draws the entities from the server every 0.1 seconds."""
try:
while True:
self.get_entities()
#self.draw_entities()
# Wait for 0.1 seconds before repeating
time.sleep(0.1)
except Exception as e:
print(f"Error: {e}")
screen_size = (320, 320)
tile_size = (32, 32)
green = (0, 255, 0)
)
I've tried implementing a dummy entity in place of the info from the server and it makes no difference. I've also tried turning off the threads for the draw entities and get entities loops, and those have made no difference either. It seems like it's an issue with my main loop, but I'm not sure what the cause is.