41、打造GUI文件共享系统与自制街机游戏

打造GUI文件共享系统与自制街机游戏

一、GUI文件共享系统

在文件共享领域,我们可以构建一个带有图形用户界面(GUI)的对等文件共享程序。

1. 运行程序的基本要求

要运行这个程序,需要一个URL文件、一个用于共享文件的目录以及节点的URL。示例运行命令如下:

$ python simple_guiclient.py urlfile.txt files/ http://localhost:8080

注意, urlfile.txt 文件必须包含其他节点的URL,程序才能正常工作。你可以在同一台机器上以不同端口号启动多个程序进行测试,也可以在不同机器上运行。

2. 第二版实现

第一版原型虽然能实现文件共享功能,但用户体验不佳。第二版将解决文件列表显示的问题。
- 扩展节点类 :为了获取节点的文件列表,我们创建一个 ListableNode 类,它是 Node 的子类,新增了 list 方法:

class ListableNode(Node):
    def list(self):
        return listdir(self.dirname)
  • 客户端更新列表方法 :在客户端添加 updateList 方法,用于更新列表框:
def updateList(self):
    self.files.Set(self.server.list())

self.files 指的是在 OnInit 方法中添加的列表框。 updateList 方法在列表框创建时调用,并且每次调用 fetchHandler 时也会调用,因为 fetchHandler 可能会改变文件列表。

3. 完整代码示例(guiclient.py)
from xmlrpclib import ServerProxy, Fault
from server import Node, UNHANDLED
from client import randomString
from threading import Thread
from time import sleep
from os import listdir
import sys
import wx
HEAD_START = 0.1 # Seconds
SECRET_LENGTH = 100

class ListableNode(Node):
    """
    An extended version of Node, which can list the files
    in its file directory.
    """
    def list(self):
        return listdir(self.dirname)

class Client(wx.App):
    """
    The main client class, which takes care of setting up the GUI and
    starts a Node for serving files.
    """
    def __init__(self, url, dirname, urlfile):
        """
        Creates a random secret, instantiates a ListableNode with that secret,
        starts a Thread with the ListableNode's _start method (making sure the
        Thread is a daemon so it will quit when the application quits),
        reads all the URLs from the URL file and introduces the Node to
        them. Finally, sets up the GUI.
        """
        # Give the server a head start:
        sleep(HEAD_START)
        self.server = ServerProxy(url)
        super(Client, self).__init__()
        self.secret = randomString(SECRET_LENGTH)
        n = ListableNode(url, dirname, self.secret)
        t = Thread(target=n._start)
        t.setDaemon(1)
        t.start()
        for line in open(urlfile):
            line = line.strip()
            self.server.hello(line)

    def updateList(self):
        """
        Updates the list box with the names of the files available
        from the server Node.
        """
        self.files.Set(self.server.list())

    def OnInit(self):
        """
        Sets up the GUI. Creates a window, a text field, a button, and
        a list box, and lays them out. Binds the submit button to
        self.fetchHandler.
        """
        win = wx.Frame(None, title="File Sharing Client", size=(400, 300))
        bkg = wx.Panel(win)
        self.input = input = wx.TextCtrl(bkg);
        submit = wx.Button(bkg, label="Fetch", size=(80, 25))
        submit.Bind(wx.EVT_BUTTON, self.fetchHandler)
        hbox = wx.BoxSizer()
        hbox.Add(input, proportion=1, flag=wx.ALL | wx.EXPAND, border=10)
        hbox.Add(submit, flag=wx.TOP | wx.BOTTOM | wx.RIGHT, border=10)
        self.files = files = wx.ListBox(bkg)
        self.updateList()
        vbox = wx.BoxSizer(wx.VERTICAL)
        vbox.Add(hbox, proportion=0, flag=wx.EXPAND)
        vbox.Add(files, proportion=1,
                 flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border=10)
        bkg.SetSizer(vbox)
        win.Show()
        return True

    def fetchHandler(self, event):
        """
        Called when the user clicks the 'Fetch' button. Reads the
        query from the text field, and calls the fetch method of the
        server Node. After handling the query, updateList is called.
        If the query is not handled, an error message is printed.
        """
        query = self.input.GetValue()
        try:
            self.server.fetch(query, self.secret)
            self.updateList()
        except Fault, f:
            if f.faultCode != UNHANDLED: raise
            print "Couldn't find the file", query

