pymunk + tkinter:如何使用 pymunk 让球向左或向右移动?
pymunk + tkinter: How to get ball to move to left or right with pymunk?
我创建了一个小示例程序,我使用 pymunk 进行物理操作,使用 tkinter 进行 GUI 操作(因为我已经放弃尝试让 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()
您可以在要推送的 body 上使用 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 位置设置为 x,400
后立即执行 body.apply_impulse_at_local_point((10000,0))
。请注意,您需要修改脉冲的强度才能获得所需的效果。通常我会创建一个长度为 1 的矢量,方向是我想要它推动的方向,然后将它乘以我想要的冲量。像这样:body.apply_impulse_at_local_point(10000 * Vec2d(1,0))
。然后它变得很容易,而不是稍微向上瞄准。
这个例子包括一个使用脉冲的射击球:https://github.com/viblo/pymunk/blob/master/examples/box2d_vertical_stack.py
我创建了一个小示例程序,我使用 pymunk 进行物理操作,使用 tkinter 进行 GUI 操作(因为我已经放弃尝试让 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()
您可以在要推送的 body 上使用 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 位置设置为 x,400
后立即执行 body.apply_impulse_at_local_point((10000,0))
。请注意,您需要修改脉冲的强度才能获得所需的效果。通常我会创建一个长度为 1 的矢量,方向是我想要它推动的方向,然后将它乘以我想要的冲量。像这样:body.apply_impulse_at_local_point(10000 * Vec2d(1,0))
。然后它变得很容易,而不是稍微向上瞄准。
这个例子包括一个使用脉冲的射击球:https://github.com/viblo/pymunk/blob/master/examples/box2d_vertical_stack.py