Интегратор верлет + трение
Я следовал " Основанному на Verlet подходу к физике 2D-игр" на Gamedev.net, и я написал нечто подобное.
У меня проблема в том, что ящики слишком сильно скользят по земле. Как я могу добавить простую вещь в состоянии покоя, где коробки будут иметь большее трение и будут скользить лишь чуть-чуть?
3 ответа
Просто введите небольшое постоянное ускорение на движущиеся объекты, которые указывают в направлении, противоположном движению. И убедитесь, что он не может полностью изменить движение; если вы обнаружите это на этапе интеграции, просто установите скорость на ноль.
Если вы хотите быть более реалистичным, ускорение должно происходить от силы, которая пропорциональна нормальной силе между объектом и поверхностью, по которой он скользит.
Вы можете найти это в любом основном физическом тексте, как "кинетическое трение" или "трение скольжения".
Вот простая схема временного шага (симплектический метод Эйлера с ручным разрешением LCP) для коробки с кулоновским трением и пружиной ( фрикционный осциллятор ).
mq'' + kq + mu*sgn(q') = F(t)
import numpy as np
import matplotlib.pyplot as plt
q0 = 0 # initial position
p0 = 0 # initial momentum
t_start = 0 # initial time
t_end = 10 # end time
N = 500 # time points
m = 1 # mass
k = 1 # spring stiffness
muN = 0.5 # friction force (slip and maximal stick)
omega = 1.5 # forcing radian frequency [RAD]
Fstat = 0.1 # static component of external force
Fdyn = 0.6 # amplitude of harmonic external force
F = lambda tt,qq,pp: Fstat + Fdyn*np.sin(omega*tt) - k*qq - muN*np.sign(pp) # total force, note sign(0)=0 used to disable friction
zero_to_disable_friction = 0
omega0 = np.sqrt(k/m)
print("eigenfrequency f = {} Hz; eigen period T = {} s".format(omega0/(2*np.pi), 2*np.pi/omega0))
print("forcing frequency f = {} Hz; forcing period T = {} s".format(omega/(2*np.pi), 2*np.pi/omega))
time = np.linspace(t_start, t_end, N) # time grid
h = time[1] - time[0] # time step
q = np.zeros(N+1) # position
p = np.zeros(N+1) # momentum
absFfriction = np.zeros(N+1)
q[0] = q0
p[0] = p0
for n, tn in enumerate(time):
p1slide = p[n] + h*F(tn, q[n], p[n]) # end-time momentum, assuming sliding
q1slide = q[n] + h*p1slide/m # end-time position, assuming sliding
if p[n]*p1slide > 0: # sliding goes on
q[n+1] = q1slide
p[n+1] = p1slide
absFfriction[n] = muN
else:
q1stick = q[n] # assume p1 = 0 at t=tn+h
Fstick = -p[n]/h - F(tn, q1stick, zero_to_disable_friction) # friction force needed to stop at t=tn+h
if np.abs(Fstick) <= muN:
p[n+1] = 0 # sticking
q[n+1] = q1stick
absFfriction[n] = np.abs(Fstick)
else: # sliding starts or passes zero crossing of velocity
q[n+1] = q1slide # possible refinements (adapt to slip-start or zero crossing)
p[n+1] = p1slide
absFfriction[n] = muN
При интеграции verlet: r(t)=2.00*r(t-dt)-1.00*r(t-2dt)+2at²
измените множители на 1,99 и 0,99 для трения
Изменить: это более верно:
r(t)=(2.00-friction_mult.)*r(t-dt)-(1.00-friction_mult.)*r(t-2dt)+at²