Whats The Issues?
I have a bug with the enemy and player characters when they both have the same ability equipped. When the enemy presses ‘E’, the character’s Blood Ball attack targets the owner instead of firing projectiles as intended.
Footage
Code
Module :
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RemoteEvent = ReplicatedStorage.Remotes:WaitForChild("BallPosition")
local rs = game:GetService("RunService")
local ContextActionService = game:GetService("ContextActionService")
local BallFollower = {}
BallFollower.__index = BallFollower
function BallFollower.new(player)
return setmetatable({
Player = player,
projectilesSpawned = false,
Count = 0,
ballActive = false -- Flag to track if the ball is active
}, BallFollower)
end
-- Mechanics
function BallFollower:CreateBall()
local ball = script.Blood:Clone()
ball.Anchored = false
ball.CanCollide = false
ball.Parent = workspace.FX
local attachmentBall = Instance.new("Attachment", ball)
local alignPos = Instance.new("AlignPosition", ball)
alignPos.Attachment0 = attachmentBall
alignPos.ReactionForceEnabled = false
alignPos.MaxForce = 10000
alignPos.Responsiveness = 35
self:TrackCharacter(ball, alignPos)
self.ballActive = true -- Set ball active flag
return ball
end
function BallFollower:StartFollowing()
self.ball = self:CreateBall()
RemoteEvent.OnServerEvent:Connect(function(player, types, mousePos)
if types == "Ability" and not self.projectilesSpawned then -- Check if projectiles have been spawned
local character = player.Character or player.CharacterAdded:Wait()
if not self.ball or not self.ball.Parent then
return
end
self.Count += 1
self.projectilesSpawned = true
local projectile = script.Arrow:Clone()
projectile.CFrame = self.ball.CFrame
projectile.Anchored = true
projectile.Parent = workspace.FX
local nearestEnemy = self:GetNearestEnemy(character)
if nearestEnemy then
local direction = (nearestEnemy.HumanoidRootPart.Position - projectile.Position).Unit
local lookAtCFrame = CFrame.new(projectile.Position, projectile.Position + direction)
projectile.CFrame = lookAtCFrame * CFrame.Angles(math.rad(180), math.rad(-90), 0)
local speed = 130
local timeout = 0.5
local startTime = tick()
self:LoadSound(workspace.FX, 1300216167)
task.spawn(function()
while (projectile.Position - nearestEnemy.HumanoidRootPart.Position).Magnitude >= 1 do
local elapsedTime = tick() - startTime
if elapsedTime > timeout then
break
end
local newPosition = projectile.Position + direction * speed * rs.Heartbeat:Wait()
projectile.Position = newPosition
task.wait()
end
nearestEnemy.Humanoid:TakeDamage(2)
end)
end
game:GetService("Debris"):AddItem(projectile, 1)
self.projectilesSpawned = false -- Reset the flag to allow next projectile to be spawned
if self.Count == 5 then
self:Stop()
end
end
end)
end
-- Properties
function BallFollower:TrackCharacter(ball, alignPosition)
local character = self.Player.Character or self.Player.CharacterAdded:Wait()
local attachmentCharacter = Instance.new("Attachment", character.HumanoidRootPart)
attachmentCharacter.CFrame = CFrame.new(0,0,5)
task.spawn(function()
while ball do
if character then
alignPosition.Attachment1 = attachmentCharacter
end
task.wait(0.01)
end
end)
end
function BallFollower:GetNearestEnemy(Character)
local character = Character
if not character then return end
local nearestDistance = math.huge
local nearestEnemy = nil
for _, enemy in pairs(workspace.Entities:GetChildren()) do
if enemy ~= character then
local distance = (enemy.HumanoidRootPart.Position - self.ball.Position).magnitude
if distance < nearestDistance then
nearestDistance = distance
nearestEnemy = enemy
end
end
end
return nearestEnemy
end
function BallFollower:Stop()
local poof : ParticleEmitter = self.ball.Attachment.Blood
poof:Emit(200)
self.ball.Transparency = 1
self:LoadSound(workspace.FX, 7837535984)
task.wait(0.4)
if self.ball and self.ball.Parent then
self.ball:Destroy()
end
-- Clean up any remaining projectiles
for _, projectile in ipairs(workspace:GetChildren()) do
if projectile.Name == "Arrow" then
projectile:Destroy()
end
end
self.projectilesSpawned = false
self.ballActive = false -- Reset ball active flag
self.Count = 0 -- Reset the count
end
function BallFollower:LoadSound(character, id)
local Sound = Instance.new("Sound", character)
local Chorus = Instance.new("ChorusSoundEffect", Sound)
Sound.SoundId = "rbxassetid://"..tostring(id)
Sound.Volume = 4
Sound:Play()
Sound.Ended:Connect(function()
task.wait(1)
Sound:Destroy()
end)
end
return BallFollower
Another Module Script:
local rp = game:GetService("ReplicatedStorage")
local slicing = require(rp.Modules:WaitForChild("PlayerMouse"))
local Skill2 = {}
Skill2.__index = Skill2
function Skill2.new(plr)
return setmetatable({
Player = plr
}, Skill2)
end
function Skill2:Play()
self:LoadAnimation(self.Player.Character, 17693442204)
self:LoadSound(self.Player.Character, 17693484524)
self:VFX()
end
function Skill2:VFX()
local new = slicing.new(self.Player)
new:StartFollowing()
end
function Skill2:LoadAnimation(character, id)
local Humanoid = character:WaitForChild("Humanoid")
local Animator : Animator = Humanoid:WaitForChild('Animator')
local animation = Instance.new("Animation", character)
animation.AnimationId = "rbxassetid://"..tostring(id)
local at = Animator:LoadAnimation(animation)
at:Play()
game.Debris:AddItem(animation, 2)
end
function Skill2:LoadSound(character, id)
local Humanoid = character:WaitForChild("Humanoid")
local Animator : Animator = Humanoid:WaitForChild('Animator')
local Sound = Instance.new("Sound", character)
local Chorus = Instance.new("ChorusSoundEffect", Sound)
Sound.SoundId = "rbxassetid://"..tostring(id)
Sound.Volume = 2
Sound:Play()
Sound.Ended:Connect(function()
task.wait(1)
Sound:Destroy()
end)
end
return Skill2
Server:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
local Players = game:GetService("Players")
local sendkey = ReplicatedStorage.Remotes:WaitForChild("SendKeys")
local getchar = ReplicatedStorage.Remotes:WaitForChild("GetChar")
local bindFunction = ReplicatedStorage.Remotes:WaitForChild("BindFunction")
local skillsUtils = ReplicatedStorage:WaitForChild("SkillUtils")
local charData = skillsUtils:WaitForChild("CharacterData")
local hotboxCache = {}
local barCache = {}
local function getHotbox(player)
if not hotboxCache[player] then
hotboxCache[player] = player.PlayerGui:WaitForChild("Hotbox")
end
return hotboxCache[player]
end
local function getAwakeningBar(player)
if not barCache[player] then
barCache[player] = player.PlayerGui:WaitForChild("AwakeningBar")
end
return barCache[player]
end
local debounces = {}
Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(character)
character:SetAttribute("Character", "None")
character:SetAttribute("CombatState", "Unused")
character:SetAttribute("Awakening", 0)
character.Parent = workspace.Entities
end)
end)
sendkey.OnServerEvent:Connect(function(player, input)
local character = player.Character or player.CharacterAdded:Wait()
local selected = character:GetAttribute("Character")
if debounces[player] and debounces[player][input] then return end
debounces[player] = debounces[player] or {}
debounces[player][input] = true
local hotbox = getHotbox(player)
for _, child in pairs(charData:GetChildren()) do
if selected == child.Name then
local requireChar = require(child)
for _, abilityData in pairs(requireChar.List) do
if selected and input then
local characterFolder = script:FindFirstChild(selected)
if characterFolder then
local ability = characterFolder:FindFirstChild(input)
if ability and abilityData.Key == input then
local abilityInstance = require(ability).new(player)
local cooldown = hotbox:WaitForChild(input).Cooldown
if cooldown and not cooldown.Visible then
local startSize = cooldown.Size
local endSize = UDim2.new(0, 54, 0, -0)
cooldown.Size = UDim2.new(0, 54, 0, 66)
cooldown.Visible = true
local tweenInfo = TweenInfo.new(abilityData.Cooldown, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut)
local tween = TweenService:Create(cooldown, tweenInfo, { Size = endSize })
tween:Play()
abilityInstance:Play()
tween.Completed:Wait()
local resetTween = TweenService:Create(cooldown, tweenInfo, { Size = startSize })
resetTween:Play()
cooldown.Visible = false
end
end
end
end
end
end
end
debounces[player][input] = nil
end)
getchar.OnServerEvent:Connect(function(player, name)
local hotbox = getHotbox(player)
local bar = getAwakeningBar(player)
local character = player.Character or player.CharacterAdded:Wait()
if not character then
warn("Character not found for player:", player.Name)
return
end
if character.Humanoid.Health == 100 then
local character_Attribute = character:GetAttribute("Character")
character:SetAttribute("Character", name)
local characterFolder = script:FindFirstChild(name)
local availableModules = {}
for _, child in pairs(characterFolder:GetChildren()) do
if child:IsA("ModuleScript") then
table.insert(availableModules, child.Name)
end
end
for _, child in pairs(charData:GetChildren()) do
if child:IsA("ModuleScript") and child.Name == name then
local requireChar = require(child)
for _, abilityData in pairs(requireChar.List) do
local hotboxChar = hotbox:FindFirstChild(abilityData.Key)
hotboxChar.SkillName.Text = abilityData.SkillName
if requireChar.Awakening then
local Charbar = bar:WaitForChild("Awakening")
Charbar.Text = requireChar.Awakening
Charbar.TextLabel.Text = requireChar.Awakening
end
end
end
end
bindFunction:InvokeClient(player, availableModules)
end
end)
Another Module Script is fired on the Server Handler.