Advertisement
JontePonte

Recursive simulation

Nov 11th, 2024
114
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 4.63 KB | None | 0 0
  1. using System;
  2. using System.Diagnostics;
  3. using TMPro;
  4. using Unity.VisualScripting;
  5. using UnityEngine;
  6. using UnityEngine.Profiling;
  7. using UnityEngine.Serialization;
  8. using Random = UnityEngine.Random;
  9.  
  10. public class Simulation : MonoBehaviour
  11. {
  12.    public struct Particle
  13.    {
  14.       public Vector2 position, velocity;
  15.       public float mass;
  16.    }
  17.    public int particleCount;
  18.    public float radius;
  19.    public float mass;
  20.    public float timeScale;
  21.    
  22.    [Header("Quad Tree")]
  23.    public float approximationThreshold;
  24.    public int capacity;
  25.    public int maxDepth;
  26.    
  27.    [Header("")]
  28.    public bool centerAttraction;
  29.    public float centerMass;
  30.  
  31.    public float particleForce;
  32.    
  33.    public Material material;
  34.  
  35.    Particle[] particles;
  36.    QuadTree quadTree;
  37.    new ParticleRenderer renderer;
  38.    Particle center;
  39.    TextMeshProUGUI latency;
  40.  
  41.    const int HalfScreenSize = 5;
  42.  
  43.    void Start()
  44.    {
  45.       center = new Particle
  46.       {
  47.          position = Vector2.zero,
  48.          velocity = Vector2.zero,
  49.          mass = centerMass
  50.       };
  51.       particles = new Particle[particleCount];
  52.       for (int i = 0; i < particleCount; i++)
  53.       {
  54.          float posX = Random.Range(-HalfScreenSize + radius, HalfScreenSize - radius);
  55.          float posY = Random.Range(-HalfScreenSize + radius, HalfScreenSize - radius);
  56.  
  57.          float centerDist = new Vector2(posX, posY).magnitude;
  58.          float force = Mathf.Sqrt(centerMass / centerDist);
  59.          Vector2 direction = new Vector2(posY, posX).normalized;
  60.          Vector2 velocity = new Vector2(direction.x, -direction.y) * force * particleForce;
  61.          
  62.          particles[i] = new()
  63.          {
  64.             position = new Vector2(posX, posY),
  65.             velocity = Vector2.zero,
  66.             mass = mass
  67.          };
  68.       }
  69.  
  70.       latency = GameObject.Find("Latency").GetComponent<TextMeshProUGUI>();
  71.       renderer = new(particles, material, radius);
  72.       RebuildQuadTree();
  73.    }
  74.  
  75.    void FixedUpdate()
  76.    {
  77.       Stopwatch watch = new();
  78.       watch.Start();
  79.      
  80.       Profiler.BeginSample("UpdateVelocities");
  81.       UpdateVelocities(Time.fixedDeltaTime * timeScale);
  82.       Profiler.EndSample();
  83.       Profiler.BeginSample("UpdatePositions");
  84.       UpdatePositions(Time.fixedDeltaTime * timeScale);
  85.       Profiler.EndSample();
  86.       Profiler.BeginSample("RebuildQuadTree");
  87.       RebuildQuadTree();
  88.       Profiler.EndSample();
  89.      
  90.       watch.Stop();
  91.       latency.text = watch.ElapsedMilliseconds + " ms";
  92.    }
  93.  
  94.    void Update()
  95.    {
  96.       renderer.Render(particles);
  97.    }
  98.    void OnDestroy()
  99.    {
  100.       renderer.ReleaseBuffers();
  101.    }
  102.  
  103.    void UpdateVelocities(float timeStep)
  104.    {
  105.       for (int i = 0; i < particleCount; i++)
  106.       {
  107.          particles[i] = quadTree.UpdateVelocity(particles[i], timeStep);
  108.       }  
  109.    }
  110.  
  111.    public static Vector2 CalculateAcceleration(Particle p1, Particle p2)
  112.    {
  113.       Vector2 diff = p2.position - p1.position;
  114.       Vector2 forceDir = diff.normalized;
  115.       float sqrDst = Mathf.Max(diff.sqrMagnitude, 0.05f);
  116.       Vector2 force = forceDir * (p1.mass * p2.mass) / sqrDst;
  117.       Vector2 acceleration = force / p1.mass;
  118.  
  119.       return acceleration;
  120.    }
  121.  
  122.    void UpdatePositions(float timeStep)
  123.    {
  124.       float minPosX = -HalfScreenSize + radius;
  125.       float maxPosX = HalfScreenSize - radius;
  126.       float minPosY = -HalfScreenSize + radius;
  127.       float maxPosY = HalfScreenSize - radius;
  128.      
  129.       for (int i = 0; i < particleCount; i++)
  130.       {
  131.          Particle particle = particles[i];
  132.          particle.position += particle.velocity * timeStep;
  133.          
  134.          Vector2 absPos = new(Mathf.Abs(particle.position.x), Mathf.Abs(particle.position.y));
  135.          if (absPos.x < minPosX || absPos.x > maxPosX || absPos.y < minPosY || absPos.y > maxPosY)
  136.          {
  137.             float posX = Random.Range(minPosX, maxPosX);
  138.             float posY = Random.Range(minPosY, maxPosY);
  139.             particle.position = new Vector2(posX, posY);
  140.          }
  141.            
  142.          particles[i] = particle;
  143.       }
  144.    }
  145.  
  146.    void RebuildQuadTree()
  147.    {
  148.       Quad boundary = new()
  149.       {
  150.          position = new Vector2(-5f, -5f),
  151.          size = 10
  152.       };
  153.       quadTree = new(boundary);
  154.       QuadTree.OverlapTolerance = radius;
  155.       QuadTree.ApproximationThreshold = approximationThreshold;
  156.       QuadTree.Capacity = capacity;
  157.       QuadTree.MaxDepth = maxDepth;
  158.       QuadTree.OriginalSize = HalfScreenSize * 2;
  159.  
  160.       for (int i = 0; i < particles.Length; i++)
  161.       {
  162.          quadTree.Insert(particles[i]);
  163.       }
  164.      
  165.       quadTree.CalculateMassAndCenterOfMass();
  166.    }
  167. }
  168.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement