using System; using System.Collections.Generic; using UnityEngine; [Serializable] public class MegaSoft2D { public List masses = new List(); public List springs = new List(); public List constraints = new List(); 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; } } }