理解..Thanks它可以做得更好,但至少可以工作。
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)
[Pygame的水平/菜單狀態(的
可能重複http://stackoverflow.com/questions/14700889/ pygame-level-menu-states) – sloth
爲什麼你有兩個獨立的程序,擁有自己的'screen'和自己的分辨率? – furas
當我點擊'Start'時,我在控制檯中看到'Hello World' - 但我沒有看到任何方法(由你製作)在代碼中運行'bounceball' – furas