"""多个弹球与矩形碰撞示例程序,本程序用海龟画图模块演示基本的矩形碰撞原理"""
from turtle import Turtle, Screen
from random import choice,randint
class Board(Turtle):
def __init__(self):
"""初始化不可见的矩形"""
Turtle.__init__(self, shape='square', visible=False)
self.penup()
self.color('yellow')
self.shapesize(10, 10)
self.st()
def up_move(self):
"""向上移动10个单位"""
y = self.ycor() + 10
self.sety(y)
def down_move(self):
"""向下移动10个单位"""
y = self.ycor() - 10
self.sety(y)
def left_move(self):
"""向左移动10个单位"""
x = self.xcor() - 10
self.setx(x)
def right_move(self):
"""向右移动10个单位"""
x = self.xcor() + 10
self.setx(x)
class Ball(Turtle):
def __init__(self,board):
"""初始化不可见圆形,参数为矩形"""
Turtle.__init__(self, shape='circle', visible=False)
self.board = board
rect = self.screen.cv.coords(self.board.turtle._item)
self.board_width = abs(rect[0] - rect[2]) # 求矩形宽度
self.board_height = abs(rect[1] - rect[5]) # 求矩形高度
self.penup() # 抬笔
self.color('red') # 设置小球颜色
self.radius = 10 # 海龟画图默认圆形的半径为10
self.sh = self.screen.window_height() # 获取屏幕高度
self.sw = self.screen.window_width() # 获取屏幕的宽度
self.ht()
self.init_move()
def init_move(self):
x = randint(-self.sw // 2, self.sh // 2)
y = randint(-self.sh // 2, self.sw // 2)
# 有些小球会生成在矩形内,可以重新调整位置让小球都生成在矩形外面
self.goto(x, y)
# 设置小球的单位移动距离
self.xspeed = choice([-1,-2,-3,-4,-5,1,2,3,4,5])
self.yspeed = choice([-1,-2,-3,-4,-5,1,2,3,4,5])
self.st()
def move(self):
"""移动"""
x = self.xcor() + self.xspeed
y = self.ycor() + self.yspeed
self.goto(x, y)
# 边缘检测
if abs(self.xcor()) + self.radius >= self.sw // 2:
self.xspeed = -self.xspeed
if abs(self.ycor()) + self.radius >= self.sh // 2:
self.yspeed = -self.yspeed
# 碰到矩形检测
self.collide_board_check()
def collide_board_check(self):
"""矩形碰撞检测"""
board_left = self.board.xcor() - self.board_width//2
board_right = self.board.xcor() + self.board_width//2
board_top = self.board.ycor() + self.board_height//2
board_bottom = self.board.ycor() - self.board_height//2
ball_left = self.xcor() - self.radius
ball_right = self.xcor() + self.radius
ball_top = self.ycor() + self.radius
ball_bottom = self.ycor() - self.radius
# 没有碰到矩形的条件
c1 = ball_right < board_left or ball_left > board_right
c2 = ball_bottom > board_top or ball_top<board_bottom
# 如果没有碰到,直接返回
if c1 or c2 :return
# 在矩形的左边,向右碰撞过去的
if ball_right > board_left and ball_bottom > board_bottom and ball_top<board_top:
self.xspeed = -self.xspeed
return
# 在矩形的右边,向左移动碰撞过去
if ball_left < board_right and ball_bottom > board_bottom and ball_top<board_top:
self.xspeed = -self.xspeed
return
# 在矩形的上边,向下撞过去
if ball_bottom < board_top and ball_left > board_left and ball_right<board_right:
self.yspeed = -self.yspeed
return
# 在矩形的下边,向上撞过去
if ball_top > board_bottom and ball_left > board_left and ball_right<board_right:
self.yspeed = -self.yspeed
return
if __name__ == '__main__':
# 声明一个空列表,用于存放小球对象
ps = []
# 计数
count = 0
# 设置小球总数
amount = 20
# 新建一个屏幕
screen = Screen()
# 设置屏幕背景色
screen.bgcolor('white')
# 设置屏幕宽高
screen.setup(700, 500)
# 设置屏幕标题
screen.title('多个弹球与矩形碰撞示例程序,作者:李兴球')
screen.delay(0)
# 创建挡板对象
d = Board()
screen.onkeypress(d.up_move, 'Up')
screen.onkeypress(d.down_move, 'Down')
screen.onkeypress(d.left_move, 'Left')
screen.onkeypress(d.right_move, 'Right')
screen.update()
screen.listen()
while True:
if count < amount:
p = Ball(d)
ps.append(p)
count += 1
[p.move() for p in ps]
screen.update()
