python - 在pygame中移动彗星
问题描述
我希望 pygame 中的 commet 可以在屏幕上拍摄。这是我的彗星课
class Commet:
def __init__(self):
self.x = -10
self.y = 10
self.radius = 20
self.commet = pygame.image.load(r"C:\Users\me\OneDrive\Documents\A level python codes\final game\commet.png")
self.commet = pygame.transform.scale(self.commet, (self.radius, self.radius))
self.drop = 0.0000009
self.speed = 2
self.pos = 0
self.commets = []
然后我在列表中添加了 20 条评论self.commets
。
def tail(self, n): # n is a variable used to denote the length of the self.commets
for i in range(n):
if len(self.commets) <= n - 1:
self.commets.append(Commet())
我有两个问题。第一个问题是移动彗星。为了移动它,我这样做了
def move_tail(self):
for c in self.commets:
c.x += self.speed
for i in range(len(self.commets) - 1):
self.commets[i].y += ((self.commets[i + 1].x) ** 2) * self.drop
对于 x 坐标,我只是在每帧的值上加了 2。但是,对于彗星的y
价值,我希望它产生类似尾巴的跟随效果。我尝试将 commet 的值分配给我们在列表中引用的 commet 上方一个索引位置的 commet 值y
的平方。我希望这些 commet 沿着一般的 x = y ** 2 二次方相互跟随曲线。它们确实遵循曲线但都以相同的速率(我希望它们以不同的速率遵循,因为所有彗星都有不同的 x 值),这给了我类似尾巴的效果。我怎样才能产生这种尾巴般的效果?x
self.commets
我的问题的第二部分是我希望第一个之后的 commets 越来越小。我尝试减小该radius
值,该值用于缩放我导入的图像。代码看起来像这样
# Decrease radius
for i in range(n):
self.commets[i].radius = i + 1
当我在控制台上打印出 commets 的半径值时,它们的范围从 1 到 20,正如我所期望的那样,但屏幕上显示的图像大小对于列表中的所有 commets 都是相同的。以下代码是我如何 blit commet
for i in range(n):
self.commets[i].pos = i * 10 # This line maintains a certain x- distance between commets
for c in self.tails:
D.blit(c.commet, (c.x - c.pos, c.y))
if self.pos >= n:
self.pos = n
解决方案
假设您希望彗星在全高清屏幕上从左到右飞行。
彗星将从左侧y坐标900处开始,然后在x=1400和y=100处到达最高点,然后在屏幕右侧下降到600处。
抛物线通常是 y = ax²+bx+c。
为了独立于屏幕分辨率,您当然会从某个百分比计算这些值,例如 900 ~ 屏幕高度 * 83%、600 ~ 屏幕高度 * 55%、1400 ~ 屏幕宽度 * 73%、100 ~ 屏幕高度 * 9 %
给出三点,您可以计算抛物线:
class ParabolaFrom3Points:
def __init__(self, points: list):
self.a = (points[0][0] * (points[1][1] - points[2][1]) + points[1][0] * (
points[2][1] - points[0][1]) + points[2][0] * (points[0][1] - points[1][1])) / (
(points[0][0] - points[1][0]) * (points[0][0] - points[2][0]) * (
points[2][0] - points[1][0]))
self.b = (points[0][0] ** 2 * (points[1][1] - points[2][1]) + points[1][0] ** 2 * (
points[2][1] - points[0][1]) + points[2][0] ** 2 * (points[0][1] - points[1][1])) / (
(points[0][0] - points[1][0]) * (points[0][0] - points[2][0]) * (
points[1][0] - points[2][0]))
self.c = (points[0][0] ** 2 * (points[1][0] * points[2][1] - points[2][0] * points[1][1]) +
points[0][0] * (points[2][0] ** 2 * points[1][1] - points[1][0] ** 2 * points[2][1]) +
points[1][0] * points[2][0] * points[0][1] * (points[1][0] - points[2][0])) / (
(points[0][0] - points[1][0]) * (points[0][0] - points[2][0]) * (
points[1][0] - points[2][0]))
def y(self, x: int) -> int:
return int(self.a * x ** 2 + self.b * x + self.c)
那么彗星就很简单了。它只需要知道它的抛物线函数,然后就可以从 x 计算 y。
class Comet:
def __init__(self, radius: int, para: ParabolaFrom3Points):
self.x = -radius # Be invisible at the beginning
self.radius = radius
self.para = para
def move(self, x):
self.x = x
def paint(self, screen):
x = self.x
radius = self.radius
for tail in range(20):
pygame.draw.circle(screen, [255, 255, 255], (int(x), self.para.y(x)), radius)
x = x - radius / 2
radius -= 1
测试代码:
import pygame
pygame.init()
pygame.fastevent.init()
clock = pygame.time.Clock()
window = pygame.display.set_mode((1920, 1080))
pygame.display.set_caption('Comet example')
comet = Comet(20, ParabolaFrom3Points([(0, 1080 * 0.83), (1920 * 0.73, 1080 * 0.12), (1920, 1080 * 0.55)]))
for x in range(-20, 1920 + 200, 3):
comet.move(x)
comet.paint(window)
clock.tick(90)
pygame.display.flip()
window.fill([0, 0, 0])
pygame.quit()
推荐阅读
- arrays - 使用唯一的 Int 仅显示 SwiftUI 中的数组选择
- sql - 用于除法和乘法的 SQL Server 计算列公式
- reactjs - WebChat 中的 BotFramework v4 在消息后显示机器人的名称和用户名
- javascript - Vue,Vuetify 没有正确初始化
- python - 带有 attrs 的 PyTorch 模块无法获取参数列表
- python-3.x - 如何在保持索引到位的同时将新列分配给 Pandas 数据框?
- c# - 如何通过 C# Selenium 错误页面?
- powershell - 如何在PowerShell中检查字符串是否不包含很多子字符串
- javascript - 如何在一个 http 请求中使用节点呈现多个 mysql 查询
- tcl - 从 TCL 文件重新创建 Vivado 项目而不复制源代码