def main():
    urlfile, directory, url = sys.argv[1:]
    client = Client(url, directory, urlfile)
    client.MainLoop()

if __name__ == '__main__': main()
4. 程序扩展思路
  • 添加状态栏 :显示如“正在下载”或“未找到文件 foo.txt ”等消息。
  • 节点共享“好友” :当一个节点与另一个节点建立连接时,彼此可以介绍自己已知的节点。并且在节点关闭前,告知当前邻居自己所知的所有节点。
  • 在GUI中添加已知节点列表 :允许添加新的URL并保存到URL文件中。
二、自制街机游戏

现在,我们将挑战编写自己的街机游戏,使用Python的Pygame扩展库。

1. 游戏设计

以“Self - Defense Against Fresh Fruit”为灵感,设计一个名为“Squish”的游戏,玩家控制香蕉躲避从上方掉落的16吨重物。

2. 具体目标
  • 游戏应按设计运行,香蕉可移动,重物从上方掉落。
  • 代码应模块化且易于扩展,游戏状态(如游戏介绍、不同关卡、游戏结束状态)应作为设计的一部分,并且易于添加新状态。
3. 有用工具

仅需从Pygame网站(http://pygame.org)下载Pygame。在UNIX系统上使用可能需要安装额外软件,安装说明可在Pygame网站找到。Windows二进制安装程序使用简单,只需执行安装程序并按提示操作。

4. Pygame模块介绍
模块 功能
pygame 自动导入其他Pygame模块,包含 Surface 函数用于创建新的表面对象, init 函数初始化所有模块, error 类用于捕获特定错误。
pygame.locals 包含事件类型、键、视频模式等名称,可安全地全部导入。
pygame.display 处理Pygame显示,包含 flip update set_mode set_caption get_surface 等函数。
pygame.font 包含 Font 函数,用于创建字体对象。
pygame.sprite 包含 Sprite Group 类, Sprite 是所有可见游戏对象的基类, Group 用于管理 Sprite 对象。
pygame.mouse 用于隐藏鼠标光标和获取鼠标位置。
pygame.event 跟踪各种事件,使用 pygame.event.get 获取最新事件列表。
pygame.image 用于处理图像,使用 load 函数读取图像文件。
5. 准备工作
  • 确保安装了Pygame,包括图像和字体模块。可以在交互式Python解释器中导入进行验证。
  • 准备两张图像,一张是16吨重物的图像,一张是香蕉的图像,尺寸建议在100×100到200×200像素之间,格式可以是GIF、PNG或JPEG。
6. 第一版实现(简单的重物掉落动画)

以下是实现步骤:

graph TD;
    A[初始化Pygame] --> B[加载重物图像];
    B --> C[创建自定义Weight类实例并添加到组];
    C --> D[获取事件并检查退出条件];
    D --> E[更新精灵组];
    E --> F[绘制精灵];
    F --> G[更新显示];
    G --> D;

代码示例(weights.py):

import sys, pygame
from pygame.locals import *
from random import randrange

class Weight(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        # image and rect used when drawing sprite:
        self.image = weight_image
        self.rect = self.image.get_rect()
        self.reset()

    def reset(self):
        """
        Move the weight to a random position at the top of the screen.
        """
        self.rect.top = -self.rect.height
        self.rect.centerx = randrange(screen_size[0])

    def update(self):
        """
        Update the weight for display in the next frame.
        """
        self.rect.top += 1
        if self.rect.top > screen_size[1]:
            self.reset()

# Initialize things
pygame.init()
screen_size = 800, 600
pygame.display.set_mode(screen_size, FULLSCREEN)
pygame.mouse.set_visible(0)

# Load the weight image
weight_image = pygame.image.load('weight.png')
weight_image = weight_image.convert() # ...to match the display

# Create a sprite group and add a Weight
sprites = pygame.sprite.RenderUpdates()
sprites.add(Weight())

# Get the screen surface and fill it
screen = pygame.display.get_surface()
white = (255, 255, 255)
screen.fill(white)
pygame.display.flip()

while 1:
    # Check for quit events:
    for event in pygame.event.get():
        if event.type == QUIT:
            sys.exit()
        if event.type == KEYDOWN and event.key == K_ESCAPE:
            sys.exit()
    # Update all sprites:
    sprites.update()
    # Draw all sprites:
    updates = sprites.draw(screen)
    # Update the necessary parts of the display:
    pygame.display.update(updates)

运行命令:

$ python weights.py

确保 weights.py weight.png 在当前目录下。

7. 代码解释
  • 精灵对象属性 :所有精灵对象应有 image rect 属性,分别用于存储图像和矩形对象,通过修改 rect 属性可以移动精灵。
  • Surface对象的convert方法 :用于创建具有不同颜色模型的副本,无参数调用时创建的表面对象更适合当前显示,显示速度更快。
  • 颜色表示 :颜色通过RGB三元组表示,如 (255, 255, 255) 表示白色。

打造GUI文件共享系统与自制街机游戏

三、深入探索文件共享系统扩展

为了让文件共享系统更加完善和实用,我们可以进一步深入探讨之前提出的扩展思路,并给出更详细的实现方向。

1. 添加状态栏

在GUI中添加状态栏可以实时反馈系统的运行状态,增强用户体验。以下是一个简单的实现步骤:
- 在 OnInit 方法中创建状态栏:

def OnInit(self):
    # ...原有代码...
    win = wx.Frame(None, title="File Sharing Client", size=(400, 300))
    bkg = wx.Panel(win)
    # 创建状态栏
    status_bar = win.CreateStatusBar()
    # ...原有代码...
    return True
  • fetchHandler 方法中更新状态栏信息:
def fetchHandler(self, event):
    query = self.input.GetValue()
    try:
        # 设置状态栏信息为正在下载
        self.GetTopLevelParent().SetStatusText("Downloading...")
        self.server.fetch(query, self.secret)
        self.updateList()
        # 设置状态栏信息为下载完成
        self.GetTopLevelParent().SetStatusText("Download completed.")
    except Fault, f:
        if f.faultCode != UNHANDLED: raise
        # 设置状态栏信息为未找到文件
        self.GetTopLevelParent().SetStatusText(f"Couldn't find the file {query}")
2. 节点共享“好友”

当节点之间建立连接时,彼此可以交换已知节点的信息,从而扩大文件共享的范围。以下是一个简单的实现思路:
- 在 ListableNode 类中添加一个方法,用于接收并存储其他节点的信息:

class ListableNode(Node):
    def __init__(self, url, dirname, secret):
        super(ListableNode, self).__init__(url, dirname, secret)
        self.friends = []

    def add_friend(self, friend_url):
        if friend_url not in self.friends:
            self.friends.append(friend_url)

    def share_friends(self, other_node):
        for friend in self.friends:
            other_node.add_friend(friend)
        for friend in other_node.friends:
            self.add_friend(friend)
  • 在节点建立连接时调用 share_friends 方法:
def __init__(self, url, dirname, urlfile):
    # ...原有代码...
    for line in open(urlfile):
        line = line.strip()
        self.server.hello(line)
        # 假设存在一个方法可以获取对方节点对象
        other_node = get_other_node(line)
        n.share_friends(other_node)
    # ...原有代码...
  • 在节点关闭前,将自己的好友信息告知邻居:
import atexit

class ListableNode(Node):
    def __init__(self, url, dirname, secret):
        # ...原有代码...
        atexit.register(self.notify_friends_on_exit)

    def notify_friends_on_exit(self):
        for friend in self.friends:
            try:
                friend_node = ServerProxy(friend)
                friend_node.receive_friends(self.friends)
            except Exception as e:
                print(f"Error notifying {friend}: {e}")
3. 在GUI中添加已知节点列表

在GUI中添加一个列表来显示已知节点的URL,并允许用户添加新的URL和保存到文件中。以下是实现步骤:
- 在 OnInit 方法中添加节点列表框和添加按钮:

def OnInit(self):
    # ...原有代码...
    node_list = wx.ListBox(bkg)
    add_button = wx.Button(bkg, label="Add Node")
    add_button.Bind(wx.EVT_BUTTON, self.add_node_handler)
    save_button = wx.Button(bkg, label="Save Nodes")
    save_button.Bind(wx.EVT_BUTTON, self.save_nodes_handler)
    # 布局调整
    node_box = wx.BoxSizer(wx.HORIZONTAL)
    node_box.Add(node_list, proportion=1, flag=wx.ALL | wx.EXPAND, border=10)
    button_box = wx.BoxSizer(wx.VERTICAL)
    button_box.Add(add_button, flag=wx.ALL, border=5)
    button_box.Add(save_button, flag=wx.ALL, border=5)
    node_box.Add(button_box, flag=wx.ALL, border=10)
    vbox.Add(node_box, proportion=1, flag=wx.EXPAND)
    # ...原有代码...
    return True
  • 实现添加节点和保存节点的处理方法:
def add_node_handler(self, event):
    dlg = wx.TextEntryDialog(self.GetTopLevelParent(), "Enter Node URL:")
    if dlg.ShowModal() == wx.ID_OK:
        node_url = dlg.GetValue()
        self.server.hello(node_url)
        self.node_list.Append(node_url)
    dlg.Destroy()

def save_nodes_handler(self, event):
    with open('urlfile.txt', 'w') as f:
        for i in range(self.node_list.GetCount()):
            f.write(self.node_list.GetString(i) + '\n')
    wx.MessageBox("Nodes saved successfully!", "Info", wx.OK | wx.ICON_INFORMATION)
四、街机游戏的进一步开发

在完成简单的重物掉落动画后,我们可以逐步完善“Squish”游戏,添加香蕉角色和碰撞检测等功能。

1. 添加香蕉角色

创建一个 Banana 类,继承自 pygame.sprite.Sprite ,并在游戏中添加香蕉精灵。

class Banana(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load('banana.png')
        self.image = self.image.convert()
        self.rect = self.image.get_rect()
        self.rect.bottom = screen_size[1]
        self.rect.centerx = screen_size[0] // 2

    def update(self):
        pos = pygame.mouse.get_pos()
        self.rect.centerx = pos[0]

在主程序中添加香蕉精灵:

# ...原有代码...
# 加载香蕉图像
banana_image = pygame.image.load('banana.png')
banana_image = banana_image.convert()
# 创建香蕉精灵并添加到组
banana = Banana()
sprites.add(banana)
# ...原有代码...
2. 碰撞检测

添加碰撞检测功能,当重物与香蕉发生碰撞时,游戏结束。

while 1:
    # ...原有代码...
    # 检测碰撞
    if pygame.sprite.collide_rect(banana, sprites.sprites()[0]):
        print("Game Over!")
        sys.exit()
    # ...原有代码...
3. 游戏状态管理

为了实现游戏的不同状态(如游戏介绍、游戏进行中、游戏结束),我们可以使用状态机来管理。以下是一个简单的状态机实现:

class GameState:
    def __init__(self):
        self.state = "intro"

    def set_state(self, new_state):
        self.state = new_state

    def get_state(self):
        return self.state

game_state = GameState()

while 1:
    for event in pygame.event.get():
        if event.type == QUIT:
            sys.exit()
        if event.type == KEYDOWN and event.key == K_ESCAPE:
            sys.exit()
        if event.type == KEYDOWN and event.key == K_RETURN:
            if game_state.get_state() == "intro":
                game_state.set_state("playing")
            elif game_state.get_state() == "game_over":
                game_state.set_state("intro")

    if game_state.get_state() == "intro":
        # 显示游戏介绍界面
        pass
    elif game_state.get_state() == "playing":
        # 游戏进行中
        sprites.update()
        updates = sprites.draw(screen)
        pygame.display.update(updates)
        if pygame.sprite.collide_rect(banana, sprites.sprites()[0]):
            game_state.set_state("game_over")
    elif game_state.get_state() == "game_over":
        # 显示游戏结束界面
        pass

通过以上步骤,我们可以不断扩展和完善文件共享系统和街机游戏,让它们更加实用和有趣。在实际开发中,还可以根据自己的需求添加更多的功能和优化,发挥无限的创意。

课程设计报告:总体方案设计说明 一、软件开发环境配置 本系统采用C++作为核心编程语言,结合Qt 5.12.7框架进行图形用户界面开发。数据库管理系统选用MySQL,用于存储用户数据小精灵信息。集成开发环境为Qt Creator,操作系统平台为Windows 10。 二、窗口界面架构设计 系统界面由多个功能模块构成,各模块职责明确,具体如下: 1. 起始界面模块(Widget) 作为应用程序的入口界面,提供初始导航功能。 2. 身份验证模块(Login) 负责处理用户登录账户注册流程,实现身份认证机制。 3. 游戏主大厅模块(Lobby) 作为用户登录后的核心交互区域,集成各项功能入口。 4. 资源管理模块(BagWidget) 展示用户持有的全部小精灵资产,提供可视化资源管理界面。 5. 精灵详情模块(SpiritInfo) 呈现选定小精灵的完整属性数据状态信息。 6. 用户名录模块(UserList) 系统内所有注册用户的基本信息列表展示界面。 7. 个人资料模块(UserInfo) 显示当前用户的详细账户资料历史数据统计。 8. 服务器精灵选择模块(Choose) 对战准备阶段,从服务器可用精灵池中选取参战单位的专用界面。 9. 玩家精灵选择模块(Choose2) 对战准备阶段,从玩家自有精灵库中筛选参战单位的操作界面。 10. 对战演算模块(FightWidget) 实时模拟精灵对战过程,动态呈现战斗动画状态变化。 11. 对战结算模块(ResultWidget) 对战结束后,系统生成并展示战斗结果报告数据统计。 各模块通过统一的事件驱动机制实现数据通信状态同步,确保系统功能的连贯性数据一致性。界面布局遵循模块化设计原则,采用响应式视觉方案适配不同显示环境。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
D3.js作为一种基于JavaScript的数据可视化框架,通过数据驱动的方式实现对网页元素的动态控制,广泛应用于网络结构的图形化呈现。在交互式网络拓扑可视化应用中,该框架展现出卓越的适应性功能性,能够有效处理各类复杂网络数据的视觉表达需求。 网络拓扑可视化工具借助D3.js展示节点间的关联结构。其中,节点对应于网络实体,连线则表征实体间的交互关系。这种视觉呈现模式有助于用户迅速把握网络整体架构。当数据发生变化时,D3.js支持采用动态布局策略重新计算节点分布,从而保持信息呈现的清晰度逻辑性。 网络状态监测界面是该工具的另一个关键组成部分,能够持续反映各连接通道的运行指标,包括传输速度、响应时间及带宽利用率等参数。通过对这些指标的持续追踪,用户可以及时评估网络性能状况并采取相应优化措施。 实时数据流处理机制是提升可视化动态效果的核心技术。D3.js凭借其高效的数据绑定特性,将连续更新的数据流同步映射至图形界面。这种即时渲染方式不仅提升了数据处理效率,同时改善了用户交互体验,确保用户始终获取最新的网络状态信息。 分层拓扑展示功能通过多级视图呈现网络的层次化特征。用户既可纵览全局网络架构,也能聚焦特定层级进行细致观察。各层级视图支持展开或收起操作,便于用户开展针对性的结构分析。 可视化样式定制系统使用户能够根据实际需求调整拓扑图的视觉表现。从色彩搭配、节点造型到整体布局,所有视觉元素均可进行个性化设置,以实现最优的信息传达效果。 支持拖拽缩放操作的交互设计显著提升了工具的使用便利性。用户通过简单的视图操控即可快速浏览不同尺度的网络结构,这一功能降低了复杂网络系统的认知门槛,使可视化工具更具实用价值。 综上所述,基于D3.js开发的交互式网络拓扑可视化系统,整合了结构展示、动态布局、状态监控、实时数据处理、分层呈现及个性化配置等多重功能,形成了一套完整的网络管理解决方案。该系统不仅协助用户高效管理网络资源,还能提供持续的状态监测深度分析能力,在网络运维领域具有重要应用价值。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值