pymunk + tkinter: как заставить мяч перемещаться влево или вправо с помощью пимунка?

Я создал небольшой пример программы, в которой я использую pymunk для выполнения физики и tkinter для работы с графическим интерфейсом (потому что я отказался от попыток установить pygame на моем Mac ...)

У меня это работает, когда один мяч создается, падает и отскакивает от пола. Если я наклоняю пол, он начинает правильно подпрыгивать влево или вправо.

Я не могу понять, как сначала приложить силу к мячу, чтобы его начальная скорость была направлена ​​вправо.

Я включаю свой код ниже. Это, наверное, что-то действительно простое, но я не физик и ничего не знаю о моментах и ​​т. Д. И т. Д.

Спасибо.

Вик

"""Simple example that bounces one ball against a floor.
The BallPhysics class defines the "model".  The Ball class is the "view".

@author: Victor Norman
"""

from tkinter import *
import pymunk
import pymunk.util
from pymunk import Vec2d
import math, sys, random


class Ball:

    RADIUS = 10

    def __init__(self, window):
        self._window = window
        self._window.title("Bouncing Ball with pymunk physics")

        self._model = BallPhysics()

        self._width = 400

        self._canvas = Canvas(self._window, bg='black',
                              width=self._width, height=self._width)
        self._canvas.pack()

        self._render()

    def _render(self):

        self._model.next_step()
        x, y = self._model.get_xy_for_ball()

        # subtract y values from self._width because y increases from 0 downward.
        self._canvas.create_oval(x - self.RADIUS, self._width - (y - self.RADIUS),
                                 x + self.RADIUS, self._width - (y + self.RADIUS),
                                 fill = 'white')
        self._canvas.after(20, self._render)


class BallPhysics:
    def __init__(self):

        self._space = pymunk.Space()
        self._space.gravity = (0.0, -900.0)

        self._balls = []

        mass = 10
        inertia = pymunk.moment_for_circle(mass, 0, Ball.RADIUS, (0, 0))
        body = pymunk.Body(mass, inertia)
        x = random.randint(50, 350)
        body.position = x, 400
        shape = pymunk.Circle(body, Ball.RADIUS, Vec2d(0,0))
        shape.elasticity = 0.9
        self._space.add(body, shape)
        self._balls.append(shape)

        # floor
        floor = pymunk.Segment(self._space.static_body, (0.0, 10.0), (400.0, 10.0), 1.0)
        floor.friction = 1.0
        floor.elasticity = 0.9
        self._space.add(floor)


    def next_step(self):
        # Remove balls that are below the bottom.
        balls_to_remove = []
        for ball in self._balls:
            if ball.body.position.y < 0:
                balls_to_remove.append(ball)
        for ball in balls_to_remove:
            self._space.remove(ball, ball.body)
            self._balls.remove(ball)

        if len(self._balls) >= 1:
            v = self._balls[0].body.position
            print("point = %.2f, %.2f" % (v.x, v.y))

        self._space.step(1 / 50)

    def get_xy_for_ball(self):
        ball_num = 0
        return (self._balls[ball_num].body.position.x,
                self._balls[ball_num].body.position.y)


main = Tk()
app = Ball(main)
main.mainloop()

person VictorNorman    schedule 15.11.2017    source источник
comment
Когда я запускаю ваш код, координата x / y никогда не меняется. Я рекомендую в первую очередь удалить код tkinter и просто попытаться создать цикл, который точно вычисляет новые координаты и выводит их на экран. Как только вы это сделаете, рисовать объект на холсте будет легко (и вы не должны рисовать новый объект на каждом тике, вы должны переместить существующий объект в новые координаты)   -  person Bryan Oakley    schedule 15.11.2017
comment
Не знаю, как тебе ответить ... Моя копия работает. Чтобы убедиться, что то, что я вставил в сообщение, правильно, я скопировал и вставил в новый файл, и он работает. Я использую python3, а не python2. вывод на консоли начинается так: Загрузка бурундука для Дарвина (64-разрядная версия) [/usr/local/lib/python3.5/site-packages/pymunk/libchipmunk.dylib] point = 127.00, 400.00 point = 127.00, 400.00 point = 127.00 , 399,64 балла = 127,00, 398,92 балла = 127,00, 397,84 балла = 127,00, 396,40 балла = 127,00, 394,60 балла = 127,00, 392,44   -  person VictorNorman    schedule 15.11.2017


Ответы (1)


Вы можете использовать body.apply_impulse_at_local_point (или *at_world_point) на теле, которое хотите подтолкнуть. API описан здесь: http://www.pymunk.org/en/latest/pymunk.html#pymunk.Body.apply_impulse_at_local_point

Итак, в вашем коде вы можете сделать body.apply_impulse_at_local_point((10000,0)) сразу после того, как вы установили положение тела на x,400. Обратите внимание, что вам нужно изменить силу импульса, чтобы получить желаемый эффект. Обычно я создаю вектор длиной один в направлении, в котором я хочу, чтобы он толкнул, а затем умножаю его на то, сколько импульса я хочу. вот так: body.apply_impulse_at_local_point(10000 * Vec2d(1,0)). Тогда становится проще, например, прицелиться немного вверх.

Этот пример включает стреляющий мяч с использованием импульса применения: https://github.com/viblo/pymunk/blob/master/examples/box2d_vertical_stack.py

person viblo    schedule 16.11.2017