如何从游戏循环外为 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()