Shield parts not positioning as wished

Quick-menu:

  1. The Goals
  2. The Problem
  3. Code
  4. End Note

The Goals

I want to make it so the scripts shown will produce an output, specifically in a way that puts the shields in front of the player. I also want the shields to space themselves appropriately based on the distance, equally if the shields are significant, relative to the radius of the shields.

For example; if the shields are close to the player, it would take around 7-8 shields before they begin spacing themselves equally, as by then the amount of shields basically covers the player’s entire horizontal vulnerabilities.

Another example; if there are only four shields, they have an offset to make sure the shields are covering an equal degree on either side. The shields are also oriented as the player’s rotation.

The Problem

I am not really good at dealing with this range of math, and so far all it’s been doing is orienting incorrectly, and also isn’t spacing like I wished.

I’ve tried various kinds of math arrangements and methods, most of which I can’t remember precisely. There is probably a better way to do this, so if so, I would like some help on understanding better techniques.

Code

“ShieldScript” Script in StarterPlayer.StarterCharacterScripts

local Players = game:GetService("Players")

local sev = Instance.new("RemoteEvent", script.Parent)
sev.Name = "ShieldInteractionBridge"

local shields = {}

local function createShieldInstance()
	local plate = Instance.new("Part", workspace)
	plate.Color = Color3.new(0,1,1)
	plate.Material = Enum.Material.Neon
	plate.Size = Vector3.new(2.1, 5, .2)
	plate.CanCollide = false
	plate.Locked = true
	
	table.insert(shields, plate)
	plate:SetNetworkOwner(Players:GetPlayerFromCharacter(script.Parent))
	sev:FireAllClients("add", plate)
end

local function removeShieldInstance(plate)
	local id = table.find(shields, plate)
	assert(id, "Shield is not part of the Shields table.")
	
	table.remove(shields, id)
	sev:FireAllClients("remove", plate)
end

wait(5)

for n=1,10 do
	createShieldInstance()
end

“ClientShieldMovement” LocalScript in StarterPlayer.StarterCharacterScripts

local plr = game:GetService("Players").LocalPlayer

local TS = game:GetService("TweenService")
local info = TweenInfo.new(.3, Enum.EasingStyle.Cubic, Enum.EasingDirection.Out)

local sev = script.Parent:WaitForChild("ShieldInteractionBridge")

local shields = {}

local config = {
	rotation = 0,
	radius = 15,
	spacing = 1,
	evenSpacing = false
}

local testval = Instance.new("NumberValue", script.Parent)
testval.Name = "radius"
testval.Value = 12
testval.Changed:Connect(function(val)
	config.radius = val
end)


local function onServerInteracting(mode, ...)
	local args = {...}
	if mode == "add" then
		-- 1: Shield
		table.insert(shields, args[1])
	elseif mode == "remove" then
		-- 1: Shield
		table.remove(shields, table.find(shields, args[1]))
	end
end
sev.OnClientEvent:Connect(onServerInteracting)


-- IxGamerXL: This is the part that I need help with
game:GetService("RunService").Heartbeat:Connect(function(dt)
	local space = 1 - (math.deg(math.pi - math.log(config.radius+1, math.pi*2))/180)
	local angleInc = config.spacing * space --(math.pi * 2) / #shields
	local extraInc = #shields% 2 == 0 and angleInc / 2 or 0
	
	local primary = script.Parent.PrimaryPart
	local pcf,po = primary.CFrame,primary.Orientation
	
	for i,plate in ipairs(shields) do
		local radian = math.rad(po.Y) + angleInc * i - math.pi/2 - (angleInc * (#shields/2))
		local ax = math.sin(radian)*config.radius
		local az = math.cos(radian)*config.radius
		TS:Create(plate, info, {
			CFrame = CFrame.new(pcf.Position)
				* CFrame.new(Vector3.new(ax,0,az), Vector3.zero)
				--* CFrame.Angles(0,math.rad(po.Y),0)
		}):Play()
		plate.AssemblyLinearVelocity = Vector3.zero
		plate.AssemblyAngularVelocity = Vector3.zero
	end
end)

There are no other instances that are required for this to work, just make sure this Script and LocalScript are both put in StarterPlayer.StarterCharacterScripts.

End Note

Have a solution you have tested and confirmed to work? Please share the new code to me! Just make sure the code isn’t cryptic or confusing, as I will want to understand the correct operations for later use.

Nevermind, I fixed it shortly afterwards through trial and error. Here are the changes done to the local script. Turns out all I had to do was divide the shield width by the radius of the shield orbit. Then I just added an offset to space things out. There isn’t a way for it to just space out equally yet, but I think I got the hang of things.

local plr = game:GetService("Players").LocalPlayer
local TS = game:GetService("TweenService")

local sev = script.Parent:WaitForChild("ShieldInteractionBridge")

local shields = {}
local config = {
	rotation = 0,
	radius = 7,
	spacing = .5,
	evenSpacing = false
}

local testval = Instance.new("NumberValue", script.Parent)
testval.Name = "radius"
testval.Value = 12
testval.Changed:Connect(function(val)
	config.radius = val
end)


local function onServerInteracting(mode, ...)
	local args = {...}
	if mode == "add" then
		-- 1: Shield
		table.insert(shields, args[1])
	elseif mode == "remove" then
		-- 1: Shield
		table.remove(shields, table.find(shields, args[1]))
	end
end
sev.OnClientEvent:Connect(onServerInteracting)


local function onUpdate(dt)
	local space = 1 - (math.deg(math.pi - math.log(config.radius+1, math.pi*2)) / 180)

	local primary = script.Parent.PrimaryPart
	local pcf,po = primary.CFrame,primary.Orientation

	for i,plate in ipairs(shields) do
		local angleInc = (plate.Size.X/config.radius) + (config.spacing/config.radius)
		local extraInc = #shields%2 == 0 and angleInc / 2 or angleInc / 2
		
		local radian = (
			math.rad(po.Y) + angleInc
				* i - (
					angleInc * (#shields/2)
				)
			) + math.pi - extraInc
		
		local ax = math.sin(radian)*config.radius
		local az = math.cos(radian)*config.radius
		
		local alpha = TS:GetValue(
			math.clamp(dt*4, 0,1),
			Enum.EasingStyle.Cubic,
			Enum.EasingDirection.Out
		)
		
		local target = CFrame.new(pcf.Position) * CFrame.new(Vector3.new(ax,0,az), Vector3.zero)
		plate.CFrame = plate.CFrame:Lerp(target, alpha)
		
		local prm = RaycastParams.new()
		prm.FilterType = Enum.RaycastFilterType.Exclude
		prm.FilterDescendantsInstances = shields
		prm.RespectCanCollide = true
		
		local rc = workspace:Raycast(plate.Position, Vector3.new(0,-plate.Size.Y,0), prm)
		if rc and rc.Distance <= plate.Size.Y/1.8 then
			plate.Position = plate.Position:Lerp(
				rc.Position + Vector3.new(0,plate.Size.Y/1.8,0),
				alpha
			)
		end
		
		
		plate.AssemblyLinearVelocity = Vector3.zero
		plate.AssemblyAngularVelocity = Vector3.zero
	end
end
game:GetService("RunService").Heartbeat:Connect(onUpdate)

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.