Hello, my fellow developers! Today, I wanna answer a
question that has been asked many times, How do you make a music player? Finding efficiency in your code makes you feel amazing, at least to me. And let me tell you right now, using wait()
in your code to play songs isn’t efficient at all. So today, I’m gonna teach you an awesome way of doing it without ever modifying the script again unless you wish to add new features.
Edited Post
I have now edited this post to include skipping songs!
Step 1:
You want to make a folder in the ServerStorage called “Songs”. In that folder, you will be putting the songs you wish to play in your music player. Each one will be an IntValue. The name of the IntValue will be the name of the song and its value will be the ROBLOX asset ID of the song.
Step 2:
Make a sound object in the SoundService. Call it whatever you wish. I recommend calling it “Music” or something similar to that. That’s how we are going to play the songs.
(This might also be called Soundspace so look for either those two.)
Step 3
After creating the required objects to play our songs, we start coding. You want to insert a Script inside the ServerScriptService. This script is where we will handle our code for the music player. You can call it whatever you want, I will call it “MusicHandler”.
Step 4
A wise bird (Scripting - Making a Music Queue) told me that it’s a good idea to use BindableEvents for our functions. So let’s do that, shall we? We will be making two BindableEvents inside our script. One will be for adding the songs to a queue and the other for playing the next song in that queue. Name those bindable functions playSong
and addSongs
Alright, let’s get to coding, shall we? In our code, we want to type this:
local music = game.Soundscape.Music -- The path to the sound object you created in the SoundService. If that doesn't work, try replacing Soundscape with SoundService.
local songs = game.ServerStorage.Songs:GetChildren() -- The :GetChildren() method returns a lua table containing the objects inside the instance we used it on. In this case, that's the Songs folder we created in the ServerStorage.
local queue = {} -- Here, we will be putting all the songs in the songs folder and play them all in order. We will also "shuffle" the queue.
The comments I provided for the lines explain what they do. Just for your information.
Now, we want to bind our addSongs
event to a function. This will add all the songs in the songs folder to our queue
table. We will be using it later.
script.addSongs.Event:Connect(function()
for _,song in pairs(songs) do -- This for loop will iterate over every object in our songs folder.
if song:IsA("IntValue") then -- We check if the song is an IntValue to make sure it's a song.
table.insert(queue, {
["songName"] = song.Name, -- The name of the song. As we mentioned, it is the name of the IntValue.
["songID"] = "rbxassetid://"..tostring(song.Value) -- The ID of the song. As we mentioned, it is the value of the IntValue. We add rbxassetid:// before it because sound objects have it in that format.
}) -- This will insert a table inside our queue table containing the information for our song.
end
end
for i = 1, #queue - 1 do
local r = math.random(i,#queue)
queue[i], queue[r] = queue[r], queue[i]
end -- This shuffles the table. This method of shuffling is called the "Fisher-Yates Shuffle". If you wish to find out how it works, go search it up!
end)
That table shuffling method is not made by me! I actually searched up a way to do this in the developer forums and found this: https://devforum.roblox.com/t/table-scrambling/13784/5?u=slipperyisawesome_a
Now, we want to bind our playSong
event to a function. This will be used to play the next song in the queue. We will also be using this later.
script.playSong.Event:Connect(function()
if #queue == 0 then script.addSongs:Fire() end -- Here, we check if there are no more songs in the queue table. If there aren't, then we add them again.
local songToPlay = queue[1] -- This is the next song in the queue table. Further into this function, we remove that from the table as it's already playing.
music.SoundId = songToPlay.songID -- We set the sound ID property of the sound object to the songID we defined in the song to play.
music:Play() -- This plays the song.
table.remove(queue, 1) -- This removes the song from the table as it's already playing.
music.Ended:Wait() -- We wait for the song to finish, and then we play the next one.
local delayBeforeNextSongPlays = 3 -- The amount of time we will wait before the next song plays after the current one is done.
wait(delayBeforeNextSongPlays)
script.playSong:Fire() -- We run this function again.
end)
Alright, we have done our primary methods! Now that we have finished these, we can easily call them all the way at the bottom of the code.
script.addSongs:Fire()-- Calls the addSongs() function which as we said, adds the songs into the queue table.
script.playSong:Fire() -- Plays the next song available in the queue. :)
Alright! Now, we will be adding a feature to be able to skip songs with a command you can type in chat called !skip
. This command will only be executable by players of your liking.
To make this event listener work, we must put it BEFORE calling our playSong()
and addSongs()
functions. If you put it after, it will not listen out for the event due to functions yielding.
local allowedPlayers = {"coolmam515", "anotherCoolMan516"} -- The people who are allowed to execute the !skip command. If you want, you can also check for a rank instead.
game.Players.PlayerAdded:Connect(function(player) -- The code inside this event listener will happen when a player joins. It passes in the player parameter which is the player who joined.
player.Chatted:Connect(function(msg) -- The code inside this event listener will happen when the player who joined chats. The msg parameter is the message they chatted.
if string.lower(msg) == "!skip" then -- We check if the lowercase version of the message they chatted is "!skip". string.lower(string) returns the lowercase version of the string.
if table.find(allowedPlayers, player.Name) then -- We check if the player's name exists in the allowedPlayers table we created earlier.
-- IF YOU WANT TO CHECK FOR A RANK, you can easily replace table.find(allowedPlayers, player.Name) with player:GetRankInGroup(groupID) which will return the numerical rank of the player in that group instead of checking if their username exists in the table.
--[[ Example:
if player:GetRankInGroup(000000) > 5 then
nice code
end
--]]
table.remove(queue, 1) -- This will remove the currently playing song from the queue table to be able to play the next one.
script.playSong:Fire() -- We then simply fire the playSong() function as we already know that handles everything.
end
end
end)
end)
And that is it! We have created our music player. I hope this didn’t only teach you to make a music player, but to find efficiency to your code and apply it. Doing this is a lot better than using multiple wait()
s in your code.
If you wish to add songs, you can easily insert an IntValue to the Songs folder we created earlier. Set the name of the IntValue to the name of the song and then set the value of it to its ROBLOX asset ID.
If I ever want to, I might teach you to add the ability to request/skip songs.
I hope you learned something new today. Thanks for reading my post.