My objective is to make a note class for a rhythm game with all information I need to register note timings and other important variables using metatables instead of using regular roblox Instances with attributes.
The note class has a Position
key on the metatable which is a UDim2 that just determines where the actual relative position of the ImageLabel that visually represents the note to the user (there’s obviously more properties to the metatable but I’m just using the Position
key to not over complicate). I want to make the game run as smoothly as possible so instead of updating the ImageLabel’s position every frame to the Position
key on the metatable (which is just a waste of resources if the position in the current frame is the exact same as the position in the last frame) I’m taking advantage of the metatable’s metamethods and using the __newindex metamethod to bind to a key change and updating the ImageLabel’s position on the spot, but for some reason the metamethod just never fires for the Position
property.
Note ModuleScript (--[[...]]--
Indicates that a section of the script was trimmed out):
local Note = {}
Note.__index = Note
Note.__newindex = function(self, key, value)
rawset(self,key,value)
--[[...]]--
if key == "Position" or key == "PositionOffsets" then --:find("Position")
print("POSS")
self._Position = self.Position
for k,v in pairs(self.PositionOffsets) do self._Position += v end
self._Frame.Position = UDim2.new(self._Position.X.Scale,self._Position.X.Offset,self._Position.Y.Scale,self._Position.Y.Offset)
end
--[[...]]--
end
--[[...]]--
function Note.new(...)
local self = setmetatable({
--[[...]]--
Position = UDim2.fromScale(-1,-1); -- MIDDLE POSITION!
PositionOffsets = {};
Parent = nil;
--[[...]]--
_Frame = nil;
SpriteLabel = nil;
}, Note)
--[[...]]--
return self
end
--[[...]]--
return Note
On my GamePlay LocalScript I have a function bind to the RenderStepped event that updates the note's positions:
game:GetService("RunService").RenderStepped:Connect(function(delta)
--[[...]]
--
local songPos = shared.Conductor.songPosition * 1000
local scrollSpeed = shared.ScrollSpeed
local mania = shared.CurMatchInfo.Mania
for idx, note in pairs(shared.Notes) do
if note ~= nil and note._Alive then
local strum = shared.StrumLines[note.NoteData + 1 + note.Player * mania]
local strumX = strum._Position.X.Scale;
local strumY = strum._Position.Y.Scale;
local strumDirection = strum.Direction;
--[[...]]--
local distance = (0.45 * ((songPos - note.StrumTime) / 1000) * scrollSpeed * 1);
--[[...]]--
local strumNoteXTimeline = 0
local strumNoteYTimeline = 0
local strumNoteSpeedTimeline = 1
--[[...]]--
pcall(function() strumNoteXTimeline = strum.NoteXTimeline:CalculateValue(distance) / 100; end)
pcall(function() strumNoteYTimeline = strum.NoteYTimeline:CalculateValue(distance) / 100; end)
pcall(function() strumNoteSpeedTimeline = strum.NoteSpeedTimeline:CalculateValue(distance); end)
--[[...]]--
local directionCompensation = distance
if strum.Downscroll then directionCompensation *= -1 end
local angleDir = strumDirection * math.pi / -180;
if note.CopyX then note.Position = UDim2.new(strumX + strumNoteXTimeline + math.cos(angleDir) * (directionCompensation * strumNoteSpeedTimeline), note.Position.X.Offset, note.Position.Y.Scale, note.Position.Y.Offset) end
if note.CopyY then note.Position = UDim2.new(note.Position.X.Scale, note.Position.X.Offset, strumY + strumNoteYTimeline + math.sin(angleDir) * (directionCompensation * strumNoteSpeedTimeline), note.Position.Y.Offset) end
--[[...]]--
end
end
end)
Post writing: after reviewing the code one more time, I think that the __newindex metamethod is not getting called because although I’m changing the value of that key to a different UDim2, I am not changing the UserData for said key, so even though the value is different it still counts as no change. If this is the case then how could I fix this?
Huge thanks viewing my post, I’m looking forward to a solution from anyone, and sorry for the length of this, I just want to leave everything as clear as possible.