You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Pygame+Pymunk传送带仿真冲量仅作用于新物体问题

Pymunk传送带仿真冲量仅作用于最新物体修复方案

核心问题原因

  • 物体列表初始化位置错误:objects = []写在鼠标点击事件分支内,每次点击添加新物体时都会先清空列表,再存入新物体,导致列表始终只保存最后一次创建的物体,冲量遍历逻辑自然只能作用到最新物体。
  • 碰撞回调范围错误:使用全局默认碰撞处理器,任意两个物体(包括物体之间、物体和非传送带对象)碰撞都会触发回调,且没有判断物体是否真的和传送带接触,会给未落到传送带上的悬空物体错误施加冲量。
  • 冲量逻辑不符合物理规则:固定施加水平方向冲量,没有匹配倾斜段传送带的走向,也没有根据物体和传送带的相对速度调整冲量大小,无法模拟速度同步后的无摩擦状态。

修复步骤

  1. 将objects列表的初始化移到主循环启动前、鼠标事件逻辑外,每次点击创建新物体时直接向列表追加元素,不要每次点击都重置空列表。
  2. 为传送带和传送物体定义专属碰撞类型,不要使用全局默认碰撞处理器,仅针对传送带与物体的碰撞对设置回调逻辑。
  3. 在碰撞回调中直接通过碰撞仲裁器arbiter获取当前发生接触的传送带段和物体,根据传送带段的预设运动方向、传送带与物体的相对速度计算冲量大小,在接触点施加冲量,模拟真实摩擦力效果。

修复后可运行代码

import pygame
import pymunk
import pymunk.pygame_util
import math
import sys

pygame.init()
WIDTH, HEIGHT = 1920,800
mu = 2
# 定义碰撞类型
COLLISION_TYPE_BELT = 1
COLLISION_TYPE_OBJECT = 2

window = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Kinematics approximation ")

def calculate_distance(p1, p2):
    return math.sqrt((p2[1] - p1[1])**2 + (p2[0] - p1[0])**2)

def calculate_angle(p1, p2):
    return math.atan2(p2[1] - p1[1], p2[0] - p1[0])

def draw(space, window,draw_options):
    window.fill("white")
    space.debug_draw(draw_options) 
    pygame.display.update()
    


def create_belt(space):
    belts = [
        # 格式:起点、终点、厚度、运动方向单位向量、线速度
        [(0,500), (600,500), 5, (1,0), 120],
        [(600,500), (800,400), 6, (math.cos(-math.pi/4), math.sin(-math.pi/4)), 120],
        [(800,400), (WIDTH,400), 6, (1,0), 120]
    ]

    for pos_1, pos_2, width, belt_dir, belt_speed in belts:
        shape = pymunk.Segment(space.static_body,pos_1, pos_2, width) 
        shape.body.position = 0,0
        shape.friction = mu
        shape.collision_type = COLLISION_TYPE_BELT
        shape.belt_dir = belt_dir
        shape.belt_speed = belt_speed
        space.add(shape)


def create_object(space, mass, pos):
    body = pymunk.Body(body_type = pymunk.Body.DYNAMIC)
    body.position = pos
    shape = pymunk.Poly.create_box(body, size = (20,10))
    shape.mass = mass
    shape.color = (255,0,0, 100)
    shape.body.friction = mu
    shape.collision_type = COLLISION_TYPE_OBJECT
    space.add(body,shape)
    return shape


def run(window, width, height):
    run = True
    clock = pygame.time.Clock()
    fps = 240
    dt = 1/fps

    space = pymunk.Space()
    space.gravity = (0,981)

    create_belt(space)
    # 提前初始化物体列表
    objects = []

    def coll_pre(arbiter, space, data):
        belt_shape, obj_shape = arbiter.shapes
        belt_dir = belt_shape.belt_dir
        belt_speed = belt_shape.belt_speed
        # 计算物体沿传送带方向的当前速度
        obj_vel_along = obj_shape.body.velocity.dot(belt_dir)
        # 计算速度差,换算为需要施加的冲量
        vel_diff = belt_speed - obj_vel_along
        impulse_mag = vel_diff * obj_shape.mass * 0.1
        # 限制冲量上限,模拟最大静摩擦
        impulse_mag = max(-100, min(100, impulse_mag))
        impulse = (belt_dir[0] * impulse_mag, belt_dir[1] * impulse_mag)
        # 在所有接触点施加冲量
        for contact in arbiter.contact_point_set.points:
            obj_shape.body.apply_impulse_at_world_point(impulse, contact.point_b)
        return True

    # 仅绑定传送带和物体的碰撞回调
    handler = space.add_collision_handler(COLLISION_TYPE_BELT, COLLISION_TYPE_OBJECT)
    handler.pre_solve = coll_pre

    draw_options = pymunk.pygame_util.DrawOptions(window)

    while run:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()    
        
            if event.type == pygame.MOUSEBUTTONDOWN:
                pressed_pos = pygame.mouse.get_pos()
                # 直接追加新物体,不重置列表
                objects.append(create_object(space,10, pressed_pos))
                

        draw(space,window, draw_options)
        space.step(dt)
        clock.tick(fps)
        

    pygame.quit()
    sys.exit()



if __name__ == "__main__":
    run(window, WIDTH, HEIGHT)

修复后所有接触传送带的物体都会受到沿传送带方向的摩擦冲量,倾斜段运动方向正确,物体速度与传送带同步后冲量会自动降低到接近0,仿真效果符合真实传送带运动规律。

内容的提问来源于stack exchange,提问作者Ruben Vreugdenhil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 04:39:20