如何让球从pygame中的三角形反弹? [英] How to make ball bounce off triangle in pygame?
问题描述
您好,我是一名相当新的程序员,我正在尝试使球从 45 度三角形上弹起.这是我的代码:
这个程序让球在碰到窗户的边时反弹,但我不知道如何让它从三角形上反弹.
import pygame # 导入 pygameimport sys # 导入系统库import time # 导入计时器随机导入from pygame.locals import * # 从pygame库集中导入locals函数pygame.init() # pygame 中初始化所有相关变量的函数# 设置长宽宽度 = 500长度 = 300# 颜色变量白色 = (255,255,255)蓝色 = (0,0,255)# 导入球图像ball = pygame.image.load('ball.png')ballRect = ball.get_rect()ballRect.left = 300ballRect.right = 300#设置速度x_速度 = 2y_speed = 2# 设置窗口大小WINDOW = pygame.display.set_mode((width, length))#设置窗口大小pygame.display.update()# 环形为真:对于 pygame.event.get() 中的事件:如果 event.type == 退出:pygame.quit()系统退出()ballRect = ballRect.move(x_speed,y_speed)WINDOW.fill(WHITE) # 改变屏幕颜色为白色WINDOW.blit(ball,ballRect) # 将球打印到屏幕上pygame.display.update()pygame.display.flip()time.sleep(0.002) # 减慢弹跳速度pygame.display.update()# 如果 ballRect 左边的位置小于 0,或者 ballRect 右边的位置大于 500如果 ballRect.left <0 或 ballRect.right >(宽度):x_speed = x_speed * -1# 如果ballRect的顶部在小于0的位置,或者ballRect的底部大于长度elif ballRect.top <0 或 ballRect.bottom >(长度):y_speed = y_speed * -1pygame.display.update()
我没有画三角形,因为我不知道从哪里画,但我希望球会像撞到窗户边时那样从三角形反弹.任何帮助都会很棒!
有趣的任务.一个三角形可以通过一个简单的列表来定义:
triangle = [(250, 220), (400, 300), (100, 300)]
三角形可以通过
导入pygamepygame.init()窗口 = pygame.display.set_mode((500, 300))尝试:ball = pygame.image.load("Ball64.png")除了:球 = pygame.Surface((64, 64), pygame.SRCALPHA)pygame.draw.circle(ball, (255, 255, 0), (32, 32), 32)ballvec = pygame.math.Vector2(1.5, 1.5)ballpos = pygame.math.Vector2(150, 250)balldiameter = ball.get_width()defreflect_circle_on_line(lp0, lp1, pt, dir, radius):l_dir = (lp1 - lp0).normalize() # 线的方向向量nv = pygame.math.Vector2(-l_dir[1], l_dir[0]) # 线的法向量d = (lp0-pt).dot(nv) # 到线的距离ptX = pt + nv * d # 无限线上的交点if (abs(d) > radius or dir.dot(ptX-pt) <= 0 or # 测试球是否击中线(ptX-lp0).dot(l_dir) <0 或 (ptX-lp1).dot(l_dir) >0):返回目录r_dir = dir.reflect(nv) # 反映直线上的方向向量(像台球一样)返回 r_dir三角形 1 = [(250, 220), (400, 300), (100, 300)]三角形 2 = [(250, 80), (400, 0), (100, 0)]screen_rect = [(0, 0), (0, window.get_height()), window.get_size(), (window.get_width(), 0)]line_list = []对于 zip(triangle1, triangle1[1:] + triangle1[:1]) 中的 p0, p1:line_list.append((pygame.math.Vector2(p0), pygame.math.Vector2(p1)))对于 zip(triangle2, triangle2[1:] + triangle2[:1]) 中的 p0, p1:line_list.append((pygame.math.Vector2(p0), pygame.math.Vector2(p1)))对于 zip(screen_rect, screen_rect[1:] + screen_rect[:1]) 中的 p0, p1:line_list.append((pygame.math.Vector2(p0), pygame.math.Vector2(p1)))时钟 = pygame.time.Clock()运行 = 真运行时:时钟滴答(250)对于 pygame.event.get() 中的事件:如果 event.type == pygame.QUIT:运行 = 错误对于 line_list 中的行:ballvec =reflect_circle_on_line(*line, ballpos, ballvec, balldiameter/2)ballpos = ballpos + ballvecwindow.fill((64, 64, 64))pygame.draw.polygon(window, (255, 0, 0), triangle1, 0)pygame.draw.polygon(window, (0, 0, 255), triangle2, 0)window.blit(ball, (round(ballpos[0]-balldiameter/2), round(ballpos[1]-balldiameter/2)))pygame.display.flip()pygame.quit()
Hello I'm a pretty new programmer and I'm trying to make a ball bounce off a 45 degree triangle. Here is my code:
This program makes the ball bounce when it hits the sides of the window, but I don't know how to make it bounce off a triangle.
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()
I haven't drawn in the triangle because I don't know where to, but I expect the ball to bounce off the triangle like it does when it hits the sides of the window. Any help would be great!
Interesting task. A triangle can be defined by a simple list:
triangle = [(250, 220), (400, 300), (100, 300)]
The triangle can be drawn by pygame.draw.polygon()
pygame.draw.polygon(WINDOW, RED, triangle, 0)
Use pygame.math.Vector2
to define the position and the motion vector of the ball:
ballvec = pygame.math.Vector2(1, 1)
ballpos = pygame.math.Vector2(150, 250)
balldiameter = 64
Create a function, which does the collision detection. The function has to detect if the ball hits a line. If the line is hit, then the motion vector of the ball is reflected on the line.
The line is represented by 2 points (lp0
, lp1
), which are pygame.math.Vector2
objects.
The position of the ball (pt
) and the motion vector (dir
) are pygame.math.Vector2
objects, too:
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
Append the window rectangle and the triangle to a list of lines. Ech line is represented by a tuple of 2 pygame.math.Vector2
objects:
# 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])))
Do the collision detection in a loop, which traverse the lines. If the ball hits a line, then the motion vector is replaced by the reflected motion vector:
for line in line_list:
ballvec = isect(*line, ballpos, ballvec, balldiameter/2)
Finally update the position of the ball an the ball rectangle:
ballpos = ballpos + ballvec
ballRect.x, ballRect.y = ballpos[0]-ballRect.width/2, ballpos[1]-ballRect.height/2
See the example code, where I applied the suggested changes to your original code. My ball image has a size of 64x64. The ball diameter has to be set to this size (balldiameter = 64
):
Minimal example
import pygame
pygame.init()
window = pygame.display.set_mode((500, 300))
try:
ball = pygame.image.load("Ball64.png")
except:
ball = pygame.Surface((64, 64), pygame.SRCALPHA)
pygame.draw.circle(ball, (255, 255, 0), (32, 32), 32)
ballvec = pygame.math.Vector2(1.5, 1.5)
ballpos = pygame.math.Vector2(150, 250)
balldiameter = ball.get_width()
def reflect_circle_on_line(lp0, lp1, pt, dir, radius):
l_dir = (lp1 - lp0).normalize() # direction vector of the line
nv = pygame.math.Vector2(-l_dir[1], l_dir[0]) # normal vector to the line
d = (lp0-pt).dot(nv) # distance to line
ptX = pt + nv * d # intersection point on endless line
if (abs(d) > radius or dir.dot(ptX-pt) <= 0 or # test if the ball hits the line
(ptX-lp0).dot(l_dir) < 0 or (ptX-lp1).dot(l_dir) > 0):
return dir
r_dir = dir.reflect(nv) # reflect the direction vector on the line (like a billiard ball)
return r_dir
triangle1 = [(250, 220), (400, 300), (100, 300)]
triangle2 = [(250, 80), (400, 0), (100, 0)]
screen_rect = [(0, 0), (0, window.get_height()), window.get_size(), (window.get_width(), 0)]
line_list = []
for p0, p1 in zip(triangle1, triangle1[1:] + triangle1[:1]):
line_list.append((pygame.math.Vector2(p0), pygame.math.Vector2(p1)))
for p0, p1 in zip(triangle2, triangle2[1:] + triangle2[:1]):
line_list.append((pygame.math.Vector2(p0), pygame.math.Vector2(p1)))
for p0, p1 in zip(screen_rect, screen_rect[1:] + screen_rect[:1]):
line_list.append((pygame.math.Vector2(p0), pygame.math.Vector2(p1)))
clock = pygame.time.Clock()
run = True
while run:
clock.tick(250)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
for line in line_list:
ballvec = reflect_circle_on_line(*line, ballpos, ballvec, balldiameter/2)
ballpos = ballpos + ballvec
window.fill((64, 64, 64))
pygame.draw.polygon(window, (255, 0, 0), triangle1, 0)
pygame.draw.polygon(window, (0, 0, 255), triangle2, 0)
window.blit(ball, (round(ballpos[0]-balldiameter/2), round(ballpos[1]-balldiameter/2)))
pygame.display.flip()
pygame.quit()
这篇关于如何让球从pygame中的三角形反弹?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!