如何在循环时构造我的主要pygame?

时间:2018-02-15 16:53:48

标签: python pygame

对于我的pygame Tower Defense程序,我有一个名为main.py的python文件,它创建了一个名为Menu的类的实例(它位于一个名为startup.py的单独模块中 )启动游戏的主菜单。

菜单屏幕上的一个按钮然后在另一个名为main的python模块中运行(单击时)一个名为mapgen.py的函数。此功能包含运行主游戏和更新屏幕所需的所有代码。它为必要的类创建实例,然后在while循环中运行所有类函数:

def main():
    global money
    money = side.Money()
    global health
    health = side.Health()
    global live_grid
    live_grid = Grid() #Creates instance of grid
    global live_sidebar
    live_sidebar = side.Sidebar() #Creates instance of sidebar
    while True:
        money.money_update() #Updates the current money of the player
        live_grid.blit_grid() #Blits the grid background
        live_sidebar.event_main() #Runs event handler for the sidebar to update any information there
        live_sidebar.blit_sidebar() #Blits the sidebar
        pg.display.update()
        C.clock.tick(C.FPS)

我将main(主游戏循环)作为一个函数的原因是我可以从startup模块(包含主菜单)调用它。

然而,这使我无法制作暂停屏幕,因为我无法在不启动课程的情况下恢复该功能。

我还需要能够从其他模块访问类的实例。这就是我为模块创建全局实例的原因。

如果我尝试在函数之外创建类的实例以避免这种情况,我会得到错误,我认为这是由于python导入模块的方式引起的,如下所示:

Traceback (most recent call last):
  File ".\main.py", line 2, in <module>
    import startup, config as C
  File "C:\Users\bobsh\Programming Project\Version 0.7b\startup.py", line 2, in <module>
    import config as C, button as B, mapgen
  File "C:\Users\bobsh\Programming Project\Version 0.7b\button.py", line 2, in <module>
    import mapgen, config as C, startup
  File "C:\Users\bobsh\Programming Project\Version 0.7b\mapgen.py", line 140, in <module>
    font = B.font
AttributeError: module 'button' has no attribute 'font' (even though it does)

这是一个相当长的问题,但我应该如何构建我的while循环以及随后的任何其他代码,以便我能够轻松创建暂停屏幕(基本上中断主游戏过程,以便玩家可以选择是否退出或恢复)并从Menu中的startup.py班级运行游戏?

这是我的代码的Github gist,这里是运行游戏本身所需的一切Dropbox

我非常感谢任何人都可以提供的任何帮助。

1 个答案:

答案 0 :(得分:0)

这个答案将分为两部分,一部分向您展示如何在您的main()功能中隐藏暂停屏幕,另一部分向您概述如何更好地构建代码。

将暂停屏幕隐藏到main()功能

好吧,这绝不是最好的方法,但我认为这也不是一个坏方法。这非常简单。

#main game function
def main():
    #Creates instances of necessary classes
    global money
    money = side.Money()
    global health
    health = side.Health()
    global live_grid
    live_grid = Grid()
    global live_sidebar
    live_sidebar = side.Sidebar()

    paused = False

    while True:
        # Pause functionality
        keys = pg.keys.get_pressed();
        if keys[pg.k_SPACE]:
            if paused:
                paused = False 
            else:
                paused = True 


        if not paused:
            money.money_update() #Updates the current money of the player
            live_grid.blit_grid() #Blits the grid background
            live_sidebar.event_main() #Runs event handler for the sidebar to update any information there
            live_sidebar.blit_sidebar() #Blits the sidebar
            pg.display.update()

        if paused:
            # Pause menu code goes here 


        C.clock.tick(C.FPS)

这就是它。我已经大量使用这种技术将不同的菜单,按钮等叠加到主游戏屏幕上,它的效果非常好。对于像暂停屏幕这样简单的东西,我认为创建另一个类或函数没有任何意义,因为那时你必须重新初始化类,确保你在游戏中的同一个地方等等。

以更好的方式构建代码:

你的游戏是我喜欢称之为“多米诺骨牌效应”的受害者。这个术语非常明显。你调用一个函数,然后调用另一个函数,依此类推。

这可以通过取出创建此多米诺骨牌效果的线条来解决,而是在实际执行游戏的文件中调用该函数:main.py

我将以第一个例子向您展示如何做到这一点。

class Menu():
    def __init__(self):
        pg.init()
        self.screen = C.screen
        self.button_x = C.game_screen_full_w * 0.4
        self.button_y = [C.game_screen_h * 0.30, C.game_screen_h * 0.50, C.game_screen_h * 0.70]
        self.play_button = B.Button("mapgen.main()", (140, 40), (self.button_x,self.button_y[0]), C.L_BLUE, C.BLUE, None, C.DARK_GREY, C.L_BLUE , "Play")
        self.lead_button = B.Button("startup.Lead()", (200, 40), (self.button_x - 30,self.button_y[1]), C.L_BLUE, C.BLUE, None, C.DARK_GREY, C.L_BLUE, "Leaderboard")
        self.quit_button = B.Button("quit()", (140, 40), (self.button_x,self.button_y[2]), C.L_BLUE, C.BLUE, None, C.DARK_GREY, C.L_BLUE, "Quit")
        self.vol_button = B.Button(None, (50,50), (40,40), C.L_BLUE, C.BLUE, None, C.DARK_GREY, C.L_BLUE, "♫")
        #self.menu_screen()

请注意,我注释掉了最后一行。该行调用另一个在其中具有while循环的函数。如您所见,这会产生多米诺骨牌效应。

现在在main.py你可以自己添加一行。

if __name__ == '__main__':
    live_menu = startup.Menu()
    live_menu.menu_screen()

我看到的下一个例子是第if event.button == 1 and self.action is not None: exec(self.action)行。修改按钮代码,使其不调用该功能。提示:您可以返回一个值,并使用它从main.py之类的地方调用该函数。

至于导入模块,我看到没有问题。导入模块时,没有运行代码,因为您只定义了类和函数。您收到了错误,因为font后没有括号。该行应为font = B.font()

但是,当你说你不能在函数之外实例化类时,你是对的。你不能因为当你导入文件时,你正在运行那行代码。如果你想要,你也可以把它代码放入它自己的函数中,只调用一次。

完成后,您的代码应该更好一些。

作为开始时构建代码的经验法则:仅在一个文件中实例化类;只在一个文件中创建函数,而不是方法,函数;尝试尽可能限制多米诺骨牌效应,以便您的代码尽可能易于管理。

如果您需要任何指导,请查看this repo中的代码。所有代码都在一个文件中。

祝你好运!我希望这个答案对你有帮助,如果你有任何问题,请随时在下面发表评论!