以下是要求:(把步骤一、二、三填完)
第一步,在Ball类的update方法中实现小球位置更新,注意小球可以在水平方向横穿画布,因此小球水平位置需要与画布宽度做取余运算。
第二步,在Ball类的update方法中实现小球落到踏板上的条件判断,根据注释分别用代码描述出四个条件。
第三步,实现Ball类的bounce方法。注意从踏板上反弹的时候水平速度不变(不需更新),竖直速度要取反并且至少是小球的 rebound 属性值。
# -*- coding=utf-8 -*-
import simplegui
import random
WIDTH = 800
HEIGHT = 600
STEP_SPACE = 100
STEP_NUMBER = 1000
CLEARANCE = 3 * STEP_SPACE
class Step:
def __init__(self):
""" 创建宽度随机的踏板 """
step_width = random.randrange(100, 160)
self.left = random.randrange(25, WIDTH-(25+step_width))
self.right = self.left + step_width
self.exists = True
class Scene(object):
def __init__(self):
self.offset = 0
def transform(self, pos):
# 把普通坐标系下坐标转换成画布内坐标
return [pos[0], HEIGHT - (pos[1] - self.offset)]
class Ball(object):
"""定义小球类"""
def __init__(self, pos):
""" 初始化小球位置与速度 """
self.size = 5 # 小球半径
self.pos = pos # 小球位置
self.vel = [0, 0] # 小球速度
self.rebound = 7 # 小球回弹初速度
def update(self):
""" 更新绘图处理程序中的小球,所有动作都在这里完成 """
# 重力加速
self.vel[1] -= .1
# 步骤 1: 更新水平和竖直位置,小球可在水平方向横穿画布
pass
# 当前所在层级
current_level = int((self.pos[1]+self.size) / STEP_SPACE)
# 步骤 2: 描述小球落在某个踏板上需满足的四个条件:
# a. 小球正在下落, b. 踏板存在, c. 小球位置的纵坐标在踏板上方一个半径范围内, d. 小球位置的横坐标在踏板左右边界内
# 修改下方各个 condition 使得小球正确反弹
condition1 = False
condition2 = False
condition3 = False
condition4 = False
if condition1 and condition2 and condition3 and condition4:
self.bounce()
if random.random() > .7: # 以一定概率消失踏板
steps[current_level].exists = False
# 如果小球靠近画面顶部,则向上移动场景
if scene.transform(self.pos)[1] < CLEARANCE:
scene.offset = self.pos[1] - (HEIGHT - CLEARANCE)
# 如果从屏幕中落下,重新开始新的一局
if scene.offset - self.pos[1] > STEP_SPACE:
scene.offset = 0
ball.pos = [WIDTH/2, 2*STEP_SPACE]
ball.vel[1] = 0
for i in range(STEP_NUMBER):
steps[i].exists = True
def bounce(self):
""" 反弹 """
# 步骤 3: 实现小球反弹。速度反向,大小至少是 self.rebound
pass
# 为事件处理程序定义回调函数
def keydown(key):
if key == simplegui.KEY_MAP["left"]:
ball.vel[0] = -3
elif key == simplegui.KEY_MAP["right"]:
ball.vel[0] = 3
def keyup(key):
if key == simplegui.KEY_MAP["left"] or key == simplegui.KEY_MAP["right"]:
ball.vel[0] = 0
def draw(canvas):
""" 更新小球位置、绘制小球、绘制可见踏板及其高度 """
ball.update()
canvas.draw_circle(scene.transform(ball.pos), ball.size, 2, "White")
# 绘制场景内踏板
for i in range(int(scene.offset / STEP_SPACE), int((HEIGHT + scene.offset) / STEP_SPACE)+1):
step_height = i * STEP_SPACE
if i < STEP_NUMBER and steps[i].exists:
canvas.draw_line(scene.transform([steps[i].left, step_height]), scene.transform([steps[i].right, step_height]), 4, "Red")
canvas.draw_text(str(step_height), scene.transform([WIDTH-50, step_height]), 12, "Cyan")
# 创建场景
scene = Scene()
# 创建跳跃小球,初始位置:画布中央两个踏板高度处
ball = Ball([WIDTH/2, 2*STEP_SPACE])
# 创建若干个踏板
steps = [Step() for _ in range(STEP_NUMBER)]
# 让第一个踏板覆盖画布的整个底部,这样就不会立即游戏失败
steps[0].left = 0
steps[0].right = WIDTH
# 创建窗口
frame = simplegui.create_frame("Ball Jump", WIDTH, HEIGHT)
# 注册事件处理器
frame.set_keydown_handler(keydown)
frame.set_keyup_handler(keyup)
frame.set_draw_handler(draw)
# 开始游戏
frame.start()
第一步:
def update(self):
# 更新小球的位置
self.x += self.vx
self.y += self.vy
# 小球横穿画布
self.x %= self.canvas_width
第二步:
def update(self):
# 更新小球的位置
self.x += self.vx
self.y += self.vy
# 小球横穿画布
self.x %= self.canvas_width
# 判断小球是否落在踏板上
if self.y > self.paddle.top and self.y < self.paddle.bottom and self.x > self.paddle.left and self.x < self.paddle.right:
# 小球在踏板左侧
if self.x < self.paddle.left + self.paddle.width / 3:
self.vx = -self.rebound
# 小球在踏板中间
elif self.x < self.paddle.left + self.paddle.width * 2 / 3:
self.vx = 0
# 小球在踏板右侧
else:
self.vx = self.rebound
第三步:
def bounce(self):
# 小球反弹
self.vy = -self.vy
# 确保竖直速度至少是小球的rebound属性值
self.vy = max(self.vy, -self.rebound)