Post by mescalyne on Jul 16, 2017 17:59:10 GMT
Hello there! If you've opened up this post, you probably want to learn how to create an audio-responsive dance floor.
If you've scripted for some time, you've more than likely seen the age-old example which shows you how to create a minimal "dance floor" with tiles that randomly change color. This is not one of those! It is audio-responsive, meaning that it responds to the qualities of an audio signal through visual changes in itself. It makes a great addition to any club or party environment.
(You can see this code in action at this ROBLOX place.)
So, first things first, let's determine a workspace setup. We need a driving LocalScript (since only the client can access PlaybackLoudness, the property of a Sound we'll be using to track the audio level), and we need a Sound to monitor.
Got that done? Great. You might also want to set the Workspace's property FilteringEnabled to true, so we keep all changes created by the DanceFloor script local. Additionally, you can set the Playing property of Sound to true so we don't have to do so within the script.
Now we can get into the logic behind the dance floor. We'll set up some constants first...
Let's explain these lines.
Additionally we'll need a small portion of code to create a "sample buffer," for tracking audio data.
Here, we get into the creation of the tiles for the dance floor. Using the TOTAL_SZ constant we defined earlier, we cover a grid by iterating from 1 to TOTAL_SZ on both the X and Y axes. Then, on line 16, we generate a unique integer that isn't shared with any other coordinate pair. As such we're able to skip usage of a 2D "array." The rest of the code is really self-explanatory assuming you understand instantiation and property changes. Finally, we use the index variable we defined earlier to store this tile in our Tiles table. Pretty easy, right?
Here's a simple helper function that'll give us a method of updating our sample buffer (the samples table). We use table.insert to push something to the first slot of the table and push everything else in the table back.
Additionally we nullify the first unneeded sample in our buffer. Again, pretty basic stuff. Note that we divide the PlaybackLoudness by 1000 because PlaybackLoudness is a floating point value ranging from 0 to 1000, and I find it easier to deal with things in the 0 - 1 range.
Now we get to the beating heart of our script-- our tile updater function. It's fairly trivial to implement, but there's a bit of math involved. First, at the beginning of every render loop, we call our sampler function to update our sample buffer. Secondly, we use the same pattern as we did in our "tile creator" block of code in which we traverse both axes to cover a grid. We use the same method as we did in the aforementioned block to determine where the tile would be located in our table.
Now for the (somewhat) mathy part. We calculate distanceFromCenter by doing the following:
With that distance calculated, we use it to find the sample that should determine the appearance of this tile. We floor the distance, then add 1 because a distance of zero is possible and arrays do not start at 0 in ROBLOX Lua.
We use this sample in the fromHSV constructor of Color3 by setting the Light value equal to the sample value.
Okay, we're probably ready to go now! All that's left to do is add code which hooks this function to the render loop and we're done!
Hopefully you get a result similar to that of what I showcased at the top of this post. If not I'll try my best to see where my tutorial fell short!
EDIT: Updated font size. Was a bit hard to see and made everything look like a massive wall of text.
If you've scripted for some time, you've more than likely seen the age-old example which shows you how to create a minimal "dance floor" with tiles that randomly change color. This is not one of those! It is audio-responsive, meaning that it responds to the qualities of an audio signal through visual changes in itself. It makes a great addition to any club or party environment.
(You can see this code in action at this ROBLOX place.)
So, first things first, let's determine a workspace setup. We need a driving LocalScript (since only the client can access PlaybackLoudness, the property of a Sound we'll be using to track the audio level), and we need a Sound to monitor.
Got that done? Great. You might also want to set the Workspace's property FilteringEnabled to true, so we keep all changes created by the DanceFloor script local. Additionally, you can set the Playing property of Sound to true so we don't have to do so within the script.
Now we can get into the logic behind the dance floor. We'll set up some constants first...
Let's explain these lines.
- The "radius" of the dance floor.
- The tile size. The resulting tiles will occupy a space of (TILE_SIZE, 1, TILE_SIZE).
- The total size of the dance floor. One tile is subtracted because the center tile doesn't have a mirrored counterpart on the X or Y axis.
- This is the max sample that can be grabbed. Using the Pythagorean theorem/distance formula, we calculate the distance to the corner tile (which will be the furthest). We round this up to give us a nice integer number.
- A table that'll contain all of the tiles we create.
Additionally we'll need a small portion of code to create a "sample buffer," for tracking audio data.
Here, we get into the creation of the tiles for the dance floor. Using the TOTAL_SZ constant we defined earlier, we cover a grid by iterating from 1 to TOTAL_SZ on both the X and Y axes. Then, on line 16, we generate a unique integer that isn't shared with any other coordinate pair. As such we're able to skip usage of a 2D "array." The rest of the code is really self-explanatory assuming you understand instantiation and property changes. Finally, we use the index variable we defined earlier to store this tile in our Tiles table. Pretty easy, right?
Here's a simple helper function that'll give us a method of updating our sample buffer (the samples table). We use table.insert to push something to the first slot of the table and push everything else in the table back.
Additionally we nullify the first unneeded sample in our buffer. Again, pretty basic stuff. Note that we divide the PlaybackLoudness by 1000 because PlaybackLoudness is a floating point value ranging from 0 to 1000, and I find it easier to deal with things in the 0 - 1 range.
Now we get to the beating heart of our script-- our tile updater function. It's fairly trivial to implement, but there's a bit of math involved. First, at the beginning of every render loop, we call our sampler function to update our sample buffer. Secondly, we use the same pattern as we did in our "tile creator" block of code in which we traverse both axes to cover a grid. We use the same method as we did in the aforementioned block to determine where the tile would be located in our table.
Now for the (somewhat) mathy part. We calculate distanceFromCenter by doing the following:
- Create a Vector2 with the x and y coordinates that we're currently at.
- Subtract (SZ, SZ) from that Vector2-- this effectively makes the center located at 0, 0
- Get the magnitude of this-- in two-dimensional space this is essentially the same as using the Pythagorean theorem.
With that distance calculated, we use it to find the sample that should determine the appearance of this tile. We floor the distance, then add 1 because a distance of zero is possible and arrays do not start at 0 in ROBLOX Lua.
We use this sample in the fromHSV constructor of Color3 by setting the Light value equal to the sample value.
Okay, we're probably ready to go now! All that's left to do is add code which hooks this function to the render loop and we're done!
Hopefully you get a result similar to that of what I showcased at the top of this post. If not I'll try my best to see where my tutorial fell short!
EDIT: Updated font size. Was a bit hard to see and made everything look like a massive wall of text.