I'm trying to make my first Roblox studio game and I ran into this problem:
attempt to call missing method 'UpdateCharacter' of table
attempt to call missing method 'Equip' of table
Any function that is called from FistCombat even if it is declared. I attach the 3 scripts that I believe are the problem.
local RS = game:GetService("ReplicatedStorage")
local UIS = game:GetService("UserInputService")
local Player = game:GetService("Players").LocalPlayer
local Camera = workspace.CurrentCamera
local GUI = Player.PlayerGui:WaitForChild("CombatGui")
local Character = Player.Character or Player.CharacterAdded:Wait()
local Humanoid
local Backpack = Player.Backpack
local CharacterConnections = {
}
--ReplicateRemote
local ReplicateRemote = RS.Remotes.Replicate
--CameraShaker
local function ShakeCamera(ShakeCFrame)
Camera.CFrame = Camera.CFrame * ShakeCFrame
end
local CameraShaker = require(RS.Modules.Auxillary.CameraShaker).new(Enum.RenderPriority.Camera.Value, ShakeCamera)
CameraShaker:Start()
--CooldownManager
local CooldownManager = require(RS.Modules.Auxillary.CooldownManager).new(Player, GUI)
--Status Manager
local StatusManager = Character:WaitForChild("StatusFolder")
local StatusManager = require(RS.Modules.Auxillary.StatusManager).new(Player)
local AuxObjects = {
["CameraShaker"] = CameraShaker,
["CooldownManager"] = CooldownManager,
["StatusManager"] = StatusManager,
}
--Default current weapon to fist
local BaseCombat = require(RS.Modules.Items.FistCombat).new(Player, AuxObjects)
local CurrentItem = BaseCombat
CurrentItem:Equip()
function HandleInputs(UserInput, GPE)
if GPE then return end
--Convert UserInput into a String for ease of use
local InputName = UserInput.KeyCode.Name
if UserInput.UserInputType == Enum.UserInputType.MouseButton1 then
InputName = "M1"
elseif UserInput.UserInputType == Enum.UserInputType.MouseButton2 then
InputName = "M2"
end
--Input Validation
if CurrentItem.Keys[InputName] then
if UserInput.UserInputState == Enum.UserInputState.Begin then
CurrentItem[InputName](CurrentItem)
elseif UserInput.UserInputState == Enum.UserInputState.End then
CurrentItem[InputName.."End"](CurrentItem)
end
end
end
UIS.InputBegan:Connect(HandleInputs)
UIS.InputEnded:Connect(HandleInputs)
-- Super Simple Replicator
local Modules = {}
for i, Item in pairs(RS.Modules.Items:GetChildren()) do
Modules[Item.Name] = require(Item)
end
ReplicateRemote.OnClientEvent:Connect(function(Args)
Modules[Args.Module][Args.Action](Args)
end)
-------------------------------------
--Inventory System
--Connections
local BackpackConnections = {}
local BackpackCoreConnections = {}
function AddItem(Tool)
if Tool:IsA("Tool") and not BackpackConnections[Tool] then
BackpackConnections[Tool] = {}
BackpackConnections[Tool].Module = require(RS.Modules.Items[Tool.Name]).new(Player, AuxObjects)
BackpackConnections[Tool].Equipped = Tool.Equipped:Connect(function()
Currentitem:Unequip()
Currentitem = BackpackConnections[Tool].Module
Currentitem:Equip()
end)
BackpackConnections[Tool].Unequipped = Tool.Unequipped:Connect(function()
if Character:FindFirstChildWhichIsA("Tool") == nil then
Currentitem:Unequip()
Currentitem = BaseCombat
Currentitem:Equip()
end
end)
end
end
for i, OtherPlayer in pairs(game:GetService("Players"):GetPlayers()) do
if OtherPlayer ~= Player then
if OtherPlayer.Character:FindFirstChildWhichIsA("Tool") then
Modules[OtherPlayer.Character:FindFirstChildWhichIsA("Tool").Name].CreateModel({Character = OtherPlayer.Character})
end
end
end
function LoadCharacter(Char)
Character = Char
Humanoid = Char:WaitForChild("Humanoid")
Humanoid:SetStateEnabled(Enum.HumanoidStateType.Ragdoll, false)
Humanoid:SetStateEnabled(Enum.HumanoidStateType.FallingDown, false)
Backpack = Player.Backpack
BackpackCoreConnections.childAdded = Backpack.ChildAdded:Connect(function(Tool)
if Tool:IsA("Tool") then
AddItem(Tool)
end
end)
BackpackCoreConnections.ChildRemoved = Backpack.ChildRemoved:Connect(function(Tool)
if Tool:IsA("Tool") then
if Tool.Parent ~= Character then
BackpackConnections[Tool].Equipped:Disconnect()
BackpackConnections[Tool].Unequipped:Disconnect()
BackpackConnections[Tool].Module:Destroy()
BackpackConnections[Tool] = nil
end
end
end)
for i,Tool in pairs(Backpack:GetChildren()) do
AddItem(Tool)
end
CurrentItem = BaseCombat
CurrentItem:Equip()
CharacterConnections["Died"] = Humanoid.Died:Connect(function()
BackpackCoreConnections.childAdded:Disconnect()
BackpackCoreConnections.ChildRemoved:Disconnect()
--Make sure our Character inst attacking when dead
CurrentItem:Lock()
end)
CurrentItem:UpdateCharacter()
CurrentItem:Unlock()
end
Player.CharacterAdded:Connect(LoadCharacter)
LoadCharacter(Character)
local FistCombat = {}
FistCombat._index = FistCombat
local RF = game:GetService("ReplicatedFirst")
local RS = game:GetService("ReplicatedStorage")
local TS = game:GetService("TweenService")
local ActionService = RS.Remotes.ActionService
local ReplicateRemote = RS.Remotes.Replicate
local Auxillary = require(RS.Modules.Auxillary.Auxillary)
local Assets = RF.Assets.FistCombat
local VFX = Assets.VFX
local Sound = Assets.Sound
local Animations = Assets.Animations
local PunchTextures = {
"rbxassetid://",
"rbxassetid://",
"rbxassetid://",
"rbxassetid://",
"rbxassetid://",
"rbxassetid://",
}
local COMBOLENGTH = 5
local COMBORESETLENGTH = 1
local ITEMNAME = "FistCombat"
function FistCombat.new(User, AuxObjects)
local self = setmetatable({}, FistCombat)
self.User = User
self.Mouse = User:GetMouse()
self.CooldownManager = AuxObjects.CooldownManager
self.CameraShaker = AuxObjects.CameraShaker
self.StatusManager = AuxObjects.StatusManager
self.Character = User.Character
self.Locked = false
self.Equipped = false
self.Status = {
["Combo"] = 1,
["LastCombo"] = 0,
["Blocking"] = false,
["Action"] = false,
}
self.Keys ={
["M1"] = {["Name"] = "Punch", ["LayoutOrder"] = 1 },
["M2"] = {["Name"] = "Heavy", ["LayoutOrder"] = 2 },
["F"] = {["Name"] = "Block", ["LayoutOrder"] = 3 },
}
self.Animations = {
}
self.CooldownManager:AddItem("FistCombat", self.Keys)
return self
end
function FistCombat:Name()
print("FistCombat")
end
function FistCombat:Equip()
--Equip the item and load cooldown ui
self.CooldownManager:LoadItem("FistCombat")
self.Equipped = true
end
function FistCombat:M1()
--CheckCooldown and other requirements
if
not self.CooldownManager:onCooldown(ITEMNAME, "Punch")
and self.Equipped
and not self.Locked
and not self.Status.Blocking
and not self.Status.Action
and not self.StatusManager:GetSatus().Stun
and not self.CooldownManager.InAction
then
self.CooldownManager.SetAction(true)
self.Status.Action = true
if time() - self.Status.LastCombo > COMBORESETLENGTH then
self.Status.LastCombo = 1
end
self.Status.LastCombo = time()
local Cooldown =.3
if self.Status.Combo == 5 then
Cooldown = 1
end
self.CoolDownManager:AddCooldown(ITEMNAME,"Punch", Cooldown)
self.Character.Humanoid.walkSpeed = 4
--Move the Player
local BV = Instance.new("BodyVelocity")
BV.MaxForce = Vector3.new(999999,0,999999)
BV.Velocity = self.Character.HumanoidRootPart.CFrame.LookVector * 25
BV.Parent = self.Character.HumanoidRootPart
task.delay(.1,function()
BV:Destroy()
end)
--Play the animation
local Animation = self.Character.Humanoid.Animator:LoadAnimation(Animations["M"..self.Status.Combo])
Animations:Play()
--Create the effect
local ReplicateArgs = {
Module = "FistCombat",
Action = "PunchEffect",
Character = self.Character,
Combo = self.Status.Combo,
}
FistCombat.PunchEffect(ReplicateArgs)
ReplicateRemote:FireServer(ReplicateArgs)
--Camera Shake
self.CameraShaker:ShakeOnce(2,4,.2,.3)
--Hitboxing
local params = OverlapParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilerDescendantsInstances = {workspace.Map, workspace.FX, self.Character}
local HitList = {}
local HB = workspace.GetPartBundsInBox(self.character:GetPivot() * CFrame.new(0,0,-4), Vector3.new(4,4,6), params)
for i, Part in pairs(HB) do
if Part.Parent:FindFirstChild("Humanoid") and table.find(HitList, Part.Parent) == nil then
table.insert(HitList, Part.Parent)
local Highlght = Instance.new("Highlight", Part.Parent)
Highlght.DepthMode = Enum.HighlightDepthMode.Occluded
Highlght.FillColor = Color3.fromRGB(195,0,0)
Highlght.FillTransparency = 0
Highlght.OutlineTransparency = 1
TS:Create(Highlght, TweenInfo.new(.4),{fillTransparency = 1}):Play()
task.delay(.4, function()
Highlght:Destroy()
end)
local ReplicateArgs = {
Module = "FistCombat",
Action = "HitEffect",
Target = Part.Parent,
Combo = self.Status.Combo,
}
FistCombat.HitEffect(ReplicateArgs)
ReplicateRemote:FireServer(ReplicateArgs)
if self.Status.Combo == 5 then
local ReplicateArgs = {
Module = "FistCombat",
Action = "HeavyhitEffect",
Target = Part.Parent,
Character = self.Character,
}
FistCombat.HeavyHitEffect(ReplicateArgs)
ReplicateRemote:FireServer(ReplicateArgs)
end
end
end
local ServerArgs = {
["Module"] = "FistCombat",
["Action"] = "hit",
["HitList"] = HitList,
["Knockback"] = self.Character.HumanoidRootPart.CFrame.LookVector *25,
["Combo"] = self.Status.Combo,
}
if self.Status.Combo == 5 then
ServerArgs.Knockback *=3
end
ActionService:InvokeServer(ServerArgs)
if self.Status.Combo == COMBOLENGTH then
self.Status.Combo = 0
end
self.Status.Combo +=1
task.wait(.3)
self.Character.humanoid.WalkSpeed = 16
self.Status.action = false
self.CooldownManager:SetAction(false)
end
end
function FistCombat.HitEffect(Args)
local Target = Args.Target
local Attachment = Instance.new("Attachment", Target.HumanoidRootPart)
Attachment.Name = "HitEffect"
if Target:GetAttribute("Blocking") then
if Args.Combo == 5 then
for i, ptc1 in pairs(VFX.BlockBreak:GetChildren()) do
ptc1:Clone().Parent = Attachment
end
else
for i, ptc1 in pairs(VFX.Block:GetChildren()) do
ptc1:Clone().Parent = Attachment
end
end
else
for i, ptc1 in pairs(VFX.Hit:GetChildren()) do
ptc1:Clone().Parent = Attachment
end
end
Auxillary.Emit(Attachment)
task.delay(1,function()
Attachment:Destroy()
end)
end
function FistCombat.HeavyHitEffect(Args)
local Character = Args.Character
local Target = Args.Target
local Direction = Character.HumanoidRootPart.CFrame.LookVector
local HeavyEffect = VFX.heavy:Clone()
HeavyEffect.CFrame = CFrame.new(Target.HumanoidRootpart.Position, Character.HumanoidRootPart.Position) * CFrame.Angles(0,math.rad(180),0)
HeavyEffect.Parent = workspace.FX
Auxillary.Emit(HeavyEffect.Attachment)
task.delay(2,function()
HeavyEffect:Destroy()
end)
task.spawn(function()
local Params = RaycastParams.new()
Params.FilterType = Enum.RaycastFilterType.Include
Params.FilterDescendantsInstances = {workspace.Map}
for i = 1, 15 do
local Result = workspace:Raycast(Target.HumanoidRootpart.Position, Vector3.new(0,-8,0), Params)
if Result then
local Dust = VFX.Dust:Clone()
Dust.CFrame = CFrame.new(Target.HumanoidRootpart.Position, Direction)
Dust.Position = Result.Position
Dust.Dust.Enabled = true
Dust.Parent = workspace.FX
Dust.Dust.Color = ColorSequence.new{ColorSequenceKeypoint.new(0,Auxillary.GetColorFromRay(Result)), ColorSequenceKeypoint.new(1, Auxillary.GetColorFromRay(Result))}
task.delay(.15, function()
Dust.Dust.Enabled = false
task.wait(4)
Dust:Destroy()
end)
end
task.wait(.03)
end
end)
end
function FistCombat.PunchEffect(Args)
local Punch = VFX.Punch:Clone()
local Weld = Auxillary.Weld(Args.Character.HumanoidRootPart, Punch, CFrame.new(), CFrame.new())
local WeldC0 = CFrame.new()
if Args.Combo == 1 then
WeldC0 = CFrame.new(1,.6,-1) * CFrame.Angles(0,0,math.rad(190)) * CFrame.Angles(0,math.rad(100), 0)
elseif Args.Combo == 2 then
WeldC0 = CFrame.new(1,.6,-1) * CFrame.Angles(0,0,math.rad(-10)) * CFrame.Angles(0,math.rad(100), 0)
elseif Args.Combo == 3 then
WeldC0 = CFrame.new(1,.6,-1) * CFrame.Angles(0,0,math.rad(200)) * CFrame.Angles(0,math.rad(100), 0)
elseif Args.Combo == 4 then
WeldC0 = CFrame.new(1,.6,-1) * CFrame.Angles(0,0,math.rad(-15)) * CFrame.Angles(0,math.rad(100), 0)
else
for i, Particle in pairs(Punch.Trail:GetChildren()) do
local ClonedParticle = Particle:Clone()
ClonedParticle.Parent = Punch.Trail
ClonedParticle.EmissionDirection = Enum.NormalId.Right
end
end
Auxillary.Emit(Punch.Trail)
Weld.C0 = WeldC0
Punch.Parent = workspace.FX
task.spawn(function()
for i = 1, 6 do
Punch.Mesh.TextureId = PunchTextures[i]
wait()
end
Punch:Destroy()
end)
TS:Create(Weld, TweenInfo.new(.3, Enum.EasingStyle.Cubic, Enum.EasingDirection.Out, 0, false,0),{C0 = Weld.C0 * CFrame.Angles(0,math.rad(-100),0)}):Play()
end
function FistCombat:M1End()
end
function FistCombat:M2()
if
not self.CooldownManager:OnCooldown(ITEMNAME, "Heavy")
and self.Equipped
and not self.Locked
and not self.Blocking
and not self.Status.Action
and not self.StatusManager:GetStatus().Stun
and not self.CooldownManager.inAction
then
self.Status.Action = true
self.CooldownManager:SetAction(true)
self.CooldownManager:AddCooldown(ITEMNAME,"Heavy", 1.5)
self.Character.Humanoid.WalkSpeed = 4
--Move the Player
local BV = Instance.new("BodyVelociy")
BV.MaxForce = Vector3.new(999999,0,999999)
BV.Velocity = self.Character.humanoidRootPart.CFrame.LookVector * 25
BV.Parent = self.Character.HumanoidRootPart
task.delay(.1, function()
BV:Destroy()
end)
--Play the animation
local Animation = self.Character.Humanoid.Animator:LoadAnimation(Animations["M5"])
Animation:Play()
--Create the Effect
local ReplicateArgs = {
Module = "FistCombat",
Action = "Puncheffect",
Character = self.Character,
Combo = 5,
}
FistCombat.PunchEffect(ReplicateArgs)
ReplicateRemote:FireServer(ReplicateArgs)
--Camera Shake
self.CameraShaker:ShakeOnce(2,4,0.2,0.3)
--Hitboxing
local Params = OverlapParams.new()
Params.FilterType = Enum.RaycastFilterType.Exclude
Params.FilterDescendantsInstances = {workspace.Map, workspace.FX, self.Character}
local HitList = {}
local HB = workspace:GetPartBoundsInBox(self.Character:GetPivot() * CFrame.new(0,0,-4), Vector3.new(4,4,6), Params)
for i, Part in pairs(HB) do
if Part.Parent:FindFirstChild("Humanoid") and table.find(HitList, Part.Parent) == nil then
table.insert(HitList, Part.Parent)
local Highlight = Instance.new("Highlight", Part.Parent)
Highlight.DepthMode = Enum.HighlightDepthMode.Occluded
Highlight.FillColor = Color3.fromRGB(195,0,0)
Highlight.FillTransparency = 1
Highlight.OutlineTransparency = 1
TS:Create(Highlight, TweenInfo.new(.4), {FillTransparency = 1}):Play()
task.delay(.4, function()
Highlight:Destroy()
end)
local ReplicateArgs = {
Module = "FistCombat",
Action = "HitEffect",
Target = Part.Parent,
Combo = 5,
}
FistCombat.HitEffect(ReplicateArgs)
ReplicateRemote:FireServer(ReplicateArgs)
local ReplicateArgs = {
Module = "FistCombat",
Action = "HeavyEffect",
Target = Part.Parent,
Character = self.Character
}
FistCombat.HeavyHitEffect(ReplicateArgs)
ReplicateRemote:FireServer(ReplicateArgs)
end
end
--Fire to Server
local ServerArgs = {
["Module"] = "FistCombat",
["Action"] = "hit",
["HitList"] = HitList,
["Knockback"] = self.Character.HumanoidRootPart.CFrame.LookVector *75,
["Combo"] = 5,
}
ActionService:InvokeServer(ServerArgs)
task.wait(.3)
self.Character.Humanoid.WalkSpeed = 16
self.Status.Action = false
self.CooldownManager:SetAction(false)
end
end
function FistCombat:M2End()
end
function FistCombat:F()
if
not self.Status.Blocking
and not self.Status.Action
and not self.Satusmanager:GetSatus().Stun
and not self.CooldownManager.InAction
then
self.CooldownManager:SetAction(true)
self.Character.humanoid.WalkSpeed = 4
self.Status.Blocking = true
self.Animations.Blocking = self.Character.Humanoid.Animator:LoadAnimation(Animations.Block)
self.Animations.Blocking:Play()
local ServerArgs = {
["Modules"] = "fistCombat",
["Action"] = "Block",
}
ActionService:InvokeServer(ServerArgs)
end
end
function FistCombat:FEnd()
local ServerArgs = {
["Modules"] = "fistCombat",
["Action"] = "Unblock",
}
ActionService:InvokeServer(ServerArgs)
self.Character.humanoid.WalkSpeed = 16
self.Status.Blocking = false
self.Animations.Blocking:Stop()
self.CooldownManager:SetAction(false)
end
function FistCombat:Unequip()
self.Equipped = false
self:FEnd()
end
function FistCombat:Lock()
self.Locked = true
end
function FistCombat:Unlock()
self.Locked = false
end
function FistCombat:UpdateCharacter()
self.Character = self.User.Character
end
function FistCombat:Destryoy()
setmetatable(self, nil)
table.clear(self)
table.freeze(self)
end
return table.freeze(FistCombat)
local CooldownManager = {}
CooldownManager.__index = CooldownManager
local RF = game:GetService("ReplicatedFirst")
local TS = game:GetService("TweenService")
local RS = game:GetService("RunService")
local Assets = RF.Assets.UI.Cooldown
function CooldownManager.new(User, GUI)
local self = setmetatable({}, CooldownManager)
self.GUI = GUI
self.CooldownList = {}
self.CurrentItem = nil
self.InAction = false
return self
end
function CooldownManager:AddCooldown(ItemName, Action, Length)
local Cooldown = self.CooldownList[ItemName][Action]
Cooldown.OnCooldown = true
Cooldown.StartTime = time()
Cooldown.Length = Length
self.GUI.Main.Cooldowns[Action].BackgroundColor3 = Color3.fromRGB(144, 80, 80)
TS:Create(self.GUI.Main.Cooldowns[Action], TweenInfo.new(Length, Enum.EasingStyle.Linear), { BackgroundColor3 = Color3.fromRGB(144, 144, 144) }):Play()
Cooldown.Times += 1
task.spawn(function()
local StartTime = Cooldown.StartTime
Cooldown.Con = RS.RenderStepped:Connect(function()
if time() - StartTime >= Length then
self.GUI.Main.Cooldowns[Action].Time.Text = "0" .. "s" self.GUI.Main.Cooldowns[Action].Time.Text = ""
Cooldown.Con:Disconnect()
-- Update CurrentTimes within the loop
Cooldown.Times = Cooldown.Times - 1
if Cooldown.Times == 0 then
Cooldown.OnCooldown = false
end
else
self.GUI.Main.Cooldowns[Action].Time.Text = "" .. (math.round((Length - (time() - StartTime)) * 10) / 10) .. "s"
end
end)
end)
end
function CooldownManager:AddItem(ItemName, Actions)
self.CooldownList[ItemName] = {}
for i, v in pairs(Actions) do
self.CooldownList[ItemName][v.Name] = {Times = 0, OnCooldown = false, Key = i}
end
end
function CooldownManager:OnCooldown(ItemName, Action)
return self.CooldownList[ItemName][Action].OnCooldown
end
function CooldownManager:LoadItem(ItemName)
if self.CurrentItem ~= nil then
for i, Cooldown in pairs(self.CooldownList[self.CurrentItem]) do
if Cooldown.Con then
Cooldown.Con:Disconnect()
end
end
end
for i, v in pairs(self.GUI.Main.Cooldowns:GetChildren()) do
if v:IsA("GuiBase") then
v:Destroy()
end
end
for i, Cooldown in pairs(self.CooldownList[ItemName]) do
local UI = Assets.CooldownHolder:Clone()
UI.LayoutOrder = Cooldown.LayoutOrder
UI.Key.Text = Cooldown.Key
UI.Time.Text = ""
UI.ActionName.Text = i
UI.Name = i
UI.Parent = self.GUI.Main.Cooldowns
UI.BackgroundColor3 = Color3.fromRGB(144,144,144)
if Cooldown.StartTime then
if time() - Cooldown.StartTime < Cooldown.Length then
self:AddCooldown(ItemName, i, Cooldown.Length - (time() - Cooldown.StartTime))
else
Cooldown.OnCooldown = false
end
end
end
self.CurrentItem = ItemName
end
function CooldownManager:SetAction(InAction)
self.InAction = InAction
end
return CooldownManager
When it came out the first time I tried to comment on the code and I saw that it was not the only one, I checked the references but they are in the right place, I have been going through the code for many hours now, I am blind xD
When working with OOP in lua, there's 3 things to double check are all present and working properly :
-- 1. The base table is defined
local Thing = {}
-- 2. The base table has a self referential __index meta method
Thing.__index = Thing
function Thing.new()
-- 3. A call to setmetatable to link the new object to the base table
return setmetatable({}, Thing)
end
And looking at your code...
FistCombat._index = FistCombat
It looks like you didn't set the __index
metamethod properly. Notice that __index
has two underscores at the front. When you defined it, it looks like you only used one.
So change that line to this :
FistCombat.__index = FistCombat
And see if that helps