Python入门 Junior-做个小游戏-做个弹珠小游戏吧(7)

书接上回,还有个问题没解决:

* 小球在向下运动时,碰到档板会反弹,没碰到就消失了,死掉了 :(


想想,反弹这事我们做过。在窗口的上下左右边界上用if做了判断。

现在的目标是下边界,在做判断的时候增加上档板。

原先的在 ball_move() 函数中的相关代码如下:

 # 检测上下边界
if new_y < ball['ball_radius']: # 上边界
new_y = ball['ball_radius']
ball['ball_yspeed'] *= -1
elif new_y > WINDOW_HIGH - ball['ball_radius']-Line_weigh: # 下边界
new_y = WINDOW_HIGH - ball['ball_radius']-Line_weigh
# 检测是否碰到线(拍子)
if new_x > lines[0]['line_start_point'][0] and new_x < lines[0]['line_end_point'][0]:
ball['ball_yspeed'] *= -1
else:
ball['ball_alive'] = False

我们需要修改下边界这部分的代码。

先不着急开始修改,还需要解决一个问题:小球在向下运动时,如果没有碰到档板,就会消失,死掉了。

怎么表达小球死掉这件事呢?我们新还记得用于表示小球的列表变量吧 balls = [],里面用字典类型保存了多个小球的信息,现在可以在增加一项 ball_alive,如果小球活着就是True, 如果死了就是False。然后,在 ball_redraw 函数里进行判读,如果是True就重画, 如果是False就从balls 列表中移除这一项。

想明白方法就可以开始干活了,要改动的地方比较多。顺着刚才的思路,一个一个地修改。

1、修改 creat_ball 函数,如下:

def creat_ball(window, pos):
# 画球
temp_ball = {
'ball_center': pos,
'ball_radius': Ball_radius,
'ball_xspeed': my_randint(-5,5),
'ball_yspeed': my_randint(-5,5),
'ball_alive': True
}
balls.append(temp_ball)
# print(balls)
# 画球
pygame.draw.circle(window, White, pos, Ball_radius, Ball_radius)

pygame.display.update() # flip后面用update

2、修改ball_move 函数,代码片断如下

 # 检测上下边界
if new_y < ball['ball_radius']: # 上边界
new_y = ball['ball_radius']
ball['ball_yspeed'] *= -1
elif new_y > WINDOW_HIGH - ball['ball_radius']-Line_weigh: # 下边界
new_y = WINDOW_HIGH - ball['ball_radius']-Line_weigh
# 检测是否碰到线(拍子)
if new_x > lines[0]['line_start_point'][0] and new_x < lines[0]['line_end_point'][0]:
ball['ball_yspeed'] *= -1
else:
ball['ball_alive'] = False

3、修改ball_redraw函数,代码如下

def ball_redraw(window):
window.fill(Black) # 窗口背景色重新置成黑色,球就没了

for ball in balls:
if ball['ball_alive']:
pygame.draw.circle(window, White, ball['ball_center'],ball['ball_radius'])
else:
balls.remove(ball)
pygame.display.update()
# 每10毫秒刷新一次
pygame.time.delay(10)


RUN一下,没问题,搞定!

完整代码如下,共182行,包括空白行。

import pygame
import random

WINDOW_WIDTH = 600 # 屏幕宽度
WINDOW_HIGH = 400 # 屏幕高度

Black = (0, 0, 0)
White = (255, 255, 255)
Red = (255, 0, 0)

lines = []
Line_length = 100
Line_weigh = 10
Line_color = Red
Line_speed = 2

balls = []
Ball_radius = 20
Ball_xspeed = 1
Ball_yspeed = 4


# random.randint(-5,5)用于生成X,Y方向,如果其中一个是0,或者全是0
# 会造成生成的球垂直或水平或原地不动,不妥
# 故做以下函数
def my_randint(start, end):

while True:
x = random.randint(start, end)
if x != 0:
break
return x


def create_line(window):
# 在指定的位置画线
# 保存线的信息
line_start_point = (WINDOW_WIDTH/2-Line_length/2, WINDOW_HIGH-Line_weigh)
line_end_point = (WINDOW_WIDTH/2+Line_length/2, WINDOW_HIGH-Line_weigh)
temp_line = {
'line_start_point': line_start_point,
'line_end_point': line_end_point,
'line_length': Line_length
}
lines.append(temp_line)
# 画线
pygame.draw.line(window, Line_color, line_start_point, line_end_point, Line_weigh)

pygame.display.update() # 第一次flip后面用update


def line_move():
pos = pygame.mouse.get_pos()
line_start_point = (pos[0]-Line_length/2, WINDOW_HIGH-Line_weigh)
line_end_point = (pos[0] + Line_length / 2, WINDOW_HIGH-Line_weigh)

lines[0]['line_start_point'] = line_start_point
lines[0]['line_end_point'] = line_end_point


def line_redraw(window):
pygame.draw.line(window, Line_color, lines[0]['line_start_point'], lines[0]['line_end_point'], Line_weigh)
pygame.display.update()
pygame.time.delay(50)


def creat_ball(window, pos):
# 画球
temp_ball = {
'ball_center': pos,
'ball_radius': Ball_radius,
'ball_xspeed': my_randint(-5,5),
'ball_yspeed': my_randint(-5,5),
'ball_alive': True
}

balls.append(temp_ball)
# print(balls)
# 画球
pygame.draw.circle(window, White, pos, Ball_radius, Ball_radius)

pygame.display.update() # flip后面用update


def ball_move():
# 计算每个球的新坐标
for ball in balls:
# 获取球的新的原点
ball_x, ball_y = ball['ball_center']
new_x = ball_x + ball['ball_xspeed']
new_y = ball_y + ball['ball_yspeed']

# 检测两边的边界
if new_x < ball['ball_radius']:
new_x = ball['ball_radius']
ball['ball_xspeed'] *= -1
elif new_x > WINDOW_WIDTH - ball['ball_radius']:
new_x = WINDOW_WIDTH - ball['ball_radius']
ball['ball_xspeed'] *= -1

# 检测上下边界
if new_y < ball['ball_radius']: # 上边界
new_y = ball['ball_radius']
ball['ball_yspeed'] *= -1
elif new_y > WINDOW_HIGH - ball['ball_radius']-Line_weigh: # 下边界
new_y = WINDOW_HIGH - ball['ball_radius']-Line_weigh
# 检测是否碰到线(拍子)
if new_x > lines[0]['line_start_point'][0] and new_x < lines[0]['line_end_point'][0]:
ball['ball_yspeed'] *= -1
else:
ball['ball_alive'] = False

# 修改圆心坐标
ball['ball_center'] = new_x, new_y

# 检测球碰撞,每个球是否和其他的球的圆心距小于等于两个半径
# 把球碰撞当做完全弹性碰撞

# 球碰撞后如何处理
# 如果像碰壁一样处理(X,Y SPEED* -1),效果完成不符合物理规则
# 可以两个球互相交换速度
for other in balls:
if ball == other or ball['ball_alive'] == False or other['ball_alive'] == False:
continue
# 判断两个球是否相撞
other_x, other_y = other['ball_center']
# 算两个球的圆心距
center_distance = ((ball_x-other_x)**2 + (ball_y-other_y)**2)**0.5
# 相撞后
if center_distance <= Ball_radius*2:

# 对心碰撞后,两个球互换方向
ball['ball_xspeed'],other['ball_xspeed'] = other['ball_xspeed'],ball['ball_xspeed']
ball['ball_yspeed'], other['ball_yspeed'] = other['ball_yspeed'], ball['ball_yspeed']

new_x = ball_x + ball['ball_xspeed']
new_y = ball_y + ball['ball_yspeed']
ball['ball_center'] = new_x, new_y

new_x = other_x + other['ball_xspeed']
new_y = other_y + other['ball_yspeed']
other['ball_center'] = new_x, new_y


def ball_redraw(window):
window.fill(Black) # 窗口背景色重新置成黑色,球就没了
for ball in balls:
if ball['ball_alive']:
pygame.draw.circle(window, White, ball['ball_center'],ball['ball_radius'])
else:
balls.remove(ball)
pygame.display.update()
# 每10毫秒刷新一次
pygame.time.delay(10)


def main_game():
# 初始化游戏

pygame.init()
# 定义窗体,指定大小
window = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HIGH))
# 指定窗体的标题
pygame.display.set_caption("PingPang")
# 指定窗体底色
window.fill(Black)
# 显示窗体
pygame.display.flip()

create_line(window)

while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
if event.type == pygame.MOUSEBUTTONDOWN:
creat_ball(window, event.pos)
ball_move()
ball_redraw(window)

line_move()
line_redraw(window)


if __name__ == '__main__':
main_game()

到现在,我们开始设想的功能都实现了,就是看起来比较粗糙。


分享到:


相關文章: