如何从游戏循环外为 Pong 游戏提供指导?
how to give directions for a Pong game from outside the game loop?
我正在尝试使用一个简单的 Server/Client 插座来控制游戏中的球拍。这个想法是让客户端能够通过向服务器发送指令来控制桨,服务器将把这些指令传递给游戏。所以我创建了一个线程来监听客户的指示并将它们存储在一个 varibale 中,另一个线程用于 运行 游戏。
问题是,当客户端发送字母 "z"(向上移动球拍)时,游戏开始了,但他发送了另一个字母,游戏就崩溃了。
我不知道我对问题的解释是否足够,我是 python 的新人,我会感谢你的帮助,告诉我如何解决这个问题!
这是我的代码:
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()
您正在等待 1024 字节的数据,但没有到达,因此线程挂起。如果您要逐键发送,请将其更改为 1,或者使用非阻塞套接字。
您也不使用新套接字连接到监听的套接字。你需要两个。一台是服务器,一台是客户端。
这是您想要的,稍微简化了一点。它只会更改 window 背景。如果你认真地计划一个网络游戏,你应该坚持使用线程模块。与低级线程相比,它为您提供了更大的灵活性。但是这段代码足够好,可以看到如何做你想做的事。此外,没有时间戳和同步。在本地主机和本地以太网上使用它时,它会正常工作。
代码:
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()
我正在尝试使用一个简单的 Server/Client 插座来控制游戏中的球拍。这个想法是让客户端能够通过向服务器发送指令来控制桨,服务器将把这些指令传递给游戏。所以我创建了一个线程来监听客户的指示并将它们存储在一个 varibale 中,另一个线程用于 运行 游戏。 问题是,当客户端发送字母 "z"(向上移动球拍)时,游戏开始了,但他发送了另一个字母,游戏就崩溃了。
我不知道我对问题的解释是否足够,我是 python 的新人,我会感谢你的帮助,告诉我如何解决这个问题!
这是我的代码:
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()
您正在等待 1024 字节的数据,但没有到达,因此线程挂起。如果您要逐键发送,请将其更改为 1,或者使用非阻塞套接字。
您也不使用新套接字连接到监听的套接字。你需要两个。一台是服务器,一台是客户端。
这是您想要的,稍微简化了一点。它只会更改 window 背景。如果你认真地计划一个网络游戏,你应该坚持使用线程模块。与低级线程相比,它为您提供了更大的灵活性。但是这段代码足够好,可以看到如何做你想做的事。此外,没有时间戳和同步。在本地主机和本地以太网上使用它时,它会正常工作。
代码:
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()