python实现的“打砖块”游戏 Brick & Ball in Python
2006-04-19 17:34
886 查看
根据摩托罗拉C289手机的同名游戏写成,使用了Python的curses,因此最好在linux下面运行。最近又用tkinter改写了界面,从而不在受限于curses的支持,还重写的游戏的算法,比以前的运行效率好多了。
1 #!/usr/bin/python 2 # 3 # Brick & Ball in Python 4 # by Jerry Fleming <jerryfleming@etang.com> 5 # 6 # This is a small game adapted from that in Motorola Mobile C289, and my first game in Python :) 7 # 8 # This progrma is best run under linux. Since Windows port of Python has poor curses support, 9 # play it under Windows is not recommended. If you have no linux box available, try Cygwin, 10 # though it too has poor curses support. 11 # 12 # As I am a newbie to Python, please tell me if you have a better implementation or any suggestions. 13 # 14 # TODO: 15 # re-implemente it with wxPython, so one does not have to rely on the ugly curses. 16 # session support. 17 # pausing, especially when confirming 18 # resize terminal at run time 19 # 20 # HISTORY 21 # 2006-04-19: first version 22 # 23 # 24 25 import curses 26 import _curses 27 import thread 28 from time import sleep 29 from string import split 30 from random import randint 31 32 # parameters: adjust them to fit you terminal 33 brick_width = 7 34 brick_gap_x = 1 35 brick_gap_y = 1 36 speed = 0.05 # sleep time to control moving speed of the ball 37 pause = 1 # time to pause 38 39 # terminal initialization 40 stdscr = curses.initscr() 41 curses.noecho() 42 curses.cbreak() 43 curses.curs_set(0) 44 stdscr.keypad(1) 45 screen_height, screen_width = stdscr.getmaxyx() 46 screen_height = screen_height - 1 47 screen_width = screen_width - 1 48 brick_rows = screen_height / 4 49 if brick_rows > 7: brick_rows = 7 50 brick_cols = (screen_width + brick_gap_x) / (brick_width + brick_gap_x) 51 brick_margin = (screen_width - brick_cols * (brick_width + brick_gap_x) + brick_gap_x)/2 52 pad_position = randint(0, screen_width - brick_width) 53 ball_position = [screen_height - 3, randint(0, screen_width - brick_width)] 54 ball_direction = [-1, 1] # abs(tan(a)) must be 1 55 char = '' 56 bricks = [] 57 game_score = 0 58 ScreenSizeError = 'ScreenSizeError' 59 60 tStart = ''' 61 ______ _ _ ___ ______ _ _ _ ______ _ 62 (____ / (_) | | / _ / (____ / | | | (_) (_____ / _ | | 63 ____) ) ____ _ ____| | _ ( (_) ) ____) )_____| | | _ ____ _____) ) _ _| |_| |__ ___ ____ 64 | __ ( / ___) |/ ___) |_/ ) ) _ ( | __ ((____ | | | | | _ / | ____/ | | (_ _) _ / / _ /| _ / 65 | |__) ) | | ( (___| _ ( ( (/ / | |__) ) ___ | | | | | | | | | | | |_| | | |_| | | | |_| | | | | 66 |______/|_| |_|/____)_| /_) /__//_) |______//_____|/_)_) |_|_| |_| |_| /__ | /__)_| |_|/___/|_| |_| 67 (____/ 68 69 70 by Jerry Fleming <jerryfleming@etang.com> 71 72 73 GAME STARTING ... 74 75 (this assumes that your terminal be larger that 130x40) 76 ''' 77 78 tExit = ''' 79 88888 88888 80 88888888888 88 ad88888ba 88 8b d8 d8 88 81 88 "" ,d d8" "8b 88 Y8, ,8P ,8P' 88 82 88 88 "" a8P 88 Y8, ,8P d8" 88 83 88aaaaa 8b, ,d8 88 MM88MMM ,a8P" 88 "8aa8" ,8P' 8b,dPPYba, 88 84 88""""" `Y8, ,8P' 88 88 d8" 88 `88' d8" 88P' `"8a 88 85 88 )888( 88 88 "" 88 88 ,8P' 88 88 88 86 88 ,d8" "8b, 88 88, aa 88 88 d8" 88 88 88 87 88888888888 8P' `Y8 88 "Y888 88 88 88 8P' 88 88 88 88 88888 88888 89 ''' 90 91 tOver = ''' 92 ,ad8888ba, 88 93 d8"' `"8b 88 94 d8' 88 95 88 ,adPPYYba, 88,dPYba,,adPYba, ,adPPYba, ,adPPYba, 8b d8 ,adPPYba, 8b,dPPYba, 88 96 88 88888 "" `Y8 88P' "88" "8a a8P_____88 a8" "8a `8b d8' a8P_____88 88P' "Y8 88 97 Y8, 88 ,adPPPPP88 88 88 88 8PP""""""" 8b d8 `8b d8' 8PP""""""" 88 "" 98 Y8a. .a88 88, ,88 88 88 88 "8b, ,aa "8a, ,a8" `8b,d8' "8b, ,aa 88 aa 99 `"Y88888P" `"8bbdP"Y8 88 88 88 `"Ybbd8"' `"YbbdP"' "8" `"Ybbd8"' 88 88 100 ''' 101 102 tGoon = ''' 103 88888 88888 104 ,ad8888ba, ad88888ba 88 8b d8 d8 88 105 d8"' `"8b d8" "8b 88 Y8, ,8P ,8P' 88 106 d8' "" a8P 88 Y8, ,8P d8" 88 107 88 ,adPPYba, ,adPPYba, 8b,dPPYba, ,a8P" 88 "8aa8" ,8P' 8b,dPPYba, 88 108 88 88888 a8" "8a a8" "8a 88P' `"8a d8" 88 `88' d8" 88P' `"8a 88 109 Y8, 88 8b d8 8b d8 88 88 "" 88 88 ,8P' 88 88 88 110 Y8a. .a88 "8a, ,a8" "8a, ,a8" 88 88 aa 88 88 d8" 88 88 88 111 `"Y88888P" `"YbbdP"' `"YbbdP"' 88 88 88 88 88 8P' 88 88 88 112 88888 88888 113 ''' 114 115 def init_game(): 116 '''Game initializing.''' 117 global bricks 118 # display the bricks 119 for row in range(brick_rows): 120 y = row * (1 + brick_gap_y) 121 for col in range(brick_cols): 122 x = col * (brick_gap_x + brick_width) + brick_margin 123 stdscr.addstr(y, x, ' ' * brick_width, curses.A_REVERSE) 124 bricks.append([y, x]) 125 # move the pad to center of bottom at starting up 126 stdscr.addstr(screen_height - 1, pad_position, ' ' * brick_width, curses.A_REVERSE) 127 # move the ball to left bottom side at starting up 128 stdscr.addstr(ball_position[0], ball_position[1], ' ', curses.A_REVERSE) 129 # display score board 130 stdscr.addstr(screen_height, 0, ' SCORE: '+ ('%03d' % game_score) + ' '* 4, curses.A_REVERSE) 131 stdscr.addstr(screen_height, 15, 'USE q to quit' + ' '* (screen_width - 28), curses.A_REVERSE) 132 # final step to init display 133 stdscr.refresh() 134 135 def move_pad(lock): 136 '''Move the pad to catch the ball.''' 137 global char, pad_position 138 char = stdscr.getch() 139 if char == ord('q'): quit_game(lock) 140 if char == curses.KEY_LEFT: pad_position = pad_position - 1 141 if char == curses.KEY_RIGHT: pad_position = pad_position + 1 142 if pad_position < 0: pad_position = 0 143 if pad_position >= screen_width - brick_width: pad_position = screen_width - brick_width 144 stdscr.addstr(screen_height - 1, 0, ' ' * screen_width) 145 stdscr.addstr(screen_height - 1, pad_position, ' ' * brick_width, curses.A_REVERSE) 146 stdscr.refresh() 147 148 def move_ball(lock): 149 '''Move the ball to a direction.''' 150 global ball_position, ball_direction 151 # clear the old position, do not if in pad 152 if ball_position[0] != screen_height - 1: 153 stdscr.addstr(ball_position[0], ball_position[1], ' ') 154 ball_position[0] = ball_position[0] + ball_direction[0] 155 ball_position[1] = ball_position[1] + ball_direction[1] 156 stdscr.addstr(ball_position[0], ball_position[1], ' ', curses.A_REVERSE) 157 detect_collision(lock) 158 stdscr.refresh() 159 sleep(speed) 160 161 def detect_collision(lock): 162 '''Detect whether the ball has hit something, change direction if yes.''' 163 global bricks, ball_direction, game_score 164 # hit upper wall 165 if ball_position[0] == 0 : 166 ball_direction = [- ball_direction[0], ball_direction[1]] 167 # hit left and right wall 168 if ball_position[1] == 0 or ball_position[1] == screen_width: 169 ball_direction = [ball_direction[0], - ball_direction[1]] 170 # hit brick 171 for brick in bricks: 172 # hit from bottom or upper direction 173 if brick[1] <= ball_position[1] + ball_direction[1] <= brick[1] + brick_width / 174 and ball_position[0] + ball_direction[0] == brick[0]: 175 ball_direction[0] = - ball_direction[0] 176 stdscr.addstr(brick[0], brick[1], ' '* brick_width) 177 game_score = game_score + 10 178 stdscr.addstr(screen_height, 8, '%03d' % game_score, curses.A_REVERSE) 179 bricks.remove(brick) 180 # another level to continue the game 181 if not len(bricks): another_level() 182 # hit body of pad 183 if ball_position[0] == screen_height - 2 and pad_position <= ball_position[1] <= pad_position + brick_width: 184 ball_direction[0] = - ball_direction[0] 185 # hit bottom 186 elif ball_position[0] == screen_height - 1: 187 ball_direction[0] = - ball_direction[0] 188 # hit left side of pad (hit bottom already) 189 if ball_position[1] == pad_position and char == curses.KEY_LEFT and ball_direction[1]: 190 ball_direction[1] = - ball_direction[1] 191 # hit right side of pad (hit bottom already) 192 if ball_position[1] == pad_position + brick_width and char == curses.KEY_RIGHT and not ball_direction[1]: 193 ball_direction[1] = - ball_direction[1] 194 # hit bottom wall, game over 195 if ball_position[0] == screen_height - 1 and not pad_position <= ball_position[1] <= pad_position + brick_width: 196 line_num = 0 197 for line in split(tOver, "/n"): 198 stdscr.addstr(screen_height / 2 + line_num, 10, line) 199 line_num = line_num + 1 200 stdscr.refresh() 201 curses.flash() 202 sleep(1) 203 curses.flash() 204 sleep(1) 205 lock.release() 206 207 def quit_game(lock): 208 '''Confirm quit the game.''' 209 global char, speed 210 if char != ord('q'): return 211 speed_old = speed # store the value for resume 212 speed = pause # wait for a long time 213 line_num = 0 214 for line in split(tExit, "/n"): 215 stdscr.addstr(screen_height / 2 + line_num, 10, line) 216 line_num = line_num + 1 217 stdscr.addstr(screen_height, 15, 'USE n to continue, any other key to quit' + ' '* (screen_width - 40), curses.A_REVERSE) 218 stdscr.refresh() 219 #char = stdscr.getch() ## fix me: why can't we use the global char? 220 if char == ord('n'): 221 speed = speed_old 222 line_num = 0 223 for line in split(tExit, "/n"): 224 stdscr.addstr(screen_height / 2 + line_num, 10, ' ' * len(line) ) 225 line_num = line_num + 1 226 stdscr.refresh() 227 else: 228 lock.release() 229 230 def another_level(): 231 '''Confirm another level of the game.''' 232 global speed, char 233 speed_old = speed # store the value for resume 234 speed = pause # wait for a long time 235 line_num = 0 236 for line in split(tGoon, "/n"): 237 stdscr.addstr(screen_height / 2 + line_num, 10, line) 238 line_num = line_num + 1 239 stdscr.addstr(screen_height, 15, 'USE n to quit, any other key to continue' + ' '* (screen_width - 40), curses.A_REVERSE) 240 stdscr.refresh() 241 #char = stdscr.getch() 242 if char == ord('n'): 243 lock.release() 244 else: 245 stdscr.erase() 246 speed = speed / 2 247 init_game() 248 249 def looper(fun, lock): 250 '''Dispatcher to drive th ball and pad.''' 251 try: 252 while lock.locked(): globals()[fun](lock) 253 except _curses.error, diag: 254 if lock.locked(): lock.release() 255 256 # main loop starts here 257 if __name__ == "__main__": 258 try: 259 line_num = 0 260 for line in split(tStart, "/n"): 261 stdscr.addstr(screen_height /4 + line_num, 10, line) 262 line_num = line_num + 1 263 stdscr.refresh() 264 sleep(1) 265 stdscr.erase() 266 init_game() 267 locks = [] 268 for i in range(2): 269 lock = thread.allocate_lock() 270 lock.acquire() 271 locks.append(lock) 272 thread.start_new_thread(looper, ('move_ball', locks[0])) 273 thread.start_new_thread(looper, ('move_pad', locks[1])) 274 while locks[0].locked() and locks[1].locked: pass # main loop 275 except _curses.error, diag: 276 msg = 'Your terminal is too small: ' + str(diag) 277 except 'dd': 278 msg = 'Game exit abnormally.' 279 else: 280 msg = 'Game stopped.' 281 # out of loop means stop 282 for i in range(2): 283 if locks[i].locked(): locks[i].release() 284 height, width = stdscr.getmaxyx() 285 if height - 1 < screen_height or width - 1 < screen_width: 286 msg = 'Your terminal is shrinked.' 287 # out of loop means stop 288 curses.curs_set(1) 289 stdscr.keypad(0) 290 curses.nocbreak() 291 curses.echo() 292 curses.endwin() 293 print msg 294
相关文章推荐
- 打小球游戏(Brick & Ball)最终完美版:C语言实现
- python核心编程第六章题目:python代码实现:设计一个"石头,剪子,布"游戏
- 女朋友用Python实现的猜数字游戏:)
- Pinball in python
- 用python的TK模块实现猜成语游戏(附源码)
- ECshop中defined('IN_ECS')的实现原理
- <Machine Learning in Action >之二 朴素贝叶斯 C#实现文章分类
- python实现的简单文本类游戏实例
- python (5分钟实现一个游戏的屏蔽敏感字系统,)
- <cocos2d-x for wp7>使用cocos2d-x和BOX2D来制作一个BreakOut(打砖块)游戏(二)
- LINQ to Entities 实现sql 关键字"In"方式总结
- leetcode 【 Reverse Words in a String 】python 实现
- 游戏开发设计模式之状态模式 & 有限状态机 & c#委托事件(unity3d 示例实现)
- 排序算法C++&&Python实现---冒泡排序
- Python实现的简单hangman游戏实例
- 用IFormatter实现>存储容器(功能:实现游戏保存和读取).
- 数据挖掘之----使用 Python & Flask 实现 RESTful Web API
- 简单实现python数独游戏
- LINQ to Entities 实现sql 关键字"In"方式总结
- 我的Android进阶之旅------>Android疯狂连连看游戏的实现之状态数据模型(三)