如何不在pymunk.Space.debug_draw()中渲染球的方向?

时间:2018-10-27 15:21:35

标签: python pygame pymunk

我正在使用Pymunk生成在框架中弹跳的球的视频。要渲染框架,我运行:

import pygame
from pymunk.pygame_util import DrawOptions

screen = pygame.display.set_mode((500, 500))
draw_options = DrawOptions(screen)

# define `space` with six balls
# ...

space.debug_draw(draw_options)

给出以下输出:

enter image description here

我们可以看到,它从球的中心到边缘画了一条黑线;我想这是为了指示每个球的旋转。

我不想画这条线:即显式传递一个标志以防止pygame绘制它,或将这条线的颜色指定为与球的其余部分相同。

有人知道怎么做吗?

1 个答案:

答案 0 :(得分:2)

# pylint: disable=方法实际上应该主要用于调试。我通常为我的物理对象创建精灵子类,并为它们提供Pymunk实体和形状作为属性。然后,我可以通过将debug_draw方法中的self.rect设置为身体坐标,并使用它来旋转图像来更新update

import math
import random

import pygame as pg
import pymunk as pm
from pymunk import Vec2d


def flipy(p):
    """Convert chipmunk physics to pygame coordinates."""
    return Vec2d(p[0], -p[1]+800)


class Entity(pg.sprite.Sprite):

    def __init__(self, pos, space, radius, mass=1):
        super().__init__()
        # The surface is a bit bigger, so that the circle fits better.
        self.orig_image = pg.Surface((radius*2+2, radius*2+2), pg.SRCALPHA)
        self.image = self.orig_image
        # Draw a circle onto the image.
        pg.draw.circle(
            self.image,
            pg.Color(random.randrange(256),
                     random.randrange(256),
                     random.randrange(256)),
            (radius+1, radius+1),  # +1 looks a bit better.
            radius)
        self.rect = self.image.get_rect(topleft=pos)

        # Create a Pymunk body and a shape and add them to the space.
        moment = pm.moment_for_circle(mass, radius, radius)
        self.body = pm.Body(mass, moment)
        self.shape = pm.Circle(self.body, radius)
        self.shape.friction = .1
        self.shape.elasticity = .99
        self.body.position = pos
        self.space = space
        self.space.add(self.body, self.shape)

    def update(self):
        # Update the rect because it's used to blit the image.
        self.rect.center = flipy(self.body.position)
        # Use the body's angle to rotate the image.
        self.image = pg.transform.rotozoom(self.orig_image, math.degrees(self.body.angle), 1)
        self.rect = self.image.get_rect(center=self.rect.center)

        if self.rect.left < 0 or self.rect.right > 1280 or self.rect.y > 790:
            self.space.remove(self.body, self.shape)
            self.kill()


class Game:

    def __init__(self):
        pg.init()
        self.screen = pg.display.set_mode((1280, 800))
        self.done = False
        self.clock = pg.time.Clock()

        # Pymunk stuff
        self.space = pm.Space()
        self.space.gravity = Vec2d(0.0, -900.0)
        self.space.damping = .9
        self.static_lines = [
            pm.Segment(self.space.static_body, flipy((60.0, 780.0)), flipy((650.0, 780.0)), .0),
            pm.Segment(self.space.static_body, flipy((650.0, 780.0)), flipy((1218.0, 660.0)), .0)
            ]
        for lin in self.static_lines:
            lin.friction = 0.2
            lin.elasticity = 0.99
        self.space.add(self.static_lines)

        self.all_sprites = pg.sprite.Group()

    def run(self):
        while not self.done:
            self.dt = self.clock.tick(60) / 1000
            self.handle_events()
            self.run_logic()
            self.draw()
            self.current_fps = self.clock.get_fps()

        pg.quit()

    def handle_events(self):
        for event in pg.event.get():
            if event.type == pg.QUIT:
                self.done = True
            elif event.type == pg.MOUSEBUTTONDOWN:
                if event.button == 1:  # Left mouse button.
                    # Spawn an entity.
                    radius = random.randrange(20, 50)
                    self.all_sprites.add(Entity(flipy(pg.mouse.get_pos()), self.space, radius))

        if pg.mouse.get_pressed()[2]:  # Right mouse button.
            radius = random.randrange(20, 50)
            self.all_sprites.add(Entity(flipy(pg.mouse.get_pos()), self.space, radius))

    def run_logic(self):
        self.space.step(1/60)
        self.all_sprites.update()

    def draw(self):
        self.screen.fill(pg.Color(140, 120, 110))
        self.all_sprites.draw(self.screen)  # Draw the images of all sprites.

        # Draw the static lines.
        for line in self.static_lines:
            body = line.body
            p1 = flipy(body.position + line.a.rotated(body.angle))
            p2 = flipy(body.position + line.b.rotated(body.angle))
            pg.draw.lines(self.screen, pg.Color('lightgray'), False, (p1, p2), 5)

        pg.display.flip()


if __name__ == '__main__':
    Game().run()

enter image description here

我还试图找到一种方法来隐藏debug_draw创建的这些方向/旋转线,并发现这些线在draw_options.shape_outline_color中是彩色的,圆圈使用draw_options.shape_dynamic_color默认。因此,当您设置

draw_options.shape_outline_color = draw_options.shape_dynamic_color

圆圈完全是蓝色的。但是,如果为每个形状指定特定的color,它仍将使用蓝色作为线条。

使用draw_options.flags属性,我只能完全关闭碰撞点或形状,而不能关闭线条:

# This is how you can turn off the collision points.
draw_options.flags ^= draw_options.DRAW_COLLISION_POINTS
# Stops drawing the constraints.
draw_options.flags ^= draw_options.DRAW_CONSTRAINTS
# Stops drawing all shapes.
draw_options.flags ^= draw_options.DRAW_SHAPES