MegaSoft2D.cs 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. public enum MegaIntegrator
  4. {
  5. Euler,
  6. Verlet,
  7. VerletTimeCorrected,
  8. MidPoint,
  9. }
  10. public class BaryVert2D
  11. {
  12. public int gx; // Grid position
  13. public int gy;
  14. public Vector2 bary;
  15. }
  16. [System.Serializable]
  17. public class Constraint2D
  18. {
  19. public bool active;
  20. public int p1;
  21. public int p2;
  22. public float length;
  23. public Vector2 pos;
  24. public int contype = 0;
  25. public Transform obj;
  26. public static Constraint2D CreatePointTargetCon(int _p1, Transform trans)
  27. {
  28. Constraint2D con = new Constraint2D();
  29. con.p1 = _p1;
  30. con.active = true;
  31. con.contype = 2;
  32. con.obj = trans;
  33. return con;
  34. }
  35. public static Constraint2D CreateLenCon(int _p1, int _p2, float _len)
  36. {
  37. Constraint2D con = new Constraint2D();
  38. con.p1 = _p1;
  39. con.p2 = _p2;
  40. con.length = _len;
  41. con.active = true;
  42. con.contype = 0;
  43. return con;
  44. }
  45. public static Constraint2D CreatePointCon(int _p1, Vector2 _pos)
  46. {
  47. Constraint2D con = new Constraint2D();
  48. con.p1 = _p1;
  49. con.pos = _pos;
  50. con.active = true;
  51. con.contype = 1;
  52. return con;
  53. }
  54. public void Apply(MegaSoft2D soft)
  55. {
  56. switch ( contype )
  57. {
  58. case 0: ApplyLengthConstraint2D(soft); break;
  59. case 1: ApplyPointConstraint2D(soft); break;
  60. //case 2: ApplyPointTargetConstraint2D(soft); break;
  61. }
  62. }
  63. // Can have a one that has a range to keep in
  64. public void ApplyLengthConstraint2D(MegaSoft2D soft)
  65. {
  66. if ( active && soft.applyConstraints )
  67. {
  68. //calculate direction
  69. Vector2 direction = soft.masses[p2].pos - soft.masses[p1].pos;
  70. //calculate current length
  71. float currentLength = direction.magnitude;
  72. //check for zero vector
  73. if ( currentLength != 0.0f ) //direction.x != 0.0f || direction.y != 0.0f || direction.y != 0.0f )
  74. {
  75. direction.x /= currentLength;
  76. direction.y /= currentLength;
  77. //move to goal positions
  78. Vector2 moveVector = 0.5f * (currentLength - length) * direction;
  79. soft.masses[p1].pos.x += moveVector.x;
  80. soft.masses[p1].pos.y += moveVector.y;
  81. soft.masses[p2].pos.x += -moveVector.x;
  82. soft.masses[p2].pos.y += -moveVector.y;
  83. }
  84. }
  85. }
  86. public void ApplyPointConstraint2D(MegaSoft2D soft)
  87. {
  88. if ( active )
  89. soft.masses[p1].pos = pos;
  90. }
  91. public void ApplyAngleConstraint(MegaSoft2D soft)
  92. {
  93. }
  94. }
  95. [System.Serializable]
  96. public class Mass2D
  97. {
  98. public Vector2 pos;
  99. public Vector2 last;
  100. public Vector2 force;
  101. public Vector2 vel;
  102. public Vector2 posc;
  103. public Vector2 velc;
  104. public Vector2 forcec;
  105. public Vector2 coef1;
  106. public Vector2 coef2;
  107. public float mass;
  108. public float oneovermass;
  109. public Mass2D(float m, Vector2 p)
  110. {
  111. mass = m;
  112. oneovermass = 1.0f / mass;
  113. pos = p;
  114. last = p;
  115. force = Vector2.zero;
  116. vel = Vector2.zero;
  117. }
  118. }
  119. [System.Serializable]
  120. public class Spring2D
  121. {
  122. public int p1;
  123. public int p2;
  124. public float restLen;
  125. public float ks;
  126. public float kd;
  127. public float len;
  128. public Spring2D(int _p1, int _p2, float _ks, float _kd, MegaSoft2D mod)
  129. {
  130. p1 = _p1;
  131. p2 = _p2;
  132. ks = _ks;
  133. kd = _kd;
  134. restLen = Vector2.Distance(mod.masses[p1].pos, mod.masses[p2].pos);
  135. len = restLen;
  136. }
  137. public void doCalculateSpringForce(MegaSoft2D mod)
  138. {
  139. Vector2 deltaP = mod.masses[p1].pos - mod.masses[p2].pos;
  140. float dist = deltaP.magnitude; //VectorLength(&deltaP); // Magnitude of deltaP
  141. float Hterm = (dist - restLen) * ks; // Ks * (dist - rest)
  142. Vector2 deltaV = mod.masses[p1].vel - mod.masses[p2].vel;
  143. float Dterm = (Vector2.Dot(deltaV, deltaP) * kd) / dist; // Damping Term
  144. Vector2 springForce = deltaP * (1.0f / dist);
  145. springForce *= -(Hterm + Dterm);
  146. mod.masses[p1].force += springForce;
  147. mod.masses[p2].force -= springForce;
  148. }
  149. public void doCalculateSpringForce1(MegaSoft2D mod)
  150. {
  151. //get the direction vector
  152. Vector2 direction = mod.masses[p1].pos - mod.masses[p2].pos;
  153. //check for zero vector
  154. if ( direction != Vector2.zero )
  155. {
  156. //get length
  157. float currLength = direction.magnitude;
  158. //normalize
  159. direction = direction.normalized;
  160. //add spring force
  161. Vector2 force = -ks * ((currLength - restLen) * direction);
  162. //add spring damping force
  163. //float v = (currLength - len) / mod.timeStep;
  164. //force += -kd * v * direction;
  165. //apply the equal and opposite forces to the objects
  166. mod.masses[p1].force += force;
  167. mod.masses[p2].force -= force;
  168. len = currLength;
  169. }
  170. }
  171. public void doCalculateSpringForce2(MegaSoft2D mod)
  172. {
  173. Vector2 deltaP = mod.masses[p1].pos - mod.masses[p2].pos;
  174. float dist = deltaP.magnitude; //VectorLength(&deltaP); // Magnitude of deltaP
  175. float Hterm = (dist - restLen) * ks; // Ks * (dist - rest)
  176. //Vector2 deltaV = mod.masses[p1].vel - mod.masses[p2].vel;
  177. float v = (dist - len); // / mod.timeStep;
  178. float Dterm = (v * kd) / dist; // Damping Term
  179. Vector2 springForce = deltaP * (1.0f / dist);
  180. springForce *= -(Hterm + Dterm);
  181. mod.masses[p1].force += springForce;
  182. mod.masses[p2].force -= springForce;
  183. }
  184. }
  185. // Want verlet for this as no collision will be done, solver type enum
  186. // need to add contact forces for weights on bridge
  187. [System.Serializable]
  188. public class MegaSoft2D
  189. {
  190. public List<Mass2D> masses = new List<Mass2D>();
  191. public List<Spring2D> springs = new List<Spring2D>();
  192. public List<Constraint2D> constraints = new List<Constraint2D>();
  193. public Vector2 gravity = new Vector2(0.0f, -9.81f);
  194. public float airdrag = 0.999f;
  195. public float friction = 1.0f;
  196. public float timeStep = 0.01f;
  197. public int iters = 4;
  198. public MegaIntegrator method = MegaIntegrator.Verlet;
  199. public bool applyConstraints = true;
  200. void doCalculateForceseuler()
  201. {
  202. for ( int i = 0; i < masses.Count; i++ )
  203. {
  204. masses[i].force = masses[i].mass * gravity;
  205. masses[i].force += masses[i].forcec;
  206. }
  207. for ( int i = 0; i < springs.Count; i++ )
  208. springs[i].doCalculateSpringForce(this);
  209. }
  210. void doCalculateForces()
  211. {
  212. for ( int i = 0; i < masses.Count; i++ )
  213. {
  214. masses[i].force = masses[i].mass * gravity;
  215. masses[i].force += masses[i].forcec;
  216. }
  217. for ( int i = 0; i < springs.Count; i++ )
  218. springs[i].doCalculateSpringForce1(this);
  219. }
  220. void doIntegration1(float dt)
  221. {
  222. doCalculateForceseuler(); // Calculate forces, only changes _f
  223. /* Then do correction step by integration with central average (Heun) */
  224. for ( int i = 0; i < masses.Count; i++ )
  225. {
  226. masses[i].last = masses[i].pos;
  227. masses[i].vel += dt * masses[i].force * masses[i].oneovermass;
  228. masses[i].pos += masses[i].vel * dt;
  229. masses[i].vel *= friction;
  230. }
  231. DoConstraints();
  232. }
  233. public float floor = 0.0f;
  234. void DoCollisions(float dt)
  235. {
  236. for ( int i = 0; i < masses.Count; i++ )
  237. {
  238. if ( masses[i].pos.y < floor )
  239. masses[i].pos.y = floor;
  240. }
  241. }
  242. // Change the base code over to Skeel or similar
  243. //public bool UseVerlet = false;
  244. // Can do drag per point using a curve
  245. // perform the verlet integration step
  246. void VerletIntegrate(float t, float lastt)
  247. {
  248. doCalculateForces(); // Calculate forces, only changes _f
  249. float t2 = t * t;
  250. /* Then do correction step by integration with central average (Heun) */
  251. for ( int i = 0; i < masses.Count; i++ )
  252. {
  253. Vector2 last = masses[i].pos;
  254. masses[i].pos += airdrag * (masses[i].pos - masses[i].last) + masses[i].force * masses[i].oneovermass * t2; // * t;
  255. masses[i].last = last;
  256. }
  257. DoConstraints();
  258. }
  259. // Pointless
  260. void VerletIntegrateTC(float t, float lastt)
  261. {
  262. doCalculateForces(); // Calculate forces, only changes _f
  263. float t2 = t * t;
  264. float dt = t / lastt;
  265. /* Then do correction step by integration with central average (Heun) */
  266. for ( int i = 0; i < masses.Count; i++ )
  267. {
  268. Vector2 last = masses[i].pos;
  269. masses[i].pos += airdrag * (masses[i].pos - masses[i].last) * dt + (masses[i].force * masses[i].oneovermass) * t2; // * t;
  270. masses[i].last = last;
  271. }
  272. DoConstraints();
  273. }
  274. void MidPointIntegrate(float t)
  275. {
  276. }
  277. // Satisfy constraints
  278. public void DoConstraints()
  279. {
  280. for ( int i = 0; i < iters; i++ )
  281. {
  282. for ( int c = 0; c < constraints.Count; c++ )
  283. {
  284. constraints[c].Apply(this);
  285. }
  286. }
  287. }
  288. public float lasttime = 0.0f;
  289. public float simtime = 0.0f;
  290. public void Update()
  291. {
  292. if ( masses == null )
  293. return;
  294. if ( Application.isPlaying )
  295. simtime += Time.deltaTime; // * fudge;
  296. if ( Time.deltaTime == 0.0f )
  297. {
  298. simtime = 0.01f;
  299. }
  300. if ( timeStep <= 0.0f )
  301. timeStep = 0.001f;
  302. float ts = 0.0f;
  303. if ( lasttime == 0.0f )
  304. lasttime = timeStep;
  305. while ( simtime > 0.0f) //timeStep ) //0.0f )
  306. {
  307. simtime -= timeStep;
  308. ts = timeStep;
  309. switch ( method )
  310. {
  311. case MegaIntegrator.Euler:
  312. doIntegration1(ts);
  313. break;
  314. case MegaIntegrator.Verlet:
  315. VerletIntegrate(ts, lasttime); //timeStep);
  316. break;
  317. case MegaIntegrator.VerletTimeCorrected:
  318. VerletIntegrateTC(ts, lasttime); //timeStep);
  319. break;
  320. case MegaIntegrator.MidPoint:
  321. MidPointIntegrate(ts); //timeStep);
  322. break;
  323. }
  324. lasttime = ts;
  325. }
  326. }
  327. }