pymunk物理引擎之掉落的弹球

""" 这是一个动画,它不断地产生物理弹球,弹球掉落在由两段线条组成的L形状上会有反弹效果。
"""
 
 
import random
 
import pygame
from pygame.key import *
from pygame.locals import *
from pygame.color import *
 
import pymunk
import pymunk.pygame_util


class BouncyBalls(object):
    """
     
    这个类实现一个简单的平台上有着随机掉落的弹球场景。
    """
    def __init__(self):
         
        self._space = pymunk.Space()           # 新建重力空间
        self._space.gravity = (0.0, -900.0)    # 重力加速度
 
        self._dt = 1.0 / 60.0                  # 这里应该是60分之一秒更新一次重力空间
        #  屏幕每一帧执行的物理刷新次数
        self._physics_steps_per_frame = 1

        # pygame 初始化
        pygame.init()
        self._screen = pygame.display.set_mode((600, 600))
        self._clock = pygame.time.Clock()

        self._draw_options = pymunk.pygame_util.DrawOptions(self._screen)
        print(self._draw_options)

        # 添加棍子,弹球碰到它会反弹
        self._add_static_scenery()

        # 所有的球在这个列表中
        self._balls = []

        # 主循环逻辑变量与产生球的时隔
        self._running = True
        self._ticks_to_next_ball = 10

    def run(self):
        """
         这里是场景的主要循环
        """
        
        while self._running:
            # 每帧执行几次物理计算过程?
            for x in range(self._physics_steps_per_frame):
                self._space.step(self._dt)

            self._process_events()
            self._update_balls()
            self._clear_screen()
            self._draw_objects()
            pygame.display.flip()
            # Delay fixed time between frames
            self._clock.tick(50)
            pygame.display.set_caption("fps: " + str(self._clock.get_fps()))
        pygame.quit()

    def _add_static_scenery(self):
        """
        创建静止不动的两根棍子
        """
        static_body = self._space.static_body
        static_lines = [pymunk.Segment(static_body, (111.0, 280.0), (407.0, 246.0), 0.0),
                        pymunk.Segment(static_body, (407.0, 246.0), (407.0, 343.0), 0.0)]
        for line in static_lines:
            line.elasticity = 0.95
            line.friction = 0.9
        self._space.add(static_lines)

    def _process_events(self):
        """
        Handle game and events like keyboard input. Call once per frame only.
        :return: None
        """
        for event in pygame.event.get():
            if event.type == QUIT:
                self._running = False
            elif event.type == KEYDOWN and event.key == K_ESCAPE:
                self._running = False
            elif event.type == KEYDOWN and event.key == K_p:
                pygame.image.save(self._screen, "bouncing_balls.png")

    def _update_balls(self):
        """
        每帧调用一次,创建球或者移出y坐标小于100的弹球。Create/remove balls as necessary. Call once per frame only.
        :return: None
        """
        self._ticks_to_next_ball -= 1
        if self._ticks_to_next_ball <= 0:
            self._create_ball()
            self._ticks_to_next_ball = 100
        # Remove balls that fall below 100 vertically
        balls_to_remove = [ball for ball in self._balls if ball.body.position.y < 100]
        for ball in balls_to_remove:
            self._space.remove(ball, ball.body)
            self._balls.remove(ball)

    def _create_ball(self):
        """
        创建一个物理 弹球
        """
        mass = 10
        radius = 25
        inertia = pymunk.moment_for_circle(mass, 0, radius, (0, 0))
        body = pymunk.Body(mass, inertia)
        x = random.randint(115, 350)
        body.position = x, 400
        shape = pymunk.Circle(body, radius, (0, 0))
        shape.elasticity = 0.95        # 弹性系数
        shape.friction = 0.9           # 摩擦系数
        self._space.add(body, shape)
        self._balls.append(shape)

    def _clear_screen(self):
        """
        清屏为白色
        """
        self._screen.fill(THECOLORS["white"])

    def _draw_objects(self):
        """
        画各个物体
        """
        self._space.debug_draw(self._draw_options)


if __name__ == '__main__':
    game = BouncyBalls()
    game.run()

以下是函数实现的,不过当小球离开屏幕时并没有把它删除,并且左边掉落的小球为什么会有瞬移现象出现呢?

import sys, random
import pygame
from pygame.locals import *
import pymunk
import pymunk.pygame_util

def add_static_L(space):
    body = pymunk.Body(body_type = pymunk.Body.STATIC) # 增加静态实体
    body.position = (300, 300)
    shape1 = pymunk.Segment(body, (-150, 0), (255, 0), 5)   # 此坐标是相对于(300,300)为原点的
    shape1.elasticity = 0.95        # 弹性系数
    shape1.friction = 0.9           # 摩擦系数
    
    shape2 = pymunk.Segment(body, (-150, 0), (-150, 50), 5) # y坐标相反
    shape2.elasticity = 0.95        # 弹性系数
    shape2.friction = 0.9           # 摩擦系数    
    
    space.add(shape1, shape2) # 增加到物理空间
    return shape1,shape2


def add_ball(space):
    mass = 1
    radius = 14
    moment = pymunk.moment_for_circle(mass, 0, radius) # 求一定质量和半径的小球的转动惯量,返回浮点数
     
    body = pymunk.Body(mass, moment)    # 新建刚体
    
    x = random.randint(120, 380)        # 随机x坐标
    body.position = x, 550              # 定位
    shape = pymunk.Circle(body, radius) # 设形状
    shape.elasticity = 0.95             # 弹性系数
    shape.friction = 0.9                # 摩擦系数
    space.add(body, shape)              # 放到物理空间     
    return shape

def main():
    pygame.init()
    screen = pygame.display.set_mode((600, 600))
    pygame.display.set_caption("自由落体小球")
    clock = pygame.time.Clock()

    space = pymunk.Space()
    space.gravity = (0.0, -900.0)

    lines = add_static_L(space)
    balls = []
    draw_options = pymunk.pygame_util.DrawOptions(screen) # 设定space内物体的渲染面

    ticks_to_next_ball = 10
    running = True
    while running:
        for event in pygame.event.get():
            if event.type in( QUIT,KEYDOWN,K_ESCAPE):
                running = False
                break                  

        ticks_to_next_ball -= 1
        if ticks_to_next_ball <= 0:
            ticks_to_next_ball = 25
            ball_shape = add_ball(space)
            balls.append(ball_shape)

        space.step(1/50.0)

        screen.fill((255,255,255))
        space.debug_draw(draw_options)

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

    pygame.quit()

if __name__ == '__main__':
    main()