将效果与pygame中的菜单相结合

时间:2014-07-02 09:33:47

标签: python pygame

嘿,伙计们正在开发一款带有pygame的游戏。游戏的想法是当用户点击菜单上的start按钮(在开始游戏之前出现在第一个按钮上)时,他必须看到两个球在pygame窗口上弹跳。

为此,我有两个python文件。

bounceball.py

这个python文件让我在pygame窗口上反弹两个球.bounceball.py的代码是 here。(很抱歉,因为很长的代码就把它粘贴在pastebin上)

menu.py

这个python文件创建了一个我从互联网上找到的菜单,这也很好.menu.py的代码是here

但问题是,当用户点击菜单中的Start按钮时,它没有做任何事情。我想要的是当用户点击菜单中的start按钮时,他必须看到我在pygame窗口的bounceball.py编码的球节。如何将我的bounceball.py链接到菜单。

我试图通过许多方法来实现这一点,但它并没有帮助我......

希望你们能帮助我实现这个目标..任何帮助都会受到赞赏..谢谢你们提前

1 个答案:

答案 0 :(得分:0)

它可以做得更好,但至少它可行。

<强> menu.py

#!/usr/bin/python

import sys
import pygame

import bounceball 

#----------------------------------------------------------------------

WHITE = (255, 255, 255)
RED   = (255,   0,   0)
BLACK = (  0,   0,   0)

#----------------------------------------------------------------------

class MenuItem(pygame.font.Font):

    def __init__(self, text, font=None, font_size=30,
                 font_color=WHITE, (pos_x, pos_y)=(0, 0)):

        pygame.font.Font.__init__(self, font, font_size)
        self.text = text
        self.font_size = font_size
        self.font_color = font_color
        self.label = self.render(self.text, 1, self.font_color)
        self.width = self.label.get_rect().width
        self.height = self.label.get_rect().height
        self.dimensions = (self.width, self.height)
        self.pos_x = pos_x
        self.pos_y = pos_y
        self.position = pos_x, pos_y

    def is_mouse_selection(self, (posx, posy)):
        if (posx >= self.pos_x and posx <= self.pos_x + self.width) and \
            (posy >= self.pos_y and posy <= self.pos_y + self.height):
                return True
        return False

    def set_position(self, x, y):
        self.position = (x, y)
        self.pos_x = x
        self.pos_y = y

    def set_font_color(self, rgb_tuple):
        self.font_color = rgb_tuple
        self.label = self.render(self.text, 1, self.font_color)

#----------------------------------------------------------------------

class GameMenu():

    def __init__(self, screen, items, funcs, bg_color=BLACK, font=None, font_size=30,
                 font_color=WHITE):
        self.screen = screen
        self.scr_width = self.screen.get_rect().width
        self.scr_height = self.screen.get_rect().height

        self.bg_color = bg_color
        self.clock = pygame.time.Clock()

        self.funcs = funcs
        self.items = []
        for index, item in enumerate(items):
            menu_item = MenuItem(item, font, font_size, font_color)

            # t_h: total height of text block
            t_h = len(items) * menu_item.height
            pos_x = (self.scr_width / 2) - (menu_item.width / 2)
            pos_y = (self.scr_height / 2) - (t_h / 2) + (index * menu_item.height)

            menu_item.set_position(pos_x, pos_y)
            self.items.append(menu_item)

        self.mouse_is_visible = True
        self.cur_item = None

    def set_mouse_visibility(self):
        if self.mouse_is_visible:
            pygame.mouse.set_visible(True)
        else:
            pygame.mouse.set_visible(False)

    def set_keyboard_selection(self, key):
        """
        Marks the MenuItem chosen via up and down keys.
        """
        for item in self.items:
            # Return all to neutral
            item.set_italic(False)
            item.set_font_color(WHITE)

        if self.cur_item is None:
            self.cur_item = 0
        else:
            # Find the chosen item
            if key == pygame.K_UP and \
                    self.cur_item > 0:
                self.cur_item -= 1
            elif key == pygame.K_UP and \
                    self.cur_item == 0:
                self.cur_item = len(self.items) - 1
            elif key == pygame.K_DOWN and \
                    self.cur_item < len(self.items) - 1:
                self.cur_item += 1
            elif key == pygame.K_DOWN and \
                    self.cur_item == len(self.items) - 1:
                self.cur_item = 0

        self.items[self.cur_item].set_italic(True)
        self.items[self.cur_item].set_font_color(RED)

        # Finally check if Enter or Space is pressed
        if key == pygame.K_SPACE or key == pygame.K_RETURN:
            text = self.items[self.cur_item].text
            self.funcs[text]()

    def set_mouse_selection(self, item, mpos):
        """Marks the MenuItem the mouse cursor hovers on."""
        if item.is_mouse_selection(mpos):
            item.set_font_color(RED)
            item.set_italic(True)
        else:
            item.set_font_color(WHITE)
            item.set_italic(False)

    def run(self):
        mainloop = True
        while mainloop:
            # Limit frame speed to 50 FPS
            self.clock.tick(50)

            mpos = pygame.mouse.get_pos()

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    mainloop = False
                if event.type == pygame.KEYDOWN:
                    self.mouse_is_visible = False
                    self.set_keyboard_selection(event.key)
                if event.type == pygame.MOUSEBUTTONDOWN:
                    for item in self.items:
                        if item.is_mouse_selection(mpos):
                            self.funcs[item.text]()

            if pygame.mouse.get_rel() != (0, 0):
                self.mouse_is_visible = True
                self.cur_item = None

            self.set_mouse_visibility()

            # Redraw the background
            self.screen.fill(self.bg_color)

            for item in self.items:
                if self.mouse_is_visible:
                    self.set_mouse_selection(item, mpos)
                self.screen.blit(item.label, item.position)

            pygame.display.flip()

