Glad part 2 is finally out! Though, Are you going to make the place you did the tutorial in uncopylocked? Copy and pasting all of those modules from part 1 and part 2 seems rather tiresome.
If it becomes really annoying to everyone who reads it, I guess ill do that, but for now I kinda want people to try to actually read the modules instead of just copying a place. I get what you are saying though, there are so many things, so I can see how tiresome it is lol.
Oh, speaking of… There’s some missing functions in the Util module that you used in this post, Those mainly being Util.Lerp and Util.GetGetXPositionForNoteData, those are the 2 functions I found missing from the Util module, or I’m just blind.
As @jamesderrman was saying the tutorial is pretty confusing at least for me and Util.Lerp and Util.GetGetXPositionForNoteData are missing from the Util module
Honestly not bad of a tutorial!
It’s really similar to the process I’ve had to go thru the development of my FNF engine, so +1 from me!
Only issue is the sprite not supporting proper centering when it relates to other sprites like the character sprites.
Oh yeah, and about the sprite positioning thing, that is probably something that I will work on and ill put an update or something. I think that it has something to do with the XML values that have more data (like 4 extra values), but ill have to test.
(probably updates in a new post because I hit the 50000 limit exactly.)
EDIT: Wow, I tried your engine, and the gameplay beats every single FNF game on Roblox by a mile! Props to you for getting it that good!
Sorry about that! I probably deleted it on accident because I was hitting the 50000 character limit
Here is Util:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Source = ReplicatedStorage:WaitForChild("Source")
local Util = {
--\\ FNF Screen size: https://github.com/FunkinCrew/Funkin/blob/master/Project.xml
ScreenSize = Vector2.new(1280, 720); --\\ FNF is in 720p lol
--\\ AspectRatio = 16:9
NoteWidth = (166 * 0.7); --\\ all notes are scaled down by 0.7, so NoteWidth is the original pixel size of every note scaled down by 0.7.
--\\ For keybinds
KeybindNames = {
[1] = "Left";
[2] = "Down";
[3] = "Up";
[4] = "Right";
};
--\\ For notes
NoteDataNames = {
[1] = "Left";
[2] = "Down";
[3] = "Up";
[4] = "Right";
};
}
function Util.GetXPositionForNoteData(NoteData, ManualSide, PlayerSide)
NoteData += 1 --\\ Shift it over one for roblox
if PlayerSide == 2 then
--\\ Normal PlayerSide
--\\ Shenanigans for Notes.
NoteData -= 1 --\\ Shift it back over because we are using modulo
if ManualSide == 2 then --\\ Player2
return (Util.ScreenSize.X - ((5 - ((NoteData % 4) + 1)) * (Util.NoteWidth)))
end
if ManualSide == 1 then --\\ Player1
return (((NoteData % 4) + 1) * (Util.NoteWidth))
end
else
--\\ Flip all if PlayerSide is flipped.
--\\ Shenanigans for Notes.
NoteData -= 1 --\\ Shift it back over because we are using modulo
if ManualSide == 1 then --\\ Player2
return (Util.ScreenSize.X - ((5 - ((NoteData % 4) + 1)) * (Util.NoteWidth)))
end
if ManualSide == 2 then --\\ Player1
return (((NoteData % 4) + 1) * (Util.NoteWidth))
end
end
return 0
end
function Util.Lerp(start, goal, t)
return start + (goal - start) * t
end
function Util.GetStrumX(StrumIndex)
StrumIndex += 1
--\\ For strums
if StrumIndex > 4 then --\\ Player2
--\\ get screensize-x and subtract (5-(index-4) * NoteWidth)
--\\ it's easier to understand this after you look at the one for the opponent
return (Util.ScreenSize.X - ((5 - (StrumIndex - 4)) * (Util.NoteWidth)))
end
if StrumIndex < 5 then --\\ Player1
--\\ just the product of the index and the NoteWidth
return (StrumIndex * (Util.NoteWidth))
end
return 0
end
return Util
That is totally my fault. Sorry for the late response, Here is Util:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Source = ReplicatedStorage:WaitForChild("Source")
local Util = {
--\\ FNF Screen size: https://github.com/FunkinCrew/Funkin/blob/master/Project.xml
ScreenSize = Vector2.new(1280, 720); --\\ FNF is in 720p lol
--\\ AspectRatio = 16:9
NoteWidth = (166 * 0.7); --\\ all notes are scaled down by 0.7, so NoteWidth is the original pixel size of every note scaled down by 0.7.
--\\ For keybinds
KeybindNames = {
[1] = "Left";
[2] = "Down";
[3] = "Up";
[4] = "Right";
};
--\\ For notes
NoteDataNames = {
[1] = "Left";
[2] = "Down";
[3] = "Up";
[4] = "Right";
};
}
function Util.GetXPositionForNoteData(NoteData, ManualSide, PlayerSide)
NoteData += 1 --\\ Shift it over one for roblox
if PlayerSide == 2 then
--\\ Normal PlayerSide
--\\ Shenanigans for Notes.
NoteData -= 1 --\\ Shift it back over because we are using modulo
if ManualSide == 2 then --\\ Player2
return (Util.ScreenSize.X - ((5 - ((NoteData % 4) + 1)) * (Util.NoteWidth)))
end
if ManualSide == 1 then --\\ Player1
return (((NoteData % 4) + 1) * (Util.NoteWidth))
end
else
--\\ Flip all if PlayerSide is flipped.
--\\ Shenanigans for Notes.
NoteData -= 1 --\\ Shift it back over because we are using modulo
if ManualSide == 1 then --\\ Player2
return (Util.ScreenSize.X - ((5 - ((NoteData % 4) + 1)) * (Util.NoteWidth)))
end
if ManualSide == 2 then --\\ Player1
return (((NoteData % 4) + 1) * (Util.NoteWidth))
end
end
return 0
end
function Util.Lerp(start, goal, t)
return start + (goal - start) * t
end
function Util.GetStrumX(StrumIndex)
StrumIndex += 1
--\\ For strums
if StrumIndex > 4 then --\\ Player2
--\\ get screensize-x and subtract (5-(index-4) * NoteWidth)
--\\ it's easier to understand this after you look at the one for the opponent
return (Util.ScreenSize.X - ((5 - (StrumIndex - 4)) * (Util.NoteWidth)))
end
if StrumIndex < 5 then --\\ Player1
--\\ just the product of the index and the NoteWidth
return (StrumIndex * (Util.NoteWidth))
end
return 0
end
return Util
For very long songs, the JSON should be compressed, and removed of all it’s spaces and new lines. If it’s small enough, it could be put in a StringValue. But to reduce logic, it should be kept in a module script.
I can’t comment on anything else in the tutorial, I have something called ‘laziness’.