169 lines
3.2 KiB
C#
169 lines
3.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
[Serializable]
|
|
public class MegaSoft2D
|
|
{
|
|
public List<Mass2D> masses = new List<Mass2D>();
|
|
|
|
public List<Spring2D> springs = new List<Spring2D>();
|
|
|
|
public List<Constraint2D> constraints = new List<Constraint2D>();
|
|
|
|
public Vector2 gravity = new Vector2(0f, -9.81f);
|
|
|
|
public float airdrag = 0.999f;
|
|
|
|
public float friction = 1f;
|
|
|
|
public float timeStep = 0.01f;
|
|
|
|
public int iters = 4;
|
|
|
|
public MegaIntegrator method = MegaIntegrator.Verlet;
|
|
|
|
public bool applyConstraints = true;
|
|
|
|
public float floor;
|
|
|
|
public float lasttime;
|
|
|
|
public float simtime;
|
|
|
|
private void doCalculateForceseuler()
|
|
{
|
|
for (int i = 0; i < masses.Count; i++)
|
|
{
|
|
masses[i].force = masses[i].mass * gravity;
|
|
masses[i].force += masses[i].forcec;
|
|
}
|
|
for (int j = 0; j < springs.Count; j++)
|
|
{
|
|
springs[j].doCalculateSpringForce(this);
|
|
}
|
|
}
|
|
|
|
private void doCalculateForces()
|
|
{
|
|
for (int i = 0; i < masses.Count; i++)
|
|
{
|
|
masses[i].force = masses[i].mass * gravity;
|
|
masses[i].force += masses[i].forcec;
|
|
}
|
|
for (int j = 0; j < springs.Count; j++)
|
|
{
|
|
springs[j].doCalculateSpringForce1(this);
|
|
}
|
|
}
|
|
|
|
private void doIntegration1(float dt)
|
|
{
|
|
doCalculateForceseuler();
|
|
for (int i = 0; i < masses.Count; i++)
|
|
{
|
|
masses[i].last = masses[i].pos;
|
|
masses[i].vel += dt * masses[i].force * masses[i].oneovermass;
|
|
masses[i].pos += masses[i].vel * dt;
|
|
masses[i].vel *= friction;
|
|
}
|
|
DoConstraints();
|
|
}
|
|
|
|
private void DoCollisions(float dt)
|
|
{
|
|
for (int i = 0; i < masses.Count; i++)
|
|
{
|
|
if (masses[i].pos.y < floor)
|
|
{
|
|
masses[i].pos.y = floor;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void VerletIntegrate(float t, float lastt)
|
|
{
|
|
doCalculateForces();
|
|
float num = t * t;
|
|
for (int i = 0; i < masses.Count; i++)
|
|
{
|
|
Vector2 pos = masses[i].pos;
|
|
masses[i].pos += airdrag * (masses[i].pos - masses[i].last) + masses[i].force * masses[i].oneovermass * num;
|
|
masses[i].last = pos;
|
|
}
|
|
DoConstraints();
|
|
}
|
|
|
|
private void VerletIntegrateTC(float t, float lastt)
|
|
{
|
|
doCalculateForces();
|
|
float num = t * t;
|
|
float num2 = t / lastt;
|
|
for (int i = 0; i < masses.Count; i++)
|
|
{
|
|
Vector2 pos = masses[i].pos;
|
|
masses[i].pos += airdrag * (masses[i].pos - masses[i].last) * num2 + masses[i].force * masses[i].oneovermass * num;
|
|
masses[i].last = pos;
|
|
}
|
|
DoConstraints();
|
|
}
|
|
|
|
private void MidPointIntegrate(float t)
|
|
{
|
|
}
|
|
|
|
public void DoConstraints()
|
|
{
|
|
for (int i = 0; i < iters; i++)
|
|
{
|
|
for (int j = 0; j < constraints.Count; j++)
|
|
{
|
|
constraints[j].Apply(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Update()
|
|
{
|
|
if (masses == null)
|
|
{
|
|
return;
|
|
}
|
|
simtime += Time.deltaTime;
|
|
if (Time.deltaTime == 0f)
|
|
{
|
|
simtime = 0.01f;
|
|
}
|
|
if (timeStep <= 0f)
|
|
{
|
|
timeStep = 0.001f;
|
|
}
|
|
float num = 0f;
|
|
if (lasttime == 0f)
|
|
{
|
|
lasttime = timeStep;
|
|
}
|
|
while (simtime > 0f)
|
|
{
|
|
simtime -= timeStep;
|
|
num = timeStep;
|
|
switch (method)
|
|
{
|
|
case MegaIntegrator.Euler:
|
|
doIntegration1(num);
|
|
break;
|
|
case MegaIntegrator.Verlet:
|
|
VerletIntegrate(num, lasttime);
|
|
break;
|
|
case MegaIntegrator.VerletTimeCorrected:
|
|
VerletIntegrateTC(num, lasttime);
|
|
break;
|
|
case MegaIntegrator.MidPoint:
|
|
MidPointIntegrate(num);
|
|
break;
|
|
}
|
|
lasttime = num;
|
|
}
|
|
}
|
|
}
|