python实现的“打砖块”游戏 Brick & Ball in Python

根据摩托罗拉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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Python制作打砖块游戏中,可以使用以下数据结构来实现游戏系统: 1. 二维数组:用于表示砖块的位置和类型。可以使用列表嵌套列表的方式,将砖块的位置和类型存储在二维数组中。例如,可以使用以下代码来初始化一个包含10行和10列的砖块数组: ``` brick_array = [[0 for col in range(10)] for row in range(10)] ``` 2. 字典:用于存储不同类型的砖块的耐久度和分值。可以使用字典的方式,将砖块的类型作为键,将砖块的耐久度和分值作为值存储在字典中。例如,可以使用以下代码来定义一个包含3种类型砖块的字典: ``` brick_dict = {'type1': {'durability': 1, 'score': 10}, 'type2': {'durability': 2, 'score': 20}, 'type3': {'durability': 3, 'score': 30}} ``` 3. 列表:用于存储游戏场景中的所有游戏对象。可以使用列表的方式,将挡板、球和砖块等游戏对象存储在列表中。例如,可以使用以下代码来定义一个包含挡板、球和10个砖块的列表: ``` game_objects = [paddle, ball] + bricks ``` 4. 队列:用于存储游戏状态和事件。可以使用队列的方式,将游戏状态和事件存储在队列中,例如,可以使用以下代码来定义一个游戏状态队列: ``` game_state_queue = queue.Queue() game_state_queue.put({'score': 0, 'level': 1, 'lives': 3}) ``` 以上是Python制作打砖块游戏中常用的数据结构,可以根据实际需要进行选择和使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值