Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- ProjectileSystem Module
- -------------------------
- This module implements a projectile system.
- Instead of using built-in physics components (like BodyVelocity) for flight,
- we simulate projectile motion using Euler integration and raycasting.
- When a projectile hits a target (a character with a Humanoid), the target is pushed back
- in the direction of the projectile's travel (preserving the impact angle),
- and the target is temporarily highlighted in red to indicate a hit before reverting to its original colors.
- Additional features include homing projectiles, trail effects, explosion effects, and more.
- --]]
- -- Create a table to hold all projectile-related functions and data.
- local ProjectileSystem = {}
- ProjectileSystem.__index = ProjectileSystem
- -- Get required Roblox services.
- local Players = game:GetService("Players") -- Manages players.
- local Debris = game:GetService("Debris") -- Automatically removes objects after a set time.
- local RunService = game:GetService("RunService") -- Provides per-frame update events.
- local Workspace = game:GetService("Workspace") -- The game world.
- -- Define the gravity vector (pointing down).
- local GRAVITY_VECTOR = Vector3.new(0, -Workspace.Gravity, 0)
- -- Table to hold all active projectile objects.
- local activeProjectiles = {}
- --------------------------------------------------------------------------------
- -- Function: CreateProjectilePart
- -- Purpose: Creates and returns a new visual part representing the projectile.
- -- Parameter:
- -- origin (Vector3) - The starting position for the projectile.
- --------------------------------------------------------------------------------
- function ProjectileSystem.CreateProjectilePart(origin)
- -- Create a new Part instance.
- local part = Instance.new("Part")
- -- Set a small size (0.5 studs cube).
- part.Size = Vector3.new(0.5, 0.5, 0.5)
- -- Use a red color for the projectile.
- part.Color = Color3.new(1, 0, 0)
- -- Set material to Neon for a glowing appearance.
- part.Material = Enum.Material.Neon
- -- Make the part spherical.
- part.Shape = Enum.PartType.Ball
- -- Position the part at the provided origin.
- part.CFrame = CFrame.new(origin)
- -- Allow physics to move the part.
- part.Anchored = false
- -- Disable collisions to avoid interfering with other objects.
- part.CanCollide = false
- -- Parent the part to the Workspace so it appears in the game.
- part.Parent = Workspace
- -- Name the part "Projectile" for easy identification.
- part.Name = "Projectile"
- return part
- end
- --------------------------------------------------------------------------------
- -- Function: ApplyHitEffect
- -- Purpose: When a projectile hits a damageable target, this function applies a knockback
- -- effect and temporarily changes the target's color to red.
- -- Parameters:
- -- character (Model) - The target character model.
- -- hitPosition (Vector3) - The position where the projectile hit.
- -- proj (table) - The projectile object (used to determine impact direction).
- --------------------------------------------------------------------------------
- function ProjectileSystem.ApplyHitEffect(character, hitPosition, proj)
- -- Attempt to find the target's HumanoidRootPart.
- local hrp = character:FindFirstChild("HumanoidRootPart")
- if hrp then
- -- Calculate the push direction as the exact opposite of the projectile's velocity.
- -- This ensures that if the projectile hits at a 45° angle, the target is pushed back along that same angle.
- local pushDir = (proj.Velocity).Unit
- -- Create a BodyVelocity to apply the knockback force.
- local bv = Instance.new("BodyVelocity")
- -- Multiply the push direction by a constant for a weighty push effect.
- bv.Velocity = pushDir * 10
- -- Set MaxForce high in all directions to ensure the force is applied properly (including vertical).
- bv.MaxForce = Vector3.new(1e5, 1e5, 1e5)
- -- Parent the BodyVelocity to the target's HumanoidRootPart.
- bv.Parent = hrp
- -- Remove the BodyVelocity after 0.5 seconds to allow natural physics to resume.
- Debris:AddItem(bv, 0.5)
- end
- -- Create a table to store original colors for all BaseParts in the character.
- local originalColors = {}
- -- Iterate over all descendants of the character.
- for _, part in pairs(character:GetDescendants()) do
- -- Check if the object is a BasePart (i.e., an actual physical part).
- if part:IsA("BasePart") then
- -- Store the original color.
- originalColors[part] = part.Color
- -- Set the part's color to bright red to indicate the hit.
- part.Color = Color3.new(1, 0, 0)
- end
- end
- -- After 1 second, revert all parts back to their original colors.
- delay(1, function()
- for part, origColor in pairs(originalColors) do
- -- Ensure the part still exists before reverting its color.
- if part and part.Parent then
- part.Color = origColor
- end
- end
- end)
- end
- --------------------------------------------------------------------------------
- -- Function: FireProjectile
- -- Purpose: Fires a projectile with the given parameters and adds it to the active list.
- -- Parameters:
- -- origin (Vector3) - The starting position of the projectile.
- -- direction (Vector3) - The firing direction (should be a unit vector).
- -- speed (number) - The initial speed in studs per second.
- -- damage (number) - The damage to apply upon impact.
- -- lifetime (number) - Time in seconds before the projectile expires.
- -- shooter (Player) - The player who fired the projectile (to prevent self-damage).
- --------------------------------------------------------------------------------
- function ProjectileSystem.FireProjectile(origin, direction, speed, damage, lifetime, shooter)
- -- Create a new projectile object represented as a table.
- local proj = {}
- -- Set the starting logical position.
- proj.Position = origin
- -- Compute the initial velocity based on the normalized direction and the given speed.
- proj.Velocity = direction.Unit * (speed or 100)
- -- Set the damage value (default is 10).
- proj.Damage = damage or 10
- -- Set the projectile's lifetime (default is 5 seconds).
- proj.Lifetime = lifetime or 5
- -- Record the time the projectile was fired.
- proj.StartTime = tick()
- -- Store the shooter to avoid self-damage.
- proj.Shooter = shooter
- -- Create the visual projectile part at the origin.
- proj.Part = ProjectileSystem.CreateProjectilePart(origin)
- -- Initialize the curve factor for curved trajectories to 0 by default.
- proj.CurveFactor = 0
- -- Set the bounce count to zero.
- proj.BounceCount = 0
- -- Allow up to 2 bounces before the projectile is destroyed.
- proj.MaxBounces = 2
- -- Define the OnHit function to handle collision events.
- proj.OnHit = function(self, hit, hitPosition)
- -- Get the parent of the hit object (typically a character model).
- local character = hit.Parent
- if character then
- -- Check for a Humanoid to determine if the target is damageable.
- local humanoid = character:FindFirstChildOfClass("Humanoid")
- if humanoid then
- -- If the target is the shooter, do not apply damage.
- if self.Shooter and character == self.Shooter.Character then
- -- Skip self-damage.
- else
- -- Apply the specified damage to the target.
- humanoid:TakeDamage(self.Damage)
- -- Apply the custom hit effect (knockback and red highlight).
- ProjectileSystem.ApplyHitEffect(character, hitPosition, self)
- -- Return true to indicate that a damageable target was hit.
- return true
- end
- end
- end
- -- Return false if the target is not damageable.
- return false
- end
- -- Add this projectile to the active projectile list.
- activeProjectiles[#activeProjectiles + 1] = proj
- return proj
- end
- --------------------------------------------------------------------------------
- -- Function: DestroyProjectile
- -- Purpose: Removes a projectile from the game and cleans up its references.
- -- Parameter:
- -- proj (table) - The projectile object to be destroyed.
- --------------------------------------------------------------------------------
- function ProjectileSystem.DestroyProjectile(proj)
- -- If the visual part exists, destroy it.
- if proj.Part then
- proj.Part:Destroy()
- end
- -- Iterate through the active projectile list in reverse order for safe removal.
- for i = #activeProjectiles, 1, -1 do
- if activeProjectiles[i] == proj then
- table.remove(activeProjectiles, i)
- break
- end
- end
- end
- --------------------------------------------------------------------------------
- -- Update Loop: Called every frame to update active projectiles.
- -- This loop uses Euler integration to update positions, applies gravity and curve forces,
- -- performs raycasts for collision detection, applies bounce logic, and updates projectile appearance.
- -- Projectiles that exceed their lifetime are removed.
- --------------------------------------------------------------------------------
- RunService.Heartbeat:Connect(function(deltaTime)
- for i = #activeProjectiles, 1, -1 do
- local proj = activeProjectiles[i]
- local timeElapsed = tick() - proj.StartTime
- if timeElapsed >= proj.Lifetime then
- ProjectileSystem.DestroyProjectile(proj)
- else
- local oldPos = proj.Position
- -- Calculate new position: newPos = oldPos + velocity * deltaTime + 0.5 * gravity * (deltaTime^2)
- local newPos = oldPos + proj.Velocity * deltaTime + 0.5 * GRAVITY_VECTOR * (deltaTime^2)
- -- Update velocity by adding gravity's effect.
- proj.Velocity = proj.Velocity + GRAVITY_VECTOR * deltaTime
- -- If a curve factor is set, add a lateral force to curve the trajectory.
- if proj.CurveFactor ~= 0 then
- local lateralForce = Vector3.new(-proj.Velocity.Z, 0, proj.Velocity.X).Unit * proj.CurveFactor * deltaTime
- proj.Velocity = proj.Velocity + lateralForce
- end
- -- Determine movement direction for raycasting.
- local rayDir = newPos - oldPos
- -- Set up raycast parameters to ignore the shooter and the projectile itself.
- local rayParams = RaycastParams.new()
- rayParams.FilterType = Enum.RaycastFilterType.Exclude
- local filters = {}
- if proj.Shooter and proj.Shooter.Character then
- table.insert(filters, proj.Shooter.Character)
- end
- table.insert(filters, proj.Part)
- rayParams.FilterDescendantsInstances = filters
- -- Perform the raycast from oldPos in the direction of rayDir.
- local rayResult = Workspace:Raycast(oldPos, rayDir, rayParams)
- if rayResult then
- -- Collision detected: update position to the hit location.
- proj.Position = rayResult.Position
- proj.Part.CFrame = CFrame.new(rayResult.Position)
- -- Call OnHit; if a damageable target was hit, destroy the projectile immediately.
- local hitDamageable = proj:OnHit(rayResult.Instance, rayResult.Position)
- if hitDamageable then
- ProjectileSystem.DestroyProjectile(proj)
- elseif proj.BounceCount < proj.MaxBounces then
- -- Otherwise, if bounces remain, increment the bounce count.
- proj.BounceCount = proj.BounceCount + 1
- -- Get the surface normal from the raycast result.
- local normal = rayResult.Normal
- -- Reflect the velocity using the standard reflection formula.
- local reflectedVel = proj.Velocity - 2 * proj.Velocity:Dot(normal) * normal
- -- Apply a bounce factor (reducing speed on bounce).
- local newVel = reflectedVel * 0.8
- -- Clamp new velocity to prevent unnatural gains (especially on vertical surfaces).
- if newVel.Magnitude > proj.Velocity.Magnitude then
- newVel = newVel.Unit * proj.Velocity.Magnitude
- end
- proj.Velocity = newVel
- -- Offset the position slightly away from the surface.
- proj.Position = rayResult.Position + normal * 0.5
- else
- -- If maximum bounces have been reached, destroy the projectile.
- ProjectileSystem.DestroyProjectile(proj)
- end
- else
- -- No collision: update the projectile's position normally.
- proj.Position = newPos
- proj.Part.CFrame = CFrame.new(newPos)
- end
- -- Update the projectile's appearance (e.g., shrink as it travels).
- ProjectileSystem.UpdateProjectileAppearance(proj)
- end
- end
- end)
- --------------------------------------------------------------------------------
- -- Function: CalculateImpactPoint
- -- Purpose: Computes the theoretical impact point using a simple ballistic formula.
- -- Parameters:
- -- origin (Vector3) - Starting position.
- -- direction (Vector3) - Firing direction (unit vector).
- -- speed (number) - Initial speed.
- -- gravity (number) - (Optional) Gravity value; defaults to Workspace.Gravity.
- -- Returns:
- -- A Vector3 representing the predicted impact point.
- --------------------------------------------------------------------------------
- function ProjectileSystem.CalculateImpactPoint(origin, direction, speed, gravity)
- gravity = gravity or Workspace.Gravity
- local t = (2 * speed * direction.Y) / gravity
- local horizontalVelocity = Vector3.new(direction.X, 0, direction.Z) * speed
- local horizontalDistance = horizontalVelocity * t
- return origin + horizontalDistance
- end
- --------------------------------------------------------------------------------
- -- Function: FireCurvedProjectile
- -- Purpose: Fires a projectile with a curved trajectory by setting a constant curve factor.
- -- Parameters: Same as FireProjectile, with an extra curveFactor parameter.
- --------------------------------------------------------------------------------
- function ProjectileSystem.FireCurvedProjectile(origin, direction, speed, damage, curveFactor, lifetime, shooter)
- local proj = ProjectileSystem.FireProjectile(origin, direction, speed, damage, lifetime, shooter)
- proj.CurveFactor = curveFactor or 5
- return proj
- end
- --------------------------------------------------------------------------------
- -- Function: SetProjectileColor
- -- Purpose: Changes the color of the projectile's visual part.
- -- Parameters:
- -- proj (table) - The projectile object.
- -- color (Color3) - The desired color.
- --------------------------------------------------------------------------------
- function ProjectileSystem.SetProjectileColor(proj, color)
- if proj and proj.Part then
- proj.Part.Color = color
- end
- end
- --------------------------------------------------------------------------------
- -- Function: FadeProjectile
- -- Purpose: Gradually fades the projectile out over a given duration.
- -- Parameters:
- -- proj (table) - The projectile object.
- -- fadeDuration (number) - Duration of the fade (defaults to projectile's lifetime).
- --------------------------------------------------------------------------------
- function ProjectileSystem.FadeProjectile(proj, fadeDuration)
- fadeDuration = fadeDuration or proj.Lifetime
- local startTime = tick()
- local connection
- connection = RunService.Heartbeat:Connect(function()
- local elapsed = tick() - startTime
- if proj and proj.Part and proj.Part.Parent then
- proj.Part.Transparency = math.clamp(elapsed / fadeDuration, 0, 1)
- if elapsed >= fadeDuration then
- connection:Disconnect()
- end
- else
- connection:Disconnect()
- end
- end)
- end
- --------------------------------------------------------------------------------
- -- Function: UpdateProjectileAppearance
- -- Purpose: Updates the projectile's visual appearance based on distance traveled.
- -- For example, it gradually shrinks the projectile.
- -- Parameter:
- -- proj (table) - The projectile object.
- --------------------------------------------------------------------------------
- function ProjectileSystem.UpdateProjectileAppearance(proj)
- if proj and proj.Part then
- local distance = (proj.Position - proj.Part.Position).Magnitude
- local newSize = Vector3.new(0.5, 0.5, 0.5) * math.clamp(1 - distance / 100, 0.5, 1)
- proj.Part.Size = newSize
- end
- end
- --------------------------------------------------------------------------------
- -- Function: ResetProjectile
- -- Purpose: Resets a projectile's state to its initial values.
- -- Parameter:
- -- proj (table) - The projectile object.
- --------------------------------------------------------------------------------
- function ProjectileSystem.ResetProjectile(proj)
- if proj and proj.Part then
- proj.Position = proj.Origin or proj.Position
- proj.Velocity = Vector3.new(0, 0, 0)
- proj.StartTime = tick()
- proj.Part.CFrame = CFrame.new(proj.Position)
- end
- end
- --------------------------------------------------------------------------------
- -- Function: BounceProjectile
- -- Purpose: Simulates a bounce by reflecting the projectile's velocity.
- -- Parameters:
- -- proj (table) - The projectile object.
- -- bounceFactor (number) - Multiplier for the reflected velocity (default 0.8).
- --------------------------------------------------------------------------------
- function ProjectileSystem.BounceProjectile(proj, bounceFactor)
- bounceFactor = bounceFactor or 0.8
- if proj and proj.Part then
- local normal = Vector3.new(0, 1, 0)
- proj.Velocity = (proj.Velocity - 2 * proj.Velocity:Dot(normal) * normal) * bounceFactor
- end
- end
- --------------------------------------------------------------------------------
- -- Function: ExtendLifetime
- -- Purpose: Increases the lifetime of a projectile.
- -- Parameters:
- -- proj (table) - The projectile object.
- -- extraTime (number)- Additional seconds to add.
- --------------------------------------------------------------------------------
- function ProjectileSystem.ExtendLifetime(proj, extraTime)
- if proj then
- proj.Lifetime = proj.Lifetime + extraTime
- end
- end
- --------------------------------------------------------------------------------
- -- Function: SlowProjectile
- -- Purpose: Reduces the projectile's speed by applying a slow factor.
- -- Parameters:
- -- proj (table) - The projectile object.
- -- slowFactor (number)- Factor to multiply the velocity (default 0.5).
- --------------------------------------------------------------------------------
- function ProjectileSystem.SlowProjectile(proj, slowFactor)
- slowFactor = slowFactor or 0.5
- if proj then
- proj.Velocity = proj.Velocity * slowFactor
- end
- end
- --------------------------------------------------------------------------------
- -- Function: ApplyAirResistance
- -- Purpose: Simulates drag by gradually reducing the projectile's velocity.
- -- Parameters:
- -- proj (table) - The projectile object.
- -- resistanceFactor (number)- Factor to multiply the velocity (default 0.99).
- --------------------------------------------------------------------------------
- function ProjectileSystem.ApplyAirResistance(proj, resistanceFactor)
- resistanceFactor = resistanceFactor or 0.99
- if proj then
- proj.Velocity = proj.Velocity * resistanceFactor
- end
- end
- --------------------------------------------------------------------------------
- -- Function: DistanceTravelled
- -- Purpose: Calculates the distance the projectile has traveled.
- -- Parameter:
- -- proj (table) - The projectile object.
- -- Returns:
- -- A number representing the travel distance.
- --------------------------------------------------------------------------------
- function ProjectileSystem.DistanceTravelled(proj)
- if proj and proj.Part then
- return (proj.Part.Position - proj.Position).Magnitude
- end
- return 0
- end
- --------------------------------------------------------------------------------
- -- Function: GetProjectileTrajectory
- -- Purpose: Computes a predicted path for the projectile using Euler integration.
- -- Parameters:
- -- proj (table) - The projectile object.
- -- steps (number) - Number of simulation steps (default 20).
- -- deltaTime (number) - Time interval per step (default 0.1 seconds).
- -- Returns:
- -- A table of Vector3 positions along the predicted trajectory.
- --------------------------------------------------------------------------------
- function ProjectileSystem.GetProjectileTrajectory(proj, steps, deltaTime)
- steps = steps or 20
- deltaTime = deltaTime or 0.1
- local trajectory = {}
- local pos = proj.Position
- local vel = proj.Velocity
- for i = 1, steps do
- pos = pos + vel * deltaTime + 0.5 * GRAVITY_VECTOR * (deltaTime^2)
- vel = vel + GRAVITY_VECTOR * deltaTime
- table.insert(trajectory, pos)
- end
- return trajectory
- end
- --------------------------------------------------------------------------------
- -- Function: PrintProjectileInfo
- -- Purpose: Outputs detailed debug info for a projectile to the output console.
- -- Parameter:
- -- proj (table) - The projectile object.
- --------------------------------------------------------------------------------
- function ProjectileSystem.PrintProjectileInfo(proj)
- if proj and proj.Part then
- print("Projectile Info:")
- print(" Position: ", proj.Position)
- print(" Velocity: ", proj.Velocity)
- print(" Damage: ", proj.Damage)
- print(" Time Elapsed: ", tick() - proj.StartTime)
- print(" Bounce Count: ", proj.BounceCount)
- end
- end
- --------------------------------------------------------------------------------
- -- Function: DebugProjectiles
- -- Purpose: Prints debug info for all active projectiles.
- --------------------------------------------------------------------------------
- function ProjectileSystem.DebugProjectiles()
- print("Active Projectiles: " .. #activeProjectiles)
- for i, proj in ipairs(activeProjectiles) do
- ProjectileSystem.PrintProjectileInfo(proj)
- end
- end
- --------------------------------------------------------------------------------
- -- Function: GetActiveProjectiles
- -- Purpose: Returns the list of all active projectiles.
- -- Returns:
- -- The activeProjectiles table.
- --------------------------------------------------------------------------------
- function ProjectileSystem.GetActiveProjectiles()
- return activeProjectiles
- end
- --------------------------------------------------------------------------------
- -- Function: ClearAllProjectiles
- -- Purpose: Destroys all active projectiles and clears the active list.
- --------------------------------------------------------------------------------
- function ProjectileSystem.ClearAllProjectiles()
- for i = #activeProjectiles, 1, -1 do
- ProjectileSystem.DestroyProjectile(activeProjectiles[i])
- end
- end
- --------------------------------------------------------------------------------
- -- Function: DrawTrajectory
- -- Purpose: Creates visual markers along the predicted projectile path for debugging.
- -- Parameters:
- -- proj (table) - The projectile object.
- -- steps (number) - Number of points to compute (default 20).
- -- deltaTime (number) - Time interval per step (default 0.1 seconds).
- --------------------------------------------------------------------------------
- function ProjectileSystem.DrawTrajectory(proj, steps, deltaTime)
- local trajectory = ProjectileSystem.GetProjectileTrajectory(proj, steps, deltaTime)
- for i, pos in ipairs(trajectory) do
- local marker = Instance.new("Part")
- marker.Size = Vector3.new(0.2, 0.2, 0.2)
- marker.Shape = Enum.PartType.Ball
- marker.CFrame = CFrame.new(pos)
- marker.Anchored = true
- marker.CanCollide = false
- marker.Transparency = 0.5
- marker.Parent = Workspace
- Debris:AddItem(marker, 3)
- end
- end
- --------------------------------------------------------------------------------
- -- Additional Complex Methods for the Projectile System
- --------------------------------------------------------------------------------
- --------------------------------------------------------------------------------
- -- Function: HomingProjectile
- -- Purpose: Fires a projectile that homes in on a target by adjusting its velocity over time.
- -- Parameters:
- -- origin (Vector3) - Starting position.
- -- direction (Vector3) - Initial firing direction (unit vector).
- -- speed (number) - Initial speed.
- -- damage (number) - Damage to apply upon impact.
- -- lifetime (number) - Projectile lifetime.
- -- shooter (Player) - The player who fired the projectile.
- -- target (Model) - The target character model.
- --------------------------------------------------------------------------------
- function ProjectileSystem.HomingProjectile(origin, direction, speed, damage, lifetime, shooter, target)
- local proj = ProjectileSystem.FireProjectile(origin, direction, speed, damage, lifetime, shooter)
- local homingFactor = 5
- local connection
- connection = RunService.Heartbeat:Connect(function(deltaTime)
- if not proj.Part or not proj.Part.Parent then
- connection:Disconnect()
- return
- end
- if target and target.Character and target.Character:FindFirstChild("HumanoidRootPart") then
- local targetPos = target.Character.HumanoidRootPart.Position
- local desiredDir = (targetPos - proj.Position).Unit
- proj.Velocity = proj.Velocity:Lerp(desiredDir * proj.Velocity.Magnitude, homingFactor * deltaTime)
- else
- connection:Disconnect()
- end
- end)
- return proj
- end
- --------------------------------------------------------------------------------
- -- Function: SetTrailEffect
- -- Purpose: Attaches a particle trail to the projectile.
- -- Parameters:
- -- proj (table) - The projectile object.
- -- color (Color3) - The trail color (default white).
- -- lifetime (number)- Particle lifetime (default 1 second).
- --------------------------------------------------------------------------------
- function ProjectileSystem.SetTrailEffect(proj, color, lifetime)
- if proj and proj.Part then
- local emitter = Instance.new("ParticleEmitter")
- emitter.Color = ColorSequence.new(color or Color3.new(1,1,1))
- emitter.Lifetime = NumberRange.new(lifetime or 1)
- emitter.Rate = 50
- emitter.Speed = NumberRange.new(2, 5)
- emitter.Parent = proj.Part
- proj.TrailEmitter = emitter
- end
- end
- --------------------------------------------------------------------------------
- -- Function: ExplodeProjectile
- -- Purpose: Forces a projectile to explode, triggering an explosion effect and area damage.
- -- Parameters:
- -- proj (table) - The projectile object.
- -- blastRadius (number) - Explosion radius (default 5 studs).
- -- blastPressure (number)- Explosion pressure (default 50000).
- --------------------------------------------------------------------------------
- function ProjectileSystem.ExplodeProjectile(proj, blastRadius, blastPressure)
- local explosion = Instance.new("Explosion")
- explosion.Position = proj.Position
- explosion.BlastRadius = blastRadius or 5
- explosion.BlastPressure = blastPressure or 50000
- explosion.Parent = Workspace
- -- Instead of traditional particle effects, trigger our custom hit effect.
- if proj and proj.Part then
- -- If the shooter has a character, apply the hit effect to it (for demonstration).
- if proj.Shooter and proj.Shooter.Character then
- ProjectileSystem.ApplyHitEffect(proj.Shooter.Character, proj.Position, proj)
- end
- end
- ProjectileSystem.DestroyProjectile(proj)
- end
- --------------------------------------------------------------------------------
- -- Return the ProjectileSystem table so it can be required in other scripts.
- --------------------------------------------------------------------------------
- return ProjectileSystem
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement