Grizmu

Unity WaveFloor.cs

Jul 15th, 2025 (edited)
34
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 11.22 KB | Source Code | 0 0
  1. using UnityEngine;
  2.  
  3. public class WaveFloor : MonoBehaviour
  4. {
  5.     [Header("Basic")]
  6.     public MeshFilter meshFilter;
  7.  
  8.     [Header("Floor")]
  9.     [Tooltip("Where the floor should start")]
  10.     public Transform transformStart;
  11.     [Tooltip("Where the floor should end")]
  12.     public Transform transformEnd;
  13.     [Min(2)]
  14.     [Tooltip("How many modules the floor will have")]
  15.     public int floorParts = 8;
  16.     [Tooltip("How strong should the waving be")]
  17.     public float power = 0.5f;
  18.     [Tooltip("How quick should the waving be")]
  19.     public float speed = 1.2f;
  20.     [Tooltip("Y offset of the vertices")]
  21.     public float yOffset = 0.5f;
  22.     [Tooltip("Speed offset")]
  23.     public float speedOffset = 0.5f;
  24.     [Tooltip("How high should the floor be")]
  25.     public float floorHeight = 0.5f;
  26.  
  27.     [Header("Colliders")]
  28.     [Tooltip("How many capsule colliders will handle this floor")]
  29.     public int collidersAmount = 32;
  30.     public float colliderRadius = 0.5f;
  31.     public float colliderHeight = 8f;
  32.  
  33.     private CapsuleCollider[] capsuleColliders;
  34.     private int vertexAmount;
  35.     private Vector3[] vertices;
  36.     private Mesh mesh;
  37.  
  38.     private void Start()
  39.     {
  40.         mesh = CreateMesh();
  41.         CreateColliders();
  42.        
  43.         meshFilter.sharedMesh = mesh;
  44.     }
  45.  
  46. #if UNITY_EDITOR
  47.     private void OnDrawGizmos()
  48.     {
  49.         // Some rendering for the scene view so we know what's up.
  50.  
  51.         if(transformStart == null)
  52.         {
  53.             return;
  54.         }
  55.  
  56.         if(transformEnd == null)
  57.         {
  58.             return;
  59.         }
  60.  
  61.         Color color = Color.red;
  62.         color.a = 0.4f;
  63.         Gizmos.color = color;
  64.  
  65.         Vector3 start = transformStart.position;
  66.         Vector3 end = transformEnd.position;
  67.         Vector3 size = (end - start);
  68.         Vector3 middle = start + (size * 0.5f);
  69.         size.y = floorHeight;
  70.         Gizmos.DrawCube(middle, size);
  71.     }
  72. #endif
  73.  
  74.     private void FixedUpdate()
  75.     {
  76.         UpdateWaveFloor();
  77.     }
  78.  
  79.     private void UpdateWaveFloor()
  80.     {
  81.         // Animate the floor vertices over time.
  82.         //
  83.         // This code could have been jobified and bursted, so if you ever need a ton of those moving floors
  84.         // it's a pretty quick way to optimize it.
  85.  
  86.         Vector3 start = transformStart.position;
  87.         Vector3 end = transformEnd.position;
  88.         float stepX = (end.x - start.x) / floorParts;
  89.  
  90.         Vector3 currentStart = start;
  91.         Vector3 currentEnd = new Vector3(start.x + stepX, end.y, end.z);
  92.  
  93.         for (int i = 0; i <= floorParts; i++)
  94.         {
  95.             float currentOffset = i * speedOffset;
  96.             float yPositon = currentStart.y + power * Mathf.Sin((Time.time + currentOffset) * speed) + yOffset;
  97.  
  98.             vertices[i * 4] = new Vector3(currentStart.x,
  99.                                           yPositon,
  100.                                           currentStart.z);
  101.  
  102.             vertices[i * 4 + 1] = new Vector3(currentStart.x,
  103.                                               yPositon,
  104.                                               currentEnd.z);
  105.  
  106.             vertices[i * 4 + 2] = new Vector3(currentStart.x,
  107.                                               yPositon - floorHeight,
  108.                                               currentEnd.z);
  109.  
  110.             vertices[i * 4 + 3] = new Vector3(currentStart.x,
  111.                                               yPositon - floorHeight,
  112.                                               currentStart.z);
  113.  
  114.  
  115.             currentStart.x = currentStart.x + stepX;
  116.             currentEnd.x = currentEnd.x + stepX;
  117.         }
  118.  
  119.         Vector3 position = Vector3.zero;
  120.         position.y = end.y;
  121.         float stepXColliders = (end.x - start.x) / (collidersAmount - 1);
  122.         float speedOffsetMultiplier = stepXColliders / stepX;
  123.         float colliderYOffset = colliderRadius;
  124.  
  125.         for (int i = 0; i < capsuleColliders.Length; i++)
  126.         {
  127.             float currentOffset = i * speedOffset * speedOffsetMultiplier;
  128.             float yPositon = currentStart.y + power * Mathf.Sin((Time.time + currentOffset) * speed) + yOffset;
  129.  
  130.             CapsuleCollider collider = capsuleColliders[i];
  131.  
  132.             position.x = start.x + i * stepXColliders;
  133.             position.y = yPositon - colliderYOffset;
  134.             collider.center = position;
  135.         }
  136.  
  137.         mesh.vertices = vertices;
  138.         mesh.RecalculateNormals();
  139.         mesh.UploadMeshData(false);
  140.     }
  141.  
  142.     private void CreateColliders()
  143.     {
  144.         //Create capsule colliders to handle collisions.
  145.         //
  146.         //You could also skip this if you don't care about primitive colliders and just throw in the generated mesh
  147.         //into a mesh collider component and collisions will be more accurate. Do have in mind though that it might be less performant if updated each frame.
  148.  
  149.         capsuleColliders = new CapsuleCollider[collidersAmount];
  150.  
  151.         Vector3 start = transformStart.position;
  152.         Vector3 end = transformEnd.position;
  153.         Vector3 difference = end - start;
  154.         Vector3 position = Vector3.zero;
  155.         float yOffset = colliderRadius;
  156.         position.y = end.y - yOffset;
  157.  
  158.         float xStep = difference.x / (collidersAmount-1);
  159.  
  160.         for (int i = 0; i < collidersAmount; i++)
  161.         {
  162.             CapsuleCollider collider = gameObject.AddComponent<CapsuleCollider>();
  163.             collider.height = colliderHeight;
  164.             collider.radius = colliderRadius;
  165.             collider.direction = 2; //This makes it streched using its height on the z axis.
  166.  
  167.             position.x = start.x + i * xStep;
  168.             collider.center = position;
  169.  
  170.             capsuleColliders[i] = collider;
  171.         }
  172.     }
  173.  
  174.     private Mesh CreateMesh()
  175.     {
  176.         // We'll do a procedural mesh generation using extruding approach, starting
  177.         // from the left side and stepping towards the end at the right side.
  178.  
  179.         Mesh mesh = new Mesh();
  180.         mesh.name = "Wave Floor";
  181.  
  182.         //Some quick maths to create arrays of just right sizes to not have to resize them.
  183.         Vector3 start = transformStart.position;
  184.         Vector3 end = transformEnd.position;
  185.         vertexAmount = 12 + 4 * (floorParts - 2);
  186.         int triangleAmount = 20 + 8 * (floorParts - 2);
  187.  
  188.         vertices = new Vector3[vertexAmount];
  189.         int[] triangles = new int[triangleAmount * 3];
  190.  
  191.         float stepX = (end.x - start.x) / floorParts;
  192.         Vector3 currentStart = start;
  193.         Vector3 currentEnd = new Vector3(start.x + stepX, end.y, end.z);
  194.  
  195.         // Start/Left part
  196.         //
  197.         //      Top  
  198.         //     ..1..      
  199.         //   0`  |  `2  
  200.         //   |``-3-``|
  201.         //   |   |   |
  202.         //   | ..5.. |
  203.         //   4`  |  `6
  204.         //    ``-7-``
  205.         //     Bottom
  206.         //
  207.         //  0,1,2,3 - Top
  208.         //  5,4,7,6 - Bottom
  209.         //  4,0,3,7 - Front
  210.         //  Skip right, no wall needed
  211.         //  1,0,4,5 - Left
  212.         //  2,1,5,6 - Back
  213.  
  214.         vertices[0] = currentStart;
  215.         vertices[1] = new Vector3(currentStart.x, currentStart.y, currentEnd.z);
  216.         vertices[2] = new Vector3(currentStart.x, currentStart.y - floorHeight, currentEnd.z);
  217.         vertices[3] = new Vector3(currentStart.x, currentStart.y - floorHeight, currentStart.z);
  218.  
  219.         int triangleID = 0;
  220.  
  221.         triangles[triangleID] = 1; triangleID++;
  222.         triangles[triangleID] = 0; triangleID++;
  223.         triangles[triangleID] = 3; triangleID++;
  224.         triangles[triangleID] = 3; triangleID++;
  225.         triangles[triangleID] = 2; triangleID++;
  226.         triangles[triangleID] = 1; triangleID++; //Left
  227.  
  228.         // Middle part
  229.         //
  230.         //      Top  
  231.         //     ..1..      
  232.         //   0`  |  `2  
  233.         //   |``-3-``|
  234.         //   |   |   |
  235.         //   | ..5.. |
  236.         //   4`  |  `6
  237.         //    ``-7-``
  238.         //     Bottom
  239.         //
  240.         //  0,1,2,3 - Top
  241.         //  5,4,7,6 - Bottom
  242.         //  4,0,3,7 - Front
  243.         //  Skip right, no wall needed
  244.         //  Skip left, no wall needed
  245.         //  2,1,5,6 - Back
  246.         //
  247.         // Iterate until we'll generate all the floor parts
  248.         // Congratulations. You are one of the few people to reach this place :)
  249.  
  250.         int i = 0;
  251.         for (i = 0; i < floorParts; i++)
  252.         {
  253.             vertices[i * 4 + 4] = new Vector3(currentEnd.x, currentStart.y, currentStart.z);
  254.             vertices[i * 4 + 5] = new Vector3(currentEnd.x, currentStart.y, currentEnd.z);
  255.             vertices[i * 4 + 6] = new Vector3(currentEnd.x, currentEnd.y - floorHeight, currentEnd.z);
  256.             vertices[i * 4 + 7] = new Vector3(currentEnd.x, currentStart.y - floorHeight, currentStart.z);
  257.  
  258.             triangles[triangleID] = i * 4 + 0; triangleID++;
  259.             triangles[triangleID] = i * 4 + 1; triangleID++;
  260.             triangles[triangleID] = i * 4 + 5; triangleID++;
  261.             triangles[triangleID] = i * 4 + 5; triangleID++;
  262.             triangles[triangleID] = i * 4 + 4; triangleID++;
  263.             triangles[triangleID] = i * 4 + 0; triangleID++; //Top
  264.  
  265.             triangles[triangleID] = i * 4 + 3; triangleID++;
  266.             triangles[triangleID] = i * 4 + 7; triangleID++;
  267.             triangles[triangleID] = i * 4 + 6; triangleID++;
  268.             triangles[triangleID] = i * 4 + 6; triangleID++;
  269.             triangles[triangleID] = i * 4 + 2; triangleID++;
  270.             triangles[triangleID] = i * 4 + 3; triangleID++; //Bottom
  271.  
  272.             triangles[triangleID] = i * 4 + 0; triangleID++;
  273.             triangles[triangleID] = i * 4 + 4; triangleID++;
  274.             triangles[triangleID] = i * 4 + 7; triangleID++;
  275.             triangles[triangleID] = i * 4 + 7; triangleID++;
  276.             triangles[triangleID] = i * 4 + 3; triangleID++;
  277.             triangles[triangleID] = i * 4 + 0; triangleID++; //Front
  278.  
  279.             triangles[triangleID] = i * 4 + 5; triangleID++;
  280.             triangles[triangleID] = i * 4 + 1; triangleID++;
  281.             triangles[triangleID] = i * 4 + 2; triangleID++;
  282.             triangles[triangleID] = i * 4 + 2; triangleID++;
  283.             triangles[triangleID] = i * 4 + 6; triangleID++;
  284.             triangles[triangleID] = i * 4 + 5; triangleID++; //Back
  285.  
  286.             currentStart.x = currentStart.x + stepX;
  287.             currentEnd.x = currentEnd.x + stepX;
  288.         }
  289.  
  290.         // End/Right part
  291.         //      Top  
  292.         //     ..1..      
  293.         //   0`  |  `2  
  294.         //   |``-3-``|
  295.         //   |   |   |
  296.         //   | ..5.. |
  297.         //   4`  |  `6
  298.         //    ``-7-``
  299.         //     Bottom
  300.         //
  301.         //  0,1,2,3 - Top
  302.         //  5,4,7,6 - Bottom
  303.         //  4,0,3,7 - Front
  304.         //  Skip left, no wall needed
  305.         //  1,0,4,5 - Right
  306.         //  2,1,5,6 - Back
  307.  
  308.         triangles[triangleID] = i * 4 + 0; triangleID++;
  309.         triangles[triangleID] = i * 4 + 1; triangleID++;
  310.         triangles[triangleID] = i * 4 + 2; triangleID++;
  311.         triangles[triangleID] = i * 4 + 2; triangleID++;
  312.         triangles[triangleID] = i * 4 + 3; triangleID++;
  313.         triangles[triangleID] = i * 4 + 0; triangleID++; //Right
  314.  
  315.         mesh.vertices = vertices;
  316.         mesh.triangles = triangles;
  317.  
  318.         mesh.RecalculateNormals();
  319.         mesh.UploadMeshData(false);
  320.  
  321.         return mesh;
  322.     }
  323. }
  324.  
Tags: Unity
Advertisement
Add Comment
Please, Sign In to add comment