你好,我是一个非常新的程序员,我正在尝试使球从45度三角形弹起。这是我的代码:
该程序使球碰到窗户的侧面时会弹跳,但我不知道如何使其从三角形弹跳。
import pygame # importing the pygame
import sys # importing the system libraries
import time # importing timer
import random
from pygame.locals import * # importing the locals functions from the pygame library set
pygame.init() # the function from pygame that initializes all relevant variable
# setting length and width
width = 500
length = 300
# colour variables
WHITE = (255,255,255)
BLUE = (0,0,255)
# importing ball image
ball = pygame.image.load('ball.png')
ballRect = ball.get_rect()
ballRect.left = 300
ballRect.right = 300
# setting speed
x_speed = 2
y_speed = 2
# setting window size
WINDOW = pygame.display.set_mode((width, length))# setting the size of the window
pygame.display.update()
# loop
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
ballRect = ballRect.move(x_speed,y_speed)
WINDOW.fill(WHITE) # changing screen colour to white
WINDOW.blit(ball,ballRect) # printing the ball to screen
pygame.display.update()
pygame.display.flip()
time.sleep(0.002) # to slow down the speed of bouncing
pygame.display.update()
# if the left side of ballRect is in a position less than 0, or the right side of ballRect is greater than 500
if ballRect.left < 0 or ballRect.right > (width):
x_speed = x_speed * -1
# if the top of ballRect is in a position less than 0, or the bottom of ballRect is greater than the length
elif ballRect.top < 0 or ballRect.bottom > (length):
y_speed = y_speed * -1
pygame.display.update()
我没有画三角形,因为我不知道要去哪里,但是我希望球像碰到窗户的侧面一样从三角形反弹。任何帮助将是巨大的!
答案 0 :(得分:2)
有趣的任务。可以通过一个简单的列表定义一个三角形:
triangle = [(250, 220), (400, 300), (100, 300)]
绘制三角形
pygame.draw.polygon(WINDOW, RED, triangle, 0)
使用pygame.math.Vector2
定义球的位置和运动矢量:
ballvec = pygame.math.Vector2(1, 1)
ballpos = pygame.math.Vector2(150, 250)
balldiameter = 64
创建一个函数,执行碰撞检测。该功能必须检测球是否命中线。如果击中线,则球的运动矢量将反映在线上。
该线由2个点(lp0
,lp1
)表示,它们是pygame.math.Vector2
个对象。
球(pt
)和运动矢量(dir
)的位置也是pygame.math.Vector2
个对象:
def isect(lp0, lp1, pt, dir, radius):
# direction vector of the line
l_dir = (lp1 - lp0).normalize()
# normal vector to the line
nv = pygame.math.Vector2(-l_dir[1], l_dir[0])
# distance to line
d = (lp0-pt).dot(nv)
# intersection point on endless line
ptX = pt + nv * d
# test if the ball hits the line
if abs(d) > radius or dir.dot(ptX-pt) <= 0:
return dir
if (ptX-lp0).dot(l_dir) < 0 or (ptX-lp1).dot(l_dir) > 0:
return dir
# reflect the direction vector on the line (like a billiard ball)
r_dir = dir.reflect(nv)
return r_dir
将窗口矩形和三角形追加到线列表中。蚀刻线由2个pygame.math.Vector2
对象的元组表示:
# add screen rect
screen_rect = [(0, 0), (0, 300), (500, 300), (500, 0)]
for i in range(len(screen_rect)):
p0, p1 = screen_rect[i], screen_rect[(i+1) % len(screen_rect)]
line_list.append((pygame.math.Vector2(p0[0], p0[1]), pygame.math.Vector2(p1[0], p1[1])))
# add red trianlge
triangle = [(250, 220), (400, 300), (100, 300)]
for i in range(len(triangle)):
p0, p1 = triangle[i], triangle[(i+1) % len(triangle)]
line_list.append((pygame.math.Vector2(p0[0], p0[1]), pygame.math.Vector2(p1[0], p1[1])))
在遍历直线的循环中进行碰撞检测。如果球撞到线,则运动矢量将替换为反射的运动矢量:
for line in line_list:
ballvec = isect(*line, ballpos, ballvec, balldiameter/2)
最后更新球和球矩形的位置:
ballpos = ballpos + ballvec
ballRect.x, ballRect.y = ballpos[0]-ballRect.width/2, ballpos[1]-ballRect.height/2
请参见示例代码,在该示例中,我将建议的更改应用于原始代码。我的球图像的尺寸为64x64。球直径必须设置为此尺寸(balldiameter = 64
):
import pygame # importing the pygame
import sys # importing the system libraries
import time # importing timer
import random
from pygame.locals import * # importing the locals functions from the pygame library set
pygame.init() # the function from pygame that initializes all relevant variable
# setting length and width
width = 500
length = 300
# colour variables
WHITE = (255,255,255)
BLUE = (0,0,255)
RED = (255,0,0)
GRAY = (128,128,128)
# importing ball image
ball = pygame.image.load("ball.png")
ballRect = ball.get_rect()
# setting ball data
ballvec = pygame.math.Vector2(1.5, 1.5)
ballpos = pygame.math.Vector2(150, 250)
balldiameter = 64
# setting window size
WINDOW = pygame.display.set_mode((width, length))# setting the size of the window
def isect(lp0, lp1, pt, dir, radius):
# direction vector of the line
l_dir = (lp1 - lp0).normalize()
# normal vector to the line
nv = pygame.math.Vector2(-l_dir[1], l_dir[0])
# distance to line
d = (lp0-pt).dot(nv)
# intersection point on endless line
ptX = pt + nv * d
# test if the ball hits the line
if abs(d) > radius or dir.dot(ptX-pt) <= 0:
return dir
if (ptX-lp0).dot(l_dir) < 0 or (ptX-lp1).dot(l_dir) > 0:
return dir
# reflect the direction vector on the line (like a billiard ball)
r_dir = dir.reflect(nv)
return r_dir
line_list = []
# add screen rect
screen_rect = [(0, 0), (0, 300), (500, 300), (500, 0)]
for i in range(len(screen_rect)):
p0, p1 = screen_rect[i], screen_rect[(i+1) % len(screen_rect)]
line_list.append((pygame.math.Vector2(p0[0], p0[1]), pygame.math.Vector2(p1[0], p1[1])))
# add red trianlge
triangle = [(250, 220), (400, 300), (100, 300)]
for i in range(len(triangle)):
p0, p1 = triangle[i], triangle[(i+1) % len(triangle)]
line_list.append((pygame.math.Vector2(p0[0], p0[1]), pygame.math.Vector2(p1[0], p1[1])))
# add blue triangle
triangle2 = [(250, 80), (400, 0), (100, 0)]
for i in range(len(triangle2)):
p0, p1 = triangle2[i], triangle2[(i+1) % len(triangle2)]
line_list.append((pygame.math.Vector2(p0[0], p0[1]), pygame.math.Vector2(p1[0], p1[1])))
# loop
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
WINDOW.fill(GRAY)
pygame.draw.polygon(WINDOW, RED, triangle, 0)
pygame.draw.polygon(WINDOW, BLUE, triangle2, 0)
WINDOW.blit(ball,ballRect)
pygame.display.update()
pygame.display.flip()
time.sleep(0.002) # to slow down the speed of bouncing
pygame.display.update()
for line in line_list:
ballvec = isect(*line, ballpos, ballvec, balldiameter/2)
ballpos = ballpos + ballvec
ballRect.x, ballRect.y = ballpos[0]-ballRect.width/2, ballpos[1]-ballRect.height/2
pygame.display.update()