Files
2026-02-21 16:45:37 +08:00

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;
}
}
}