I’m trying to create a beam set up in the Roblox Weapon Kit..
WeaponsSystem.Libraries.WeaponTypes
BeamWeapon
-- WeaponsSystem/WeaponTypes/BeamWeapon
local TweenService = game:GetService("TweenService")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local Debris = game:GetService("Debris")
local ContextActionService = game:GetService("ContextActionService")
local CollectionService = game:GetService("CollectionService")
local ContentProvider = game:GetService("ContentProvider")
local IsServer = RunService:IsServer()
local WeaponsSystemFolder = script.Parent.Parent
local Libraries = WeaponsSystemFolder:WaitForChild("Libraries")
local BaseWeapon = require(Libraries:WaitForChild("BaseWeapon"))
local Parabola = require(Libraries:WaitForChild("Parabola"))
local Roblox = require(Libraries:WaitForChild("Roblox"))
local Effects = WeaponsSystemFolder:WaitForChild("Assets"):WaitForChild("Effects")
local ShotsFolder = Effects:WaitForChild("Shots")
local localPlayer = not IsServer and Players.LocalPlayer
local BeamWeapon = {}
BeamWeapon.__index = BeamWeapon
setmetatable(BeamWeapon, BaseWeapon)
BeamWeapon.CanAimDownSights = true
BeamWeapon.CanBeFired = true
BeamWeapon.CanBeReloaded = false
BeamWeapon.CanHit = false
function BeamWeapon.new(weaponsSystem, instance)
local self = BaseWeapon.new(weaponsSystem, instance)
setmetatable(self, BeamWeapon)
self.usesCharging = false
self.charge = 0
self.triggerDisconnected = false
self.nextFireTime = 0
self.recoilIntensity = 0
self.aimPoint = Vector3.new()
self:addOptionalDescendant("tipAttach", "TipAttachment")
self:addOptionalDescendant("muzzleFlash0", "MuzzleFlash0")
self:addOptionalDescendant("muzzleFlash1", "MuzzleFlash1")
self:addOptionalDescendant("muzzleFlashBeam", "MuzzleFlash")
self:doInitialSetup()
return self
end
function BeamWeapon:onEquippedChanged()
BaseWeapon.onEquippedChanged(self)
if not IsServer then
if self.equipped then
ContextActionService:BindAction("ReloadWeapon", function(...) self:onReloadAction(...) end, false, Enum.KeyCode.R, Enum.KeyCode.ButtonX)
else
ContextActionService:UnbindAction("ReloadWeapon")
end
self.triggerDisconnected = false
end
end
function BeamWeapon:onReloadAction(actionName, inputState, inputObj)
end
function BeamWeapon:getRandomSeedForId(id)
return id
end
function BeamWeapon:simulateFire(firingPlayer, fireInfo)
-- print("simulateFire called")
BaseWeapon.simulateFire(self, fireInfo)
if self.lastFireSound then
self.lastFireSound:Stop()
end
self.lastFireSound = self:tryPlaySound("Fired", self:getConfigValue("FiredPlaybackSpeedRange", 0.1))
self:simulateProjectile(firingPlayer, fireInfo, 1, Random.new(self:getRandomSeedForId(fireInfo.id)))
end
function BeamWeapon:simulateProjectile(firingPlayer, fireInfo, projectileIdx, randomGenerator)
if self.tipAttach ~= nil then
local tipCFrame = self.tipAttach.WorldCFrame
local tipPos = tipCFrame.Position
local tipDir = tipCFrame.LookVector
local amountToCheatBack = math.abs((self.instance:FindFirstChild("Handle").Position - tipPos):Dot(tipDir)) + 1
local gunRay = Ray.new(tipPos - tipDir.Unit * amountToCheatBack, tipDir.Unit * amountToCheatBack)
local hitPart, hitPoint = Roblox.penetrateCast(gunRay, self:getIgnoreList(true))
if hitPart and math.abs((tipPos - hitPoint).Magnitude) > 0 then
fireInfo.origin = hitPoint - tipDir.Unit * 0.1
fireInfo.dir = tipDir.Unit
end
end
local origin, dir = fireInfo.origin, fireInfo.dir
local bulletSpeed = self:getConfigValue("BulletSpeed", 5000)
local maxDistance = self:getConfigValue("MaxDistance", 2000)
local beamThickness0 = self:getConfigValue("BeamWidth0", 0.15)
local beamThickness1 = self:getConfigValue("BeamWidth1", 0.15)
local beamFadeTime = self:getConfigValue("BeamFadeTime", 0.5)
local bulletEffect = self.bulletEffectTemplate:Clone()
bulletEffect.CFrame = CFrame.new(origin, origin + dir)
bulletEffect.Parent = workspace.CurrentCamera
CollectionService:AddTag(bulletEffect, "WeaponsSystemIgnore")
local beam0 = bulletEffect:FindFirstChild("Beam0")
if beam0 then beam0.Enabled = true end
local parabola = Parabola.new()
parabola:setPhysicsLaunch(origin, dir * bulletSpeed, nil, 0)
parabola:setNumSamples(1)
local stepConn = nil
local pTravelDistance = 0
local startTime = tick()
local didHit = false
local stoppedMotion = false
local stoppedMotionAt = 0
local fadingOut = false
local steppedCallback = function(dt)
local now = tick()
local timeSinceStart = now - startTime
local travelDist = bulletSpeed * dt
local projFront = pTravelDistance
local maxDist = maxDistance
if not didHit then
local castProjBack, castProjFront = projFront, projFront + travelDist
parabola:setDomain(castProjBack, castProjFront)
local hitPart, hitPoint, hitNormal, hitMaterial, hitT = parabola:findPart(self:getIgnoreList(true))
if hitPart then
didHit = true
projFront = castProjBack + hitT * (castProjFront - castProjBack)
parabola:setDomain(0, projFront)
maxDist = projFront
end
end
if projFront >= maxDist then
if not stoppedMotion then
stoppedMotion = true
stoppedMotionAt = now
end
end
parabola:setDomain(0, math.min(projFront, maxDist))
if projFront < maxDist then
pTravelDistance = math.max(0, timeSinceStart * bulletSpeed)
end
if self.tipAttach and bulletEffect then
bulletEffect.CFrame = self.tipAttach.WorldCFrame
end
if stoppedMotion then
if not self.activated and not fadingOut then
fadingOut = true
stoppedMotionAt = now
end
local thickness0 = beamThickness0
local thickness1 = beamThickness1
if fadingOut then
local fadeAlpha = math.clamp((now - stoppedMotionAt) / beamFadeTime, 0, 1)
thickness0 = thickness0 * (1 - fadeAlpha)
thickness1 = thickness1 * (1 - fadeAlpha)
if fadeAlpha >= 1 then
if bulletEffect then
bulletEffect:Destroy()
bulletEffect = nil
end
stepConn:Disconnect()
return
end
end
if beam0 then
beam0.Width0 = thickness0
beam0.Width1 = thickness1
parabola:renderToBeam(beam0)
end
else
if beam0 then
beam0.Width0 = beamThickness0
beam0.Width1 = beamThickness1
parabola:renderToBeam(beam0)
end
end
end
stepConn = RunService.Heartbeat:Connect(steppedCallback)
end
function BeamWeapon:getIgnoreList(includeLocalPlayer)
local ignoreList = {
self.instanceIsTool and self.instance.Parent or self.instance,
workspace.CurrentCamera
}
if not RunService:IsServer() then
if includeLocalPlayer and Players.LocalPlayer and Players.LocalPlayer.Character then
table.insert(ignoreList, Players.LocalPlayer.Character)
end
end
return ignoreList
end
function BeamWeapon:onConfigValueChanged(valueName, newValue, oldValue)
BaseWeapon.onConfigValueChanged(self, valueName, newValue, oldValue)
if valueName == "ShotEffect" then
self.bulletEffectTemplate = ShotsFolder:FindFirstChild(self:getConfigValue("ShotEffect", "Bullet"))
if self.bulletEffectTemplate then
local config = self.bulletEffectTemplate:FindFirstChildOfClass("Configuration")
if config then
self:importConfiguration(config)
end
local beam0 = self.bulletEffectTemplate:FindFirstChild("Beam0")
if beam0 then
coroutine.wrap(function()
ContentProvider:PreloadAsync({ beam0 })
end)()
end
end
end
end
function BeamWeapon:onActivatedChanged()
BaseWeapon.onActivatedChanged(self)
if not IsServer then
if self.activated and self.player == localPlayer and self:canFire() and tick() > self.nextFireTime then
self:doLocalFire()
end
if not self.activated and self.triggerDisconnected then
self.triggerDisconnected = false
end
end
end
function BeamWeapon:onFired(firingPlayer, fireInfo, fromNetwork)
if not IsServer and firingPlayer == Players.LocalPlayer and fromNetwork then
return
end
self.nextFireTime = tick() + self:getConfigValue("ShotCooldown", 0.1)
BaseWeapon.onFired(self, firingPlayer, fireInfo, fromNetwork)
end
function BeamWeapon:getAmmoInWeapon()
return 1
end
function BeamWeapon:useAmmo(amount)
return amount
end
function BeamWeapon:canFire()
-- print("canFire called", self.player == Players.LocalPlayer, self.activated, not self.triggerDisconnected, not self.reloading)
return self.player == Players.LocalPlayer and self.activated and not self.triggerDisconnected and not self.reloading
end
function BeamWeapon:doLocalFire()
-- print("doLocalFire called", self.tipAttach, self.aimPoint)
if self.tipAttach then
local tipCFrame = self.tipAttach.WorldCFrame
local tipPos = tipCFrame.Position
local aimDir = (self.aimPoint - tipPos).Unit
-- print("firing", tipPos, aimDir)
self:fire(tipPos, aimDir, self.charge)
end
end
function BeamWeapon:onRenderStepped(dt)
BaseWeapon.onRenderStepped(self, dt)
if not self.tipAttach then return end
if not self.equipped then return end
local tipCFrame = self.tipAttach.WorldCFrame
if self.player == Players.LocalPlayer then
local aimTrack = self:getAnimTrack(self:getConfigValue("AimTrack", "RifleAim"))
local aimZoomTrack = self:getAnimTrack(self:getConfigValue("AimZoomTrack", "RifleAimDownSights"))
if aimTrack then
local aimDir = tipCFrame.LookVector
local gunLookRay = Ray.new(tipCFrame.p, aimDir * 500)
local _, gunHitPoint = Roblox.penetrateCast(gunLookRay, self:getIgnoreList(true))
if self.weaponsSystem.aimRayCallback then
local _, hitPoint = Roblox.penetrateCast(self.weaponsSystem.aimRayCallback(), self:getIgnoreList(true))
self.aimPoint = hitPoint
else
self.aimPoint = gunHitPoint
end
if not aimTrack.IsPlaying and not self.reloading then
aimTrack:Play(0.15)
end
if aimZoomTrack and not self.reloading then
if not aimZoomTrack.IsPlaying then
aimZoomTrack:Play(0.15)
end
aimZoomTrack:AdjustSpeed(0.001)
if self.weaponsSystem.camera:isZoomed() then
if aimTrack.WeightTarget ~= 0 then
aimZoomTrack:AdjustWeight(1)
aimTrack:AdjustWeight(0)
end
elseif aimTrack.WeightTarget ~= 1 then
aimZoomTrack:AdjustWeight(0)
aimTrack:AdjustWeight(1)
end
end
local MIN_ANGLE = -80
local MAX_ANGLE = 80
local aimYAngle = math.deg(self.recoilIntensity)
if self.weaponsSystem.camera.enabled then
aimYAngle = math.deg(self.weaponsSystem.camera:getRelativePitch() + self.weaponsSystem.camera.currentRecoil.Y + self.recoilIntensity)
end
local aimTimePos = 2 * ((aimYAngle - MIN_ANGLE) / (MAX_ANGLE - MIN_ANGLE))
aimTrack:AdjustSpeed(0.001)
aimTrack.TimePosition = math.clamp(aimTimePos, 0.001, 1.97)
if aimZoomTrack then
aimZoomTrack.TimePosition = math.clamp(aimTimePos, 0.001, 1.97)
end
end
end
end
function BeamWeapon:onStepped(dt)
if not self.tipAttach then return end
if not self.equipped then return end
BaseWeapon.onStepped(self, dt)
end
return BeamWeapon
This comes out like this.. Beam stops when I left off fire..
I want to make this into a gravity beam or a scanner beam, but it has to stay with the gun, and the beam has to move where I point the gun. Any thoughts here? Just getting to this point was a bear.