WoolHatJoin Date: 2013-05-19 Post Count: 1873 |
I'm trying to make a custom Humanoid class. If you're going to tell me that classes/metatables are useless, that's nice; I'd still like to test this out for myself.
Things in this setup work fine, with the exception being: When I call the method :GetChildren(), which then indexes ModuleScript object's table of properties, I get the error saying that ":" was not used, but "." was. I'd like to find out why this error is appearing, and if there's a way to fix it.
local Humanoid = {}
local HumanoidData = {
Name = "Humanoid",
CameraOffset = Vector3.new(0,0,0),
Health = 100,
MaxHealth = 100,
JumpPower = 50,
WalkSpeed = 16,
Jump = false,
TakeDamage = function(self,Damage)
self.Health = self.Health - Damage
end
}
do
local CustomProperties = setmetatable(HumanoidData, {__index=script}) --If property isn't in HumanoidData, look through ModuleScript
Humanoid = setmetatable({},{__index=CustomProperties}) --If property isn't in {}, look through CustomProperties
end
print(Humanoid.Archivable)--Prints the ModuleScript's True archivable value
Humanoid:TakeDamage(5)--Successfully decrements the health by 5
Humanoid:GetChildren()--"Expected ':' not '.' calling member function GetChildren"
return Humanoid |
|
cntkillmeJoin Date: 2008-04-07 Post Count: 49450 |
The problem is your fake humanoid object is being propogated as the “self” to the real GetChildren method.
So it ends up doing script.GetChildren(fakeHumamoid) and since it isn’t an actual instance Roblox just spits out that error since self isn’t an instance.
To solve this you’d have to do something like
__index = function(self, key)
local value = CustomProperties[key]
if type(value) == “function” then
return function(_, ..,)
return value(realHumanoid, ...)
end
end
end
You should probably have it fallback to the real humanoid instead of script but oh well. |
|
WoolHatJoin Date: 2013-05-19 Post Count: 1873 |
I edited it to follow your recommended code, but it still yields the same error. Question before I paste the new code: How would it be able to search the the script object before searching through the table of properties? setmetatable takes only table arguments, as opposed to objects.
Updated code:
local Humanoid = {}
local HumanoidData = {
Name = "Humanoid",
Health = 100,
MaxHealth = 100,
JumpPower = 50,
WalkSpeed = 16,
Jump = false,
TakeDamage = function(self,Damage)
self.Health = self.Health - Damage
end
}
do
local ModuleProperties = setmetatable({ },{__index = script})
Humanoid = setmetatable(HumanoidData,{
__index = function(self, key)
local ModuleProperty = ModuleProperties[key]
if type(ModuleProperty) == "function" then
return function(_,...)
return ModuleProperty(HumanoidData,...)
end
end
end
})
end
print(Humanoid.Archivable)--Prints the ModuleScript's True archivable value
Humanoid:TakeDamage(5)--Successfully decrements the health by 5
Humanoid:GetChildren()--"Expected ':' not '.' calling member function GetChildren"
return Humanoid |
|
cntkillmeJoin Date: 2008-04-07 Post Count: 49450 |
No you implemented it wrong, you're still passing a FAKE OBJECT to a REAL ROBLOX METHOD.
Read what I put.
If you want to index script first, create an object to force __index to fire then just index the script first (with pcall in the case the member doesn't exist). |
|
WoolHatJoin Date: 2013-05-19 Post Count: 1873 |
Did it! Here's my resulting code, for anyone who may take use of it later on. If there are any recommendations/issues you find, I'd like to know so I can try to fix them.
local Humanoid = {}
local HumanoidData = {
Name = "Humanoid",
Health = 100,
MaxHealth = 100,
JumpPower = 50,
WalkSpeed = 16,
Jump = false,
TakeDamage = function(self,Damage)
self.Health = self.Health - Damage
end
}
do
setmetatable(HumanoidData,{ --Checks for properties in the fake humanoid
__index = function(self,key)--Function only runs after HumanoidData turns out to not have any results
error(key.." is not a valid member of Humanoid")
end
})
Humanoid = setmetatable({},{
__index = function(self, key)
local ModulePropertyFound,ModuleProperty = pcall(function()
return script[key]
end)
if ModulePropertyFound or ModulePropertyFound then
if type(ModuleProperty) == "function" then --Check for methods of the fake humanoid
return function(_,...)
return ModuleProperty(script,...) --pass arguments appropriately
end
else
return ModuleProperty
end
else
local HumanoidProperty = HumanoidData[key]
return HumanoidProperty
end
end
})
end
print(Humanoid.Parent)--Prints the ModuleScript's True archivable value
print(Humanoid.Health)
Humanoid:TakeDamage(5)--Successfully decrements the health by 5
print(Humanoid.Health)
print(unpack(Humanoid:GetChildren()))--Prints all children of the modulescript/fake humanoid
print(Humanoid.Jump)
print(Humanoid.yy)
return Humanoid |
|
Dollar500Join Date: 2013-01-12 Post Count: 504 |
So, what exactly is this for? Humanoids are already part of roblox... |
|
WoolHatJoin Date: 2013-05-19 Post Count: 1873 |
Well, the Humanoids are conflicting with me for a certain project I'm working on. So I'm creating my own humanoid, with its own properties.
All this code is in a ModuleScript called "Humanoid", which would go in a character model in place of a regular Humanoid. When the module is required, it returns a table that acts as a Humanoid, with all of the properties that I want it to have.
In the code I put above, the humanoid has explicit properties of Humanoid.Health, Humanoid.Jump. But I can also use function default to the ModuleScript, like Humanoid:GetChildren().
Tl;dr when I need to rewrite every new Humanoid function, I'll give up |
|
Dollar500Join Date: 2013-01-12 Post Count: 504 |
Makes sense |
|
gskwJoin Date: 2013-01-05 Post Count: 1364 |
You should totally use the BaseLib/LiteLib from a project of Crescent Code whose name can't be posted on Roblox (Norse god). It will help you do this. |
|