Как не отобразить ориентацию шара в pymunk.Space.debug_draw ()? - PullRequest
0 голосов
/ 27 октября 2018

Я использую 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

Как мы видим, эторисует черную линию, идущую от центра к краю шара;Я предполагаю, что это указывает на вращение каждого шара.

Я бы не хотел, чтобы эта линия была нарисована: т.е. явно передавал флаг, чтобы пигмея не рисовала его, или указывал цвет этой линии, чтобы он был таким же, как и остальная часть шара.

Кто-нибудь знает, как это сделать?

1 Ответ

0 голосов
/ 27 октября 2018

Метод 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
...