Advertisement
djgaven588

Minecraft Collision Engine

Aug 1st, 2018
144
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 11.87 KB | None | 0 0
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Timers;
  5. using UnityEngine;
  6.  
  7. public static class CollisionEngine
  8. {
  9.     private static Queue<DynamicCollider> dynamicColliders;
  10.  
  11.     public static void RegisterDynamicCollider(DynamicCollider collider)
  12.     {
  13.         if (dynamicColliders == null)
  14.         {
  15.             dynamicColliders = new Queue<DynamicCollider>();
  16.         }
  17.  
  18.         if (collider.isRegistered == false)
  19.         {
  20.             dynamicColliders.Enqueue(collider);
  21.             collider.isRegistered = true;
  22.         }
  23.     }
  24.  
  25.     public static void UnregisterDynamicCollider(DynamicCollider collider)
  26.     {
  27.         if (collider.isRegistered)
  28.         {
  29.             Queue<DynamicCollider> newColliders = new Queue<DynamicCollider>();
  30.             for (int i = 0; i < dynamicColliders.Count; i++)
  31.             {
  32.                 DynamicCollider col = dynamicColliders.Dequeue();
  33.                 if (col != collider)
  34.                     newColliders.Enqueue(col);
  35.             }
  36.             collider.isRegistered = false;
  37.             dynamicColliders = newColliders;
  38.         }
  39.     }
  40.  
  41.     public static void RunPhysicsSimulation(float time)
  42.     {
  43.         Queue<DynamicCollider> cols = new Queue<DynamicCollider>(dynamicColliders);
  44.  
  45.         while (cols.Count > 0)
  46.         {
  47.             DynamicCollider col = cols.Dequeue();
  48.             col.PhysicsUpdate(time);
  49.  
  50.             DoCollision(col, time);
  51.         }
  52.     }
  53.  
  54.     private static void DoCollision(DynamicCollider col, float time)
  55.     {
  56.         Pos3Int colliderPos = new Pos3Int((int)col.transform.position.x, (int)col.transform.position.y, (int)col.transform.position.z);
  57.         Queue<ushort> blocksInRadius = new Queue<ushort>();
  58.         float lowestCollisionTime = 1f;
  59.         float highestRemainingTime = 0f;
  60.         Vector3 foundNormal = Vector3.zero;
  61.  
  62.         for (int x = colliderPos.x - Mathf.RoundToInt(col.colliderSize.x) + Mathf.RoundToInt(col.colliderOffset.x) - 1; x <= colliderPos.x + Mathf.RoundToInt(col.colliderSize.x) + Mathf.RoundToInt(col.colliderOffset.x) + 1; x++)
  63.         {
  64.             for (int z = colliderPos.z - Mathf.RoundToInt(col.colliderSize.z) + Mathf.RoundToInt(col.colliderOffset.z) - 1; z <= colliderPos.z + Mathf.RoundToInt(col.colliderSize.z) + Mathf.RoundToInt(col.colliderOffset.z) + 1; z++)
  65.             {
  66.                 Pos2Int chunkPos = new Pos2Int(x / 16, z / 16);
  67.                 WorldChunk data = World.FindChunkData(chunkPos);
  68.                 if (data != null)
  69.                 {
  70.                     for (int y = colliderPos.y - Mathf.RoundToInt(col.colliderSize.y) + Mathf.RoundToInt(col.colliderOffset.y) - 1; y <= colliderPos.y + Mathf.RoundToInt(col.colliderSize.y) + Mathf.RoundToInt(col.colliderOffset.z) + 1; y++)
  71.                     {
  72.                         if (y >= 0 && y < 256)
  73.                         {
  74.                             int xChunk = Mathf.Abs(x) % 16;
  75.                             int zChunk = Mathf.Abs(z) % 16;
  76.  
  77.                             ushort block = data.chunkInfo[xChunk + zChunk * 16 + y * 256];
  78.                             if (block != 0 && BlockDictionary.GetBlockInformation(block).hasCollision)
  79.                             {
  80.                                 Pos3 vel = new Pos3(col.velocity.x * time, col.velocity.y * time, col.velocity.z * time);
  81.                                 //if (AABBBroadCheck(broadStart, broadSize, new Pos3Int(x, y, z)))
  82.                                 //{
  83.                                     Vector3 normal;
  84.                                     float colTime;
  85.                                     CollisionHandeling(block, new Pos3(x, y, z), col, vel, out normal, out colTime);
  86.                                     if (colTime < lowestCollisionTime)
  87.                                     {
  88.                                         lowestCollisionTime = colTime;
  89.                                         foundNormal = normal;
  90.                                         Debug.Log("Closest collision is " + BlockDictionary.GetBlockInformation(block).internalName);
  91.                                     }
  92.                                 //}
  93.                             }
  94.                         }
  95.                     }
  96.                 }
  97.             }
  98.         }
  99.         highestRemainingTime = 1 - lowestCollisionTime;
  100.  
  101.         if(lowestCollisionTime > 0)
  102.             col.transform.position += col.velocity * time * lowestCollisionTime;
  103.  
  104.         // slide
  105.         // push
  106.         /*
  107.         float magnitude = Mathf.Sqrt((col.velocity.x * col.velocity.x + col.velocity.y * col.velocity.y)) * highestRemainingTime;
  108.         float dotprod = col.velocity.x * foundNormal.y + col.velocity.y * foundNormal.x;
  109.         if (dotprod > 0.0f)
  110.             dotprod = 1.0f;
  111.         else if (dotprod < 0.0f)
  112.             dotprod = -1.0f;
  113.         col.velocity.x = dotprod * foundNormal.y * magnitude;
  114.         col.velocity.y = dotprod * foundNormal.x * magnitude;*/
  115.         //col.velocity.x = foundNormal.x * col.velocity.x;
  116.         //col.velocity.y = foundNormal.y * col.velocity.y;
  117.         //col.transform.position += col.velocity * time;
  118.         Debug.Log(col.velocity + " " + foundNormal);
  119.         col.velocity.x = (foundNormal.x == 0) ? col.velocity.x : 0;
  120.         col.velocity.y = (foundNormal.y == 0) ? col.velocity.y : 0;
  121.         col.velocity.z = (foundNormal.z == 0) ? col.velocity.z : 0;
  122.         Debug.Log(col.velocity + " " + foundNormal.x);
  123.         col.hitNormal = foundNormal;
  124.         /*
  125.         if (highestRemainingTime > 0)
  126.         {
  127.             float dotprod = col.velocity.x * foundNormal.x + col.velocity.y * foundNormal.y;
  128.             col.velocity = col.velocity + dotprod * foundNormal;
  129.         }*/
  130.     }
  131.  
  132.     private static bool AABBBroadCheck(Vector3 areaStart, Vector3 size, Pos3Int cubePos)
  133.     {
  134.         if (areaStart.x + size.x > cubePos.x && areaStart.x < cubePos.x + 1 &&
  135.             areaStart.y + size.y > cubePos.y && areaStart.y < cubePos.y + 1 &&
  136.             areaStart.z + size.z > cubePos.x && areaStart.z < cubePos.z + 1)
  137.         {
  138.             return true;
  139.         }
  140.         return false;
  141.     }
  142.  
  143.     private static void GenerateBroadArea(Vector3 start, Vector3 size, out Vector3 finishedStart, out Vector3 finishedSize)
  144.     {
  145.         if (size.x < 0)
  146.         {
  147.             start.x += size.x;
  148.             size.x = -size.x;
  149.         }
  150.         if (size.y < 0)
  151.         {
  152.             start.y += size.y;
  153.             size.y = -size.y;
  154.         }
  155.         if (size.z < 0)
  156.         {
  157.             start.z += size.z;
  158.             size.z = -size.z;
  159.         }
  160.         finishedStart = start;
  161.         finishedSize = size;
  162.         Debug.Log(finishedStart + " " + finishedSize);
  163.     }
  164.  
  165.     private static void CollisionHandeling(ushort blockId, Pos3 blockPosition, DynamicCollider toCheck, Pos3 velocity, out Vector3 normal, out float collisionTime)
  166.     {
  167.         //Pos3 toCheckPosition = new Pos3(toCheck.transform.position.x + toCheck.colliderOffset.x, toCheck.transform.position.y + toCheck.colliderOffset.y, toCheck.transform.position.z + toCheck.colliderOffset.z) + velocity;
  168.  
  169.         normal = Vector3.zero;
  170.         collisionTime = SweptAABB(toCheck, blockPosition, velocity, out normal.x, out normal.y, out normal.z);
  171.     }
  172.  
  173.     private static float SweptAABB(DynamicCollider col, Pos3 blockPos, Pos3 velocity, out float normalX, out float normalY, out float normalZ)
  174.     {
  175.         float xInvEntry, yInvEntry, zInvEntry;
  176.         float xInvExit, yInvExit, zInvExit;
  177.         Pos3 colPos = new Pos3(col.transform.position.x + col.colliderOffset.x, col.transform.position.y + col.colliderOffset.y, col.transform.position.z + col.colliderOffset.z);
  178.         // find the distance between the objects on the near and far sides for both x and y
  179.         if (velocity.x > 0.0f)
  180.         {
  181.             xInvEntry = blockPos.x - (colPos.x + col.colliderSize.x);
  182.             xInvExit = (blockPos.x + 1) - colPos.x;
  183.         }
  184.         else
  185.         {
  186.             xInvEntry = (blockPos.x + 1) - colPos.x;
  187.             xInvExit = blockPos.x - (colPos.x + col.colliderSize.x);
  188.         }
  189.  
  190.         if (velocity.y > 0.0f)
  191.         {
  192.             yInvEntry = blockPos.y - (colPos.y + col.colliderSize.y);
  193.             yInvExit = (blockPos.y + 1) - colPos.y;
  194.         }
  195.         else
  196.         {
  197.             yInvEntry = (blockPos.y + 1) - colPos.y;
  198.             yInvExit = blockPos.y - (colPos.y + col.colliderSize.y);
  199.         }
  200.         /*
  201.         if (velocity.z > 0.0f)
  202.         {
  203.             zInvEntry = blockPos.z - (colPos.z + col.colliderSize.z);
  204.             zInvExit = (blockPos.z + 1) - colPos.z;
  205.         }
  206.         else
  207.         {
  208.             zInvEntry = (blockPos.z + 1) - colPos.z;
  209.             zInvExit = blockPos.z - (colPos.z + col.colliderSize.z);
  210.         }*/
  211.  
  212.         // find time of collision and time of leaving for each axis (if statement is to prevent divide by zero)
  213.         float xEntry, yEntry, zEntry;
  214.         float xExit, yExit, zExit;
  215.         if (velocity.x == 0.0f)
  216.         {
  217.             xEntry = float.NegativeInfinity;//-std::numeric_limits::infinity();
  218.             xExit = float.PositiveInfinity;//std::numeric_limits::infinity();
  219.         }
  220.         else
  221.         {
  222.             xEntry = xInvEntry / velocity.x;
  223.             xExit = xInvExit / velocity.x;
  224.         }
  225.  
  226.         if (velocity.y == 0.0f)
  227.         {
  228.             yEntry = float.NegativeInfinity;//-std::numeric_limits::infinity();
  229.             yExit = float.PositiveInfinity;//std::numeric_limits::infinity();
  230.         }
  231.         else
  232.         {
  233.             yEntry = yInvEntry / velocity.y;
  234.             yExit = yInvExit / velocity.y;
  235.         }
  236.         /*
  237.         if (velocity.z == 0.0f)
  238.         {
  239.             zEntry = float.NegativeInfinity;//-std::numeric_limits::infinity();
  240.             zExit = float.PositiveInfinity;//std::numeric_limits::infinity();
  241.         }
  242.         else
  243.         {
  244.             zEntry = zInvEntry / col.velocity.z;
  245.             zExit = zInvExit / col.velocity.z;
  246.         }
  247.         */
  248.  
  249.         // find the earliest/latest times of collision
  250.         float entryTime = Mathf.Max(xEntry, yEntry);//, zEntry);
  251.         float exitTime = Mathf.Min(xExit, yExit);//, zExit);
  252.  
  253.         if (entryTime > exitTime || xEntry < 0.0f && yEntry < 0.0f ||/* zEntry < 0.0f ||*/ xEntry > 1.0f || yEntry > 1.0f /*|| zEntry > 1.0f*/)
  254.         {
  255.             normalX = 0.0f;
  256.             normalY = 0.0f;
  257.             normalZ = 0.0f;
  258.             return 1.0f;
  259.         }
  260.         else // if there was a collision
  261.         {
  262.             // calculate normal of collided surface
  263.             if (xEntry > yEntry)// && xEntry > zEntry)
  264.             {
  265.                 if (xInvEntry < 0.0f)
  266.                 {
  267.                     normalX = 1.0f;
  268.                     normalY = 0.0f;
  269.                     normalZ = 0.0f;
  270.                 }
  271.                 else
  272.                 {
  273.                     normalX = -1.0f;
  274.                     normalY = 0.0f;
  275.                     normalZ = 0.0f;
  276.                 }
  277.             }
  278.             else// if (yEntry > zEntry)
  279.             {
  280.                 if (yInvEntry < 0.0f)
  281.                 {
  282.                     normalX = 0.0f;
  283.                     normalY = 1.0f;
  284.                     normalZ = 0.0f;
  285.                 }
  286.                 else
  287.                 {
  288.                     normalX = 0.0f;
  289.                     normalY = -1.0f;
  290.                     normalZ = 0.0f;
  291.                 }
  292.             }
  293.             /*
  294.             else
  295.             {
  296.                 if (zInvEntry < 0.0f)
  297.                 {
  298.                     normalX = 0.0f;
  299.                     normalY = 0.0f;
  300.                     normalZ = 1.0f;
  301.                 }
  302.                 else
  303.                 {
  304.                     normalX = 0.0f;
  305.                     normalY = 0.0f;
  306.                     normalZ = -1.0f;
  307.                 }
  308.             }
  309.             */
  310.             // return the time of collision
  311.             return entryTime;
  312.         }
  313.     }
  314. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement