Changeset 224 for trunk/src/pyspacewar/ui.py
- Timestamp:
- 12/25/06 18:25:30 (5 years ago)
- Files:
-
- 1 modified
-
trunk/src/pyspacewar/ui.py (modified) (24 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/pyspacewar/ui.py
r223 r224 27 27 28 28 29 DEFAULT_CONTROLS = { 30 # Player 1 31 'P1_TOGGLE_AI': K_1, 32 'P1_LEFT': K_LEFT, 33 'P1_RIGHT': K_RIGHT, 34 'P1_FORWARD': K_UP, 35 'P1_BACKWARD': K_DOWN, 36 'P1_BRAKE': K_RALT, 37 'P1_FIRE': K_RCTRL, 38 # Player 2 39 'P2_TOGGLE_AI': K_2, 40 'P2_LEFT': K_a, 41 'P2_RIGHT': K_d, 42 'P2_FORWARD': K_w, 43 'P2_BACKWARD': K_s, 44 'P2_BRAKE': K_LALT, 45 'P2_FIRE': K_LCTRL, 46 } 47 48 29 49 HELP_TEXT = u"""\ 30 50 =PySpaceWar= … … 41 61 =Player 1 Controls= 42 62 43 LEFT, RIGHT\u2014 rotate44 UP\u2014 accelerate in the direction you're facing45 DOWN\u2014 accelerate in the opposite direction46 RCTRL\u2014 launch a missile47 RALT\u2014 brake (lose 5% speed)48 1\u2014 enable/disable computer control63 P1_LEFT, P1_RIGHT \u2014 rotate 64 P1_FORWARD \u2014 accelerate in the direction you're facing 65 P1_BACKWARD \u2014 accelerate in the opposite direction 66 P1_FIRE \u2014 launch a missile 67 P1_BRAKE \u2014 brake (lose 5% speed) 68 P1_TOGGLE_AI \u2014 enable/disable computer control 49 69 50 70 =Player 2 Controls= 51 71 52 A, D\u2014 rotate53 W\u2014 accelerate in the direction you're facing54 S\u2014 accelerate in the opposite direction55 LCTRL\u2014 launch a missile56 LALT\u2014 brake (lose 5% speed)57 2\u2014 enable/disable computer control72 P2_LEFT, P2_RIGHT \u2014 rotate 73 P2_FORWARD \u2014 accelerate in the direction you're facing 74 P2_BACKWARD \u2014 accelerate in the opposite direction 75 P2_FIRE \u2014 launch a missile 76 P2_BRAKE \u2014 brake (lose 5% speed) 77 P2_TOGGLE_AI \u2014 enable/disable computer control 58 78 59 79 =Other Controls= … … 84 104 version. 85 105 """ 106 107 108 def key_name(key): 109 """Return the name of the key. 110 111 >>> key_name(K_RCTRL) 112 'RIGHT CTRL' 113 >>> key_name(None) 114 '(unset)' 115 116 """ 117 if not key: 118 return '(unset)' 119 return pygame.key.name(key).upper() 120 121 122 def fixup_keys_in_text(text, controls): 123 """Replace action names with key names in help text. 124 125 >>> fixup_keys_in_text('Press FIRE to start', {'FIRE': K_RCTRL}) 126 'Press RIGHT CTRL to start' 127 128 """ 129 for action, key in controls.items(): 130 text = text.replace(action, key_name(key)) 131 return text 86 132 87 133 … … 801 847 self.top = 0 802 848 self.item_height = item_height 803 self.surface = pygame.Surface((self.width, self.full_height)) 804 self.surface.set_alpha(255 * 0.9) 805 self.surface.set_colorkey((1, 1, 1)) 806 self.invalidate() 849 self.resize() 807 850 808 851 def position(self, surface, margin=10): … … 820 863 return HUDElement.position(self, surface, margin) 821 864 865 def resize(self): 866 self.surface = pygame.Surface((self.width, self.full_height)) 867 self.surface.set_alpha(255 * 0.9) 868 self.surface.set_colorkey((1, 1, 1)) 869 self.invalidate() 870 822 871 def invalidate(self): 823 872 """Indicate that the menu needs to be redrawn.""" … … 830 879 for item in items: 831 880 size = font.size(item) 881 if '\t' in item: 882 size = (size[0] + xpadding * 2, size[1]) 832 883 width = max(width, size[0]) 833 884 height = max(height, size[1]) … … 858 909 fg_color = self.normal_fg_color 859 910 bg_color = self.normal_bg_color 860 img = self.font.render(item, True, fg_color)861 911 self.surface.fill(bg_color, (x, y, self.width, self.item_height)) 862 self.surface.blit(img, 863 (x + (self.width - img.get_width())/2, 864 y + (self.item_height - img.get_height())/2)) 912 if '\t' in item: 913 # align left and right 914 parts = item.split('\t', 1) 915 img = self.font.render(parts[0], True, fg_color) 916 margin = (self.item_height - img.get_height())/2 917 self.surface.blit(img, (x + self.xpadding, y + margin)) 918 img = self.font.render(parts[1], True, fg_color) 919 self.surface.blit(img, 920 (x + self.width - img.get_width() 921 - self.xpadding, 922 y + margin)) 923 else: 924 # center 925 img = self.font.render(item, True, fg_color) 926 margin = (self.item_height - img.get_height())/2 927 self.surface.blit(img, 928 (x + (self.width - img.get_width())/2, 929 y + margin)) 865 930 for ax in (0, self.width-1): 866 931 for ay in (0, self.item_height-1): … … 875 940 surface.blit(self.surface, (x, y), 876 941 (0, self.top, self.width, self.height)) 942 943 944 class HUDControlsMenu(HUDMenu): 945 """A scrolling menu for keyboard controls.""" 946 947 def __init__(self, font, items, xalign=0.5, yalign=0.5, 948 xpadding=8, ypadding=4, yspacing=2): 949 HUDMenu.__init__(self, font, items, xalign, yalign, xpadding, 950 ypadding, yspacing) 951 952 def position(self, surface, margin=10): 953 """Calculate screen position for the widget.""" 954 width = surface.get_width() - 2 * margin - 2 * self.xpadding 955 if width != self.width: 956 self.width = width 957 self.resize() 958 return HUDMenu.position(self, surface, margin) 877 959 878 960 … … 915 997 916 998 999 class HUDMessage(HUDElement): 1000 """An message box.""" 1001 1002 fg_color = (220, 255, 255) 1003 bg_color = (24, 120, 14) 1004 1005 def __init__(self, font, text, xpadding=16, ypadding=16, xalign=0.5, 1006 yalign=0.5): 1007 width, height = font.size(text) 1008 width += 2*xpadding 1009 height += 2*ypadding 1010 HUDElement.__init__(self, width, height, xalign, yalign) 1011 self.xpadding = xpadding 1012 self.ypadding = ypadding 1013 self.font = font 1014 self.text = text 1015 self.surface = pygame.Surface((self.width, self.height)) 1016 self.surface.set_alpha(255 * 0.9) 1017 self.surface.set_colorkey((1, 1, 1)) 1018 self.surface.fill(self.bg_color) 1019 img = self.font.render(text, True, self.fg_color) 1020 x = (self.width - img.get_width()) / 2 1021 y = (self.height - img.get_height()) / 2 1022 self.surface.blit(img, (x, y)) 1023 for dx, dy in (0, 0), (1, 0), (0, 1): 1024 self.surface.set_at((dx, dy), (1, 1, 1)) 1025 self.surface.set_at((self.width-1-dx, dy), (1, 1, 1)) 1026 self.surface.set_at((dx, self.height-1-dy), (1, 1, 1)) 1027 self.surface.set_at((self.width-1-dx, self.height-1-dy), (1, 1, 1)) 1028 1029 def draw(self, surface): 1030 """Draw the element.""" 1031 x, y = self.position(surface) 1032 surface.blit(self.surface, (x, y)) 1033 1034 917 1035 class UIMode(object): 918 1036 """Mode of user interface. … … 978 1096 def handle_key_press(self, event): 979 1097 """Handle a KEYDOWN event.""" 980 handler_and_args = self._keymap_once.get(event.key) 1098 key = event.key 1099 if key in self.ui.rev_controls: 1100 action = self.ui.rev_controls[key] 1101 if action in self._keymap_once or action in self._keymap_repeat: 1102 key = action 1103 handler_and_args = self._keymap_once.get(key) 981 1104 if handler_and_args: 982 1105 handler, args = handler_and_args 983 1106 handler(*args) 984 elif event.key not in self._keymap_repeat:1107 elif key not in self._keymap_repeat: 985 1108 self.handle_any_other_key(event) 986 1109 … … 992 1115 """Handle any keys that are pressed.""" 993 1116 for key, (handler, args) in self._keymap_repeat.items(): 1117 key = self.ui.controls.get(key, key) 994 1118 if pressed[key]: 995 1119 handler(*args) … … 1086 1210 """Initialize the mode.""" 1087 1211 self.init_menu() 1088 self.menu = HUDMenu(self.ui.menu_font, 1089 [item[0] for item in self.menu_items]) 1212 self.menu = self.create_menu() 1213 if self.has_no_action(self.menu.selected_item): 1214 self.select_next_item() 1090 1215 self.on_key(K_UP, self.select_prev_item) 1091 1216 self.on_key(K_DOWN, self.select_next_item) … … 1108 1233 ] 1109 1234 1235 def create_menu(self): 1236 """Create the menu control for display.""" 1237 return HUDMenu(self.ui.menu_font, 1238 [item[0] for item in self.menu_items]) 1239 1240 def has_no_action(self, item_idx): 1241 """Is this menu item just an unselectable label?""" 1242 return len(self.menu_items[item_idx]) == 1 1243 1110 1244 def reinit_menu(self): 1111 1245 """Reinitialize the menu.""" … … 1118 1252 """Select menu item under cursor.""" 1119 1253 which = self.menu.find(self.ui.screen, pos) 1120 if which != -1 :1254 if which != -1 and not self.has_no_action(which): 1121 1255 self.menu.selected_item = which 1122 1256 return which … … 1154 1288 self.menu.selected_item = len(self.menu.items) 1155 1289 self.menu.selected_item -= 1 1290 if self.has_no_action(self.menu.selected_item): 1291 self.select_prev_item() 1156 1292 1157 1293 def select_next_item(self): … … 1160 1296 if self.menu.selected_item == len(self.menu.items): 1161 1297 self.menu.selected_item = 0 1298 self.menu.top = 0 1299 if self.has_no_action(self.menu.selected_item): 1300 self.select_next_item() 1162 1301 1163 1302 def activate_item(self): 1164 1303 """Activate the selected menu item.""" 1165 1304 action = self.menu_items[self.menu.selected_item][1:] 1166 handler = action[0] 1167 args = action[1:] 1168 handler(*args) 1305 if action: 1306 handler = action[0] 1307 args = action[1:] 1308 handler(*args) 1169 1309 1170 1310 def close_menu(self): … … 1218 1358 or 'Show missile orbits', 1219 1359 self.toggle_missile_orbits), 1360 ('Controls', self.ui.controls_menu), 1220 1361 ('Return to main menu', self.close_menu), 1221 1362 ] … … 1263 1404 self.ui.switch_to_mode(mode) 1264 1405 self.reinit_menu() 1406 1407 1408 class ControlsMenuMode(MenuMode): 1409 """Mode: controls menu.""" 1410 1411 def items(self, label, items): 1412 return ([(label, )] + 1413 [(title + '\t' + key_name(self.ui.controls[action]), 1414 self.set_control, title, action) 1415 for title, action in items]) 1416 1417 def init_menu(self): 1418 self.menu_items = self.items('Player 1', [ 1419 ('Turn left', 'P1_LEFT'), 1420 ('Turn right', 'P1_RIGHT'), 1421 ('Accelerate', 'P1_FORWARD'), 1422 ('Decelerate', 'P1_BACKWARD'), 1423 ('Launch missile', 'P1_FIRE'), 1424 ('Brake', 'P1_BRAKE'), 1425 ('Toggle computer control', 'P1_TOGGLE_AI'), 1426 ]) + self.items('Player 2', [ 1427 ('Turn left', 'P2_LEFT'), 1428 ('Turn right', 'P2_RIGHT'), 1429 ('Accelerate', 'P2_FORWARD'), 1430 ('Decelerate', 'P2_BACKWARD'), 1431 ('Launch missile', 'P2_FIRE'), 1432 ('Brake', 'P2_BRAKE'), 1433 ('Toggle computer control', 'P2_TOGGLE_AI'), 1434 ]) + [ 1435 ('Return to options menu', self.close_menu), 1436 ] 1437 1438 def create_menu(self): 1439 """Create the menu control for display.""" 1440 return HUDControlsMenu(self.ui.input_font, 1441 [item[0] for item in self.menu_items]) 1442 1443 def set_control(self, action, key): 1444 """Change a control""" 1445 self.ui.ui_mode = WaitingForControlMode(self.ui, action, key) 1446 1447 1448 class WaitingForControlMode(UIMode): 1449 """Mode: controls menu, waiting for a key press.""" 1450 1451 inherit_pause_from_prev_mode = True 1452 1453 def __init__(self, ui, action, key): 1454 self.action = action 1455 self.key = key 1456 UIMode.__init__(self, ui) 1457 1458 def init(self): 1459 self.prompt = HUDMessage(self.ui.menu_font, 1460 "Press a key or ESC to cancel") 1461 self.on_key(K_PAUSE, self.ui.pause) 1462 self.on_key(K_ESCAPE, self.return_to_previous_mode) 1463 1464 def draw(self, screen): 1465 """Draw extra things pertaining to the mode.""" 1466 self.prev_mode.draw(screen) 1467 self.prompt.draw(screen) 1468 1469 def handle_any_other_key(self, event): 1470 """Handle a KEYDOWN event for unknown keys.""" 1471 self.ui.set_control(self.key, event.key) 1472 self.prev_mode.reinit_menu() 1473 self.return_to_previous_mode() 1474 1475 def handle_mouse_release(self, event): 1476 """Handle a MOUSEBUTTONUP event.""" 1477 self.return_to_previous_mode() 1265 1478 1266 1479 … … 1296 1509 self.while_key(K_MINUS, self.ui.zoom_out) 1297 1510 # Player 1 1298 self.on_key( K_1, self.ui.toggle_ai, 0)1299 self.while_key( K_LEFT, self.ui.turn_left, 0)1300 self.while_key( K_RIGHT, self.ui.turn_right, 0)1301 self.while_key( K_UP, self.ui.accelerate, 0)1302 self.while_key( K_DOWN, self.ui.backwards, 0)1303 self.while_key( K_RALT, self.ui.brake, 0)1304 self.on_key( K_RCTRL, self.ui.launch_missile, 0)1511 self.on_key('P1_TOGGLE_AI', self.ui.toggle_ai, 0) 1512 self.while_key('P1_LEFT', self.ui.turn_left, 0) 1513 self.while_key('P1_RIGHT', self.ui.turn_right, 0) 1514 self.while_key('P1_FORWARD', self.ui.accelerate, 0) 1515 self.while_key('P1_BACKWARD', self.ui.backwards, 0) 1516 self.while_key('P1_BRAKE', self.ui.brake, 0) 1517 self.on_key('P1_FIRE', self.ui.launch_missile, 0) 1305 1518 # Player 2 1306 self.on_key( K_2, self.ui.toggle_ai, 1)1307 self.while_key( K_a, self.ui.turn_left, 1)1308 self.while_key( K_d, self.ui.turn_right, 1)1309 self.while_key( K_w, self.ui.accelerate, 1)1310 self.while_key( K_s, self.ui.backwards, 1)1311 self.while_key( K_LALT, self.ui.brake, 1)1312 self.on_key( K_LCTRL, self.ui.launch_missile, 1)1519 self.on_key('P2_TOGGLE_AI', self.ui.toggle_ai, 1) 1520 self.while_key('P2_LEFT', self.ui.turn_left, 1) 1521 self.while_key('P2_RIGHT', self.ui.turn_right, 1) 1522 self.while_key('P2_FORWARD', self.ui.accelerate, 1) 1523 self.while_key('P2_BACKWARD', self.ui.backwards, 1) 1524 self.while_key('P2_BRAKE', self.ui.brake, 1) 1525 self.on_key('P2_FIRE', self.ui.launch_missile, 1) 1313 1526 1314 1527 def handle_mouse_release(self, event): … … 1405 1618 mouse_visible = True 1406 1619 1407 def draw(self, screen):1408 """Draw extra things pertaining to the mode."""1409 self.help_text.draw(screen)1410 1411 1620 def init(self): 1412 1621 """Initialize the mode.""" … … 1420 1629 self.help_text = HUDFormattedText(self.ui.help_font, 1421 1630 self.ui.help_bold_font, 1422 HELP_TEXT, 1631 fixup_keys_in_text(HELP_TEXT, 1632 self.ui.controls), 1423 1633 small_font=self.ui.hud_font) 1634 1635 def draw(self, screen): 1636 """Draw extra things pertaining to the mode.""" 1637 self.help_text.draw(screen) 1424 1638 1425 1639 def handle_mouse_release(self, event): … … 1472 1686 def __init__(self): 1473 1687 self.rng = random.Random() 1688 self.controls = dict(DEFAULT_CONTROLS) 1689 self.rev_controls = dict([(value, key) 1690 for (key, value) in self.controls.items()]) 1691 assert len(self.controls) == len(self.rev_controls) 1474 1692 1475 1693 def init(self): … … 1752 1970 self.ui_mode = ScreenResolutionMenuMode(self) 1753 1971 1972 def controls_menu(self): 1973 """Enter the controls menu.""" 1974 self.ui_mode = ControlsMenuMode(self) 1975 1754 1976 def watch_demo(self): 1755 1977 """Go back to demo mode.""" … … 1797 2019 self.fullscreen_mode = mode 1798 2020 self._set_display_mode() 2021 2022 def set_control(self, action, key): 2023 """Change a key mapping""" 2024 if key in self.rev_controls: 2025 old_action = self.rev_controls[key] 2026 self.controls[old_action] = None 2027 self.controls[action] = key 2028 self.rev_controls[key] = action 1799 2029 1800 2030 def zoom_in(self):