#----------------------------------------------------------------------

def run_bounceball():
    print "run bounceball"
    bounceball.run(screen)

#----------------------------------------------------------------------

if __name__ == "__main__":

    pygame.init()

    # Creating the screen
    screen = pygame.display.set_mode((300, 300), 0, 32)

    menu_items = ('Start', 'Quit')
    funcs = {'Start': run_bounceball,
             'Quit': sys.exit}

    pygame.display.set_caption('Game Menu')

    gm = GameMenu(screen, funcs.keys(), funcs)
    gm.run()

<强> bounceball.py

import pygame
import math
from itertools import cycle

#----------------------------------------------------------------------

# some simple vector helper functions, stolen from http://stackoverflow.com/a/4114962/142637
def magnitude(v):
    return math.sqrt(sum(v[i]*v[i] for i in range(len(v))))

def add(u, v):
    return [ u[i]+v[i] for i in range(len(u)) ]

def sub(u, v):
    return [ u[i]-v[i] for i in range(len(u)) ]    

def dot(u, v):
    return sum(u[i]*v[i] for i in range(len(u)))

def normalize(v):
    vmag = magnitude(v)
    return [ v[i]/vmag  for i in range(len(v)) ]

#----------------------------------------------------------------------

class Ball(object):

    def __init__(self, path, screen):
        self.x, self.y = (0, 0)
        self.speed = 2.5
        self.color = (200, 200, 200)
        self.path = cycle(path)
        self.set_target(next(self.path))

        self.screen = screen

    @property
    def pos(self):
        return self.x, self.y

    # for drawing, we need the position as tuple of ints
    # so lets create a helper property
    @property
    def int_pos(self):
        return map(int, self.pos)

    @property
    def target(self):
        return self.t_x, self.t_y

    @property
    def int_target(self):
        return map(int, self.target)   

    def next_target(self):
        self.set_target(self.pos)
        self.set_target(next(self.path))

    def set_target(self, pos):
        self.t_x, self.t_y = pos

    def update(self):
        # if we won't move, don't calculate new vectors
        if self.int_pos == self.int_target:
            return self.next_target()

        target_vector = sub(self.target, self.pos) 

        # a threshold to stop moving if the distance is to small.
        # it prevents a 'flickering' between two points
        if magnitude(target_vector) < 2: 
            return self.next_target()

        # apply the balls's speed to the vector
        move_vector = [c * self.speed for c in normalize(target_vector)]

        # update position
        self.x, self.y = add(self.pos, move_vector)

    def draw(self):
        pygame.draw.circle(self.screen, self.color, self.int_pos, 4)

#----------------------------------------------------------------------

def run(screen): 

    #pygame.init() # no need it - inited in menu.py
    #screen = pygame.display.set_mode((300, 300))  # no need it - created in menu.py

    clock = pygame.time.Clock()    

    quit = False

    path = [(26, 43),
            (105, 110),
            (45, 225),
            (145, 295),
            (266, 211),
            (178, 134),
            (250, 56),
            (147, 12)]

    path2 = [(26, 43),
             (105, 10),
             (45, 125),
             (150, 134),
             (150, 26),
             (107, 12)]

    ball = Ball(path, screen)
    ball.speed = 1.9

    ball2 = Ball(path2, screen)
    ball2.color = (200, 200, 0)

    balls = [ball, ball2]

    while not quit:
        quit = pygame.event.get(pygame.QUIT)
        pygame.event.poll()

        map(Ball.update, balls)

        screen.fill((0, 0, 0))

        map(Ball.draw, balls)

        pygame.display.flip()
        clock.tick(60)