这是来自 The Rice的课程 An Introduction to Interactive Programming in Python (Part 1)最后一周的项目,一个乒乓球小游戏,可以分别用上下方向键和 “w” “S”键控制两方对手打乒乓球,最后一个项目相对之前的来说稍微复杂一些,主要完成的思路是先做好拍子,再让拍子按照规则上下移动不超过球台;再做好可以直线运动的球,接触到球桌边缘会直角反弹;最后再根据球是否触拍计分或者重新开始,具体步骤的解析,写在代码的注释里啦
源代码
# Implementation of classic arcade game Pong
import simplegui
import random
# initialize globals - pos and vel encode vertical info for paddles
WIDTH = 600
HEIGHT = 400 # table size
BALL_RADIUS = 20 # ball size
PAD_WIDTH = 8
PAD_HEIGHT = 80 # pad size
HALF_PAD_WIDTH = PAD_WIDTH / 2
HALF_PAD_HEIGHT = PAD_HEIGHT / 2
LEFT = False
RIGHT = True
t = 0
ball_pos = [WIDTH / 2, HEIGHT / 2] # initial position of the ball
# initialize ball_pos and ball_vel for new bal in middle of table
# if direction is RIGHT, the ball's velocity is upper right, else upper left
def spawn_ball(): # spown new ball
global ball_pos, ball_vel # these are vectors stored as lists
ball_pos = [WIDTH / 2, HEIGHT / 2]
ball_vel = [0, 0] # the velocity of ball
ball_vel[1] = - random.randrange(60, 180) / 60 # y axis of the velocity
if LEFT:
ball_vel[0] = random.randrange(120, 240) / 60 # x axis of the velocity
else:
ball_vel[0] = - random.randrange(120, 240) / 60
# define event handlers
def new_game(): # start a new game
global paddle1_pos, paddle2_pos, paddle1_vel, paddle2_vel # these are numbers
global score1, score2 # these are ints
paddle1_vel = 0
paddle2_vel = 0
paddle1_pos = (HEIGHT + PAD_HEIGHT) / 2
paddle2_pos = (HEIGHT + PAD_HEIGHT) / 2
score1 = 0
score2 = 0
spawn_ball()
def draw(canvas): # draw the canvas
global score1, score2, paddle1_pos, paddle2_pos, ball_pos, ball_vel, LEFT, RIGHT
# draw mid line and gutters
canvas.draw_line([WIDTH / 2, 0],[WIDTH / 2, HEIGHT], 1, "White")
canvas.draw_line([PAD_WIDTH, 0],[PAD_WIDTH, HEIGHT], 1, "White")
canvas.draw_line([WIDTH - PAD_WIDTH, 0],[WIDTH - PAD_WIDTH, HEIGHT], 1, "White")
# update ball position
ball_pos[0] += ball_vel[0]
ball_pos[1] += ball_vel[1]
# the ball bounce or game restart when touch the wall---right
if ball_pos[0] + ball_vel[0] >= WIDTH - PAD_WIDTH - BALL_RADIUS:
ball_pos[0] = WIDTH - PAD_WIDTH - BALL_RADIUS
ball_vel[0] = - ball_vel[0]
if paddle2_pos >= ball_pos[1] >= paddle2_pos - PAD_HEIGHT:
score2 += 1 # you win and get 1 score when your pad touch the ball
else:
new_game()
# the ball bounce or game restart when touch the wall---left
if ball_pos[0] + ball_vel[0] <= PAD_WIDTH + BALL_RADIUS:
ball_pos[0] = PAD_WIDTH + BALL_RADIUS
ball_vel[0] = - ball_vel[0]
if paddle1_pos >= ball_pos[1] >= paddle1_pos - PAD_HEIGHT:
score1 += 1 # you win and get 1 score when your pad touch the ball
else:
new_game()
# the ball bounce when touch the wall---up
if ball_pos[1] + ball_vel[1] <= BALL_RADIUS:
ball_pos[1] = BALL_RADIUS
ball_vel[1] = - ball_vel[1]
# the ball bounce when touch the wall---down
if ball_pos[1] + ball_vel[1] >= HEIGHT - BALL_RADIUS:
ball_pos[1] = HEIGHT - BALL_RADIUS
ball_vel[1] = - ball_vel[1]
# draw ball
canvas.draw_circle(ball_pos, BALL_RADIUS, 1, "White")
# update paddle's vertical position by the velocity, keep paddle on the screen
if (paddle1_pos > PAD_HEIGHT and paddle1_vel < 0) or (paddle1_pos < HEIGHT and paddle1_vel > 0):
paddle1_pos += paddle1_vel
if (paddle2_pos > PAD_HEIGHT and paddle2_vel < 0) or (paddle2_pos < HEIGHT and paddle2_vel > 0):
paddle2_pos += paddle2_vel
# draw paddles
canvas.draw_line([PAD_WIDTH / 2, paddle1_pos], [PAD_WIDTH / 2, paddle1_pos - PAD_HEIGHT], PAD_WIDTH, "White")
canvas.draw_line([WIDTH - PAD_WIDTH / 2, paddle2_pos],[WIDTH - PAD_WIDTH / 2, paddle2_pos - PAD_HEIGHT], PAD_WIDTH, "White")
# determine whether paddle and ball collide
if ball_vel[0] > 0:
LEFT = False
elif ball_vel[0] < 0:
LEFT = True
RIGHT = (not LEFT)
# draw scores
canvas.draw_text(str(score1), [30, 20], 20, "White")
canvas.draw_text(str(score2), [550, 20], 20, "White")
def keydown(key):
global paddle1_vel, paddle2_vel
if LEFT: # if the ball move left, you just can move the left pad
if key == simplegui.KEY_MAP['W']:
paddle1_vel = -10
elif key == simplegui.KEY_MAP['S']:
paddle1_vel = 10
if RIGHT: # if the ball move right, you just can move the right pad
if key == simplegui.KEY_MAP['up']:
paddle2_vel = -10
elif key == simplegui.KEY_MAP['down']:
paddle2_vel = 10
def keyup(key): # the pad just move when keydown
global paddle1_vel, paddle2_vel
paddle1_vel = 0
paddle2_vel = 0
# create frame
frame = simplegui.create_frame("Pong", WIDTH, HEIGHT)
frame.set_draw_handler(draw)
frame.set_keydown_handler(keydown)
frame.set_keyup_handler(keyup)
frame.add_button('Restart', new_game, 100)
# start frame
new_game()
frame.start()
运行结果示例