code_计梦星河 2025-03-31 22:22 采纳率: 75%
浏览 22
已结题

pygame如何使一张图片绕固定点旋转

如何在pygame中使一张图片绕固定点旋转

import pygame
import math

# 初始化Pygame
pygame.init()

# 设置窗口大小
screen_width, screen_height = 800, 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('投石机模拟')

# 加载图片
catapult_body_image = pygame.image.load('投石机主体.png').convert_alpha()
catapult_lever_image = pygame.image.load('投石机杠杆.png').convert_alpha()
projectile_image = pygame.image.load('投掷物.png').convert_alpha()

# 调整图片缩放比例(可根据实际情况调整)
scale_factor = 0.15
catapult_body_image = pygame.transform.scale(catapult_body_image, (int(catapult_body_image.get_width() * scale_factor),
                                                                  int(catapult_body_image.get_height() * scale_factor)))
catapult_lever_image = pygame.transform.scale(catapult_lever_image, (int(catapult_lever_image.get_width() * scale_factor),
                                                                    int(catapult_lever_image.get_height() * scale_factor)))
projectile_image = pygame.transform.scale(projectile_image, (int(projectile_image.get_width() * scale_factor),
                                                            int(projectile_image.get_height() * scale_factor)))

# 定义颜色
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

# 投石机主体相关坐标
catapult_body_x = 120
catapult_body_y = 450

# 杠杆相关坐标
catapult_lever_x = catapult_body_x - 50
catapult_lever_y = catapult_body_y - 35

# 投掷物相关坐标
projectile_x = catapult_lever_x
projectile_y = catapult_lever_y

# 杠杆长度
lever_length = 150
# 角度
angle = 0
# 配重
counterweight = 50
# 初始速度
initial_velocity = 0
# 杠杆绘制时的y方向偏移量,可根据实际效果调整
lever_y_offset = 20

# 物理参数
gravity = 9.8
# 抛体运动相关
is_projectile_flying = False
time = 0
dt = 0.1

clock = pygame.time.Clock()

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                angle = max(-90, angle - 5)
            elif event.key == pygame.K_RIGHT:
                angle = min(90, angle + 5)
            elif event.key == pygame.K_UP:
                counterweight += 10
                initial_velocity = counterweight * 0.5
            elif event.key == pygame.K_DOWN:
                counterweight = max(10, counterweight - 10)
                initial_velocity = counterweight * 0.5
            elif event.key == pygame.K_SPACE:
                is_projectile_flying = True
                time = 0
                v0x = initial_velocity * math.cos(math.radians(angle))
                v0y = initial_velocity * math.sin(math.radians(angle))

    screen.fill(WHITE)

    # 绘制投石机主体
    screen.blit(catapult_body_image, (catapult_body_x - catapult_body_image.get_width() // 2,
                                      catapult_body_y - catapult_body_image.get_height() // 2))

    # 计算杠杆旋转后的坐标
    rotated_lever = pygame.transform.rotate(catapult_lever_image, -angle)
    lever_center_x = catapult_lever_x
    lever_center_y = catapult_lever_y + lever_y_offset
    lever_rect = rotated_lever.get_rect(center=(lever_center_x, lever_center_y))
    screen.blit(rotated_lever, lever_rect)

    if is_projectile_flying:
        # 抛体运动计算
        projectile_x += v0x * dt
        projectile_y -= v0y * dt - 0.5 * gravity * dt * dt
        if projectile_y > screen_height:
            is_projectile_flying = False
    else:
        # 计算投掷物在杠杆上的坐标
        projectile_x = lever_center_x + lever_length * math.sin(math.radians(angle))
        projectile_y = lever_center_y - lever_length * math.cos(math.radians(angle))

    # 绘制投掷物
    screen.blit(projectile_image, (int(projectile_x - projectile_image.get_width() // 2),
                                   int(projectile_y - projectile_image.get_height() // 2)))

    pygame.display.flip()
    clock.tick(60)

pygame.quit()

这是源代码。实现的功能是投石机

img

img


如图,它事实上已经对齐了,但是现在存在的问题是,按下键盘左右键之后投石机杠杆图片会沿着自己的中点旋转,这就导致投石机动画并不现实。
我的问题是:怎么可以使杠杆部分绕图片最右端旋转且最右端点固定不动。投掷物在杠杆线末端

  • 写回答

5条回答 默认 最新

  • trust Tomorrow 2025-03-31 22:34
    关注
    import pygame
    import math
    
    # 初始化Pygame
    pygame.init()
    
    # 设置窗口大小
    screen_width, screen_height = 800, 600
    screen = pygame.display.set_mode((screen_width, screen_height))
    pygame.display.set_caption('投石机模拟')
    
    # 加载图像
    catapult_body_image = pygame.image.load('投石机主体.png').convert_alpha()
    catapult_lever_image = pygame.image.load('投石机杠杆.png').convert_alpha()
    projectile_image = pygame.image.load('投掷物.png').convert_alpha()
    
    # 调整图像缩放比例
    scale_factor = 0.15
    catapult_body_image = pygame.transform.scale(catapult_body_image, 
                         (int(catapult_body_image.get_width() * scale_factor),
                         int(catapult_body_image.get_height() * scale_factor)))
    catapult_lever_image = pygame.transform.scale(catapult_lever_image, 
                         (int(catapult_lever_image.get_width() * scale_factor),
                         int(catapult_lever_image.get_height() * scale_factor)))
    projectile_image = pygame.transform.scale(projectile_image, 
                       (int(projectile_image.get_width() * scale_factor),
                       int(projectile_image.get_height() * scale_factor)))
    
    # 定义颜色
    WHITE = (255, 255, 255)
    BLACK = (0, 0, 0)
    
    # 投石机主体坐标
    catapult_body_x = 120
    catapult_body_y = 450
    
    # 定义支点(杠杆连接到主体的固定点)
    # 这个点在旋转时保持不动
    pivot_x = catapult_body_x - 30
    pivot_y = catapult_body_y - 20
    
    # 杠杆长度
    lever_length = 150
    # 初始角度
    angle = 0
    # 配重
    counterweight = 50
    # 初始速度
    initial_velocity = 0
    
    # 物理参数
    gravity = 9.8  # 重力加速度
    is_projectile_flying = False  # 投掷物是否在飞行中
    time = 0  # 时间变量
    dt = 0.1  # 时间步长
    
    def rotate_image_around_pivot(image, angle, pivot):
        """
        绕支点旋转图像。
        
        Args:
            image: 要旋转的Pygame Surface
            angle: 旋转角度(顺时针,单位为度)
            pivot: 支点坐标(相对于图像左上角的偏移量)
        """
        # 创建图像的旋转副本
        rotated_image = pygame.transform.rotate(image, -angle)
        
        # 获取旋转后图像的矩形区域
        rotated_rect = rotated_image.get_rect()
        
        # 计算旋转后支点在图像中的位置
        rot_pivot = pygame.math.Vector2(pivot).rotate(-angle)
        
        # 计算旋转后图像的绘制位置
        rotated_rect.topleft = (pivot_x - rot_pivot.x, pivot_y - rot_pivot.y)
        
        return rotated_image, rotated_rect
    
    # 初始化投掷物位置
    projectile_x = pivot_x
    projectile_y = pivot_y
    
    # 创建时钟对象控制帧率
    clock = pygame.time.Clock()
    
    running = True
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.KEYDOWN:
                # 处理键盘输入
                if event.key == pygame.K_LEFT:
                    # 左箭头:减少角度(最大角度为-90度)
                    angle = max(-90, angle - 5)
                elif event.key == pygame.K_RIGHT:
                    # 右箭头:增加角度(最大角度为90度)
                    angle = min(90, angle + 5)
                elif event.key == pygame.K_UP:
                    # 上箭头:增加配重
                    counterweight += 10
                    initial_velocity = counterweight * 0.5  # 根据配重计算初始速度
                elif event.key == pygame.K_DOWN:
                    # 下箭头:减少配重(最小配重为10)
                    counterweight = max(10, counterweight - 10)
                    initial_velocity = counterweight * 0.5  # 根据配重计算初始速度
                elif event.key == pygame.K_SPACE:
                    # 空格键:发射投掷物
                    is_projectile_flying = True
                    time = 0
                    # 计算初始速度的水平和垂直分量
                    v0x = initial_velocity * math.cos(math.radians(angle))
                    v0y = initial_velocity * math.sin(math.radians(angle))
    
        # 填充背景色
        screen.fill(WHITE)
    
        # 绘制投石机主体
        screen.blit(catapult_body_image, (catapult_body_x - catapult_body_image.get_width() // 2,
                                          catapult_body_y - catapult_body_image.get_height() // 2))
        
        # 计算杠杆支点在图像中的位置(右端)
        lever_pivot_x = catapult_lever_image.get_width()  # 杠杆图像的右边缘
        lever_pivot_y = catapult_lever_image.get_height() // 2  # 杠杆图像的垂直中心
        
        # 绕支点旋转杠杆
        rotated_lever, lever_rect = rotate_image_around_pivot(
            catapult_lever_image, 
            angle, 
            (lever_pivot_x, lever_pivot_y)
        )
        
        # 绘制旋转后的杠杆
        screen.blit(rotated_lever, lever_rect)
    
        if is_projectile_flying:
            # 投掷物飞行中的物理计算
            projectile_x += v0x * dt  # 水平方向匀速运动
            projectile_y -= v0y * dt - 0.5 * gravity * dt * dt  # 垂直方向受重力影响
            time += dt
            # 如果投掷物超出屏幕底部,停止飞行
            if projectile_y > screen_height:
                is_projectile_flying = False
        else:
            # 投掷物在杠杆末端的位置
            angle_rad = math.radians(angle)  # 将角度转换为弧度
            # 根据角度计算投掷物位置
            projectile_x = pivot_x - lever_length * math.cos(angle_rad)
            projectile_y = pivot_y - lever_length * math.sin(angle_rad)
    
        # 绘制投掷物
        screen.blit(projectile_image, (int(projectile_x - projectile_image.get_width() // 2),
                                      int(projectile_y - projectile_image.get_height() // 2)))
    
        # 更新屏幕显示
        pygame.display.flip()
        # 控制帧率为60 FPS
        clock.tick(60)
    
    # 退出Pygame
    pygame.quit()
    

    主要功能说明:

    1. 投石机模拟:通过调整角度和配重,模拟投石机发射投掷物的过程。
    2. 图像旋转:使用自定义函数 rotate_image_around_pivot 实现围绕支点的旋转。
    3. 物理计算:模拟投掷物的抛物线运动,考虑了重力加速度的影响。
    4. 用户交互:通过键盘控制角度、配重和发射动作。

    控制方式:

    • 左/右箭头:调整投石机角度。
    • 上/下箭头:调整配重(影响初始速度)。
    • 空格键:发射投掷物。

    关键修改解释:

    1. 支点定义:

      • 支点被定义为杠杆连接到投石机框架的固定位置。
      • 在旋转函数中,我们精确计算如何定位旋转后的图像,以保持该点固定。
    2. 杠杆旋转:

      • 旋转函数现在围绕杠杆图像的右边缘而不是中心进行旋转。
      • lever_pivot_x设置为杠杆图像的宽度,使支点位于其右端。
    3. 投掷物定位:

      • 投掷物的位置是根据固定的支点和当前角度计算得出的。
      • 确保了投掷物正确地定位在杠杆的末端。
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(4条)

报告相同问题?

问题事件

  • 系统已结题 4月26日
  • 已采纳回答 4月18日
  • 创建了问题 3月31日