PcoWSkbVqDnWTu_dm2ix
Hit Detection with Lasers
Part 3 - Rendering the Laser Beam
Hit Detection with Lasers
Part 3 - Rendering the Laser Beam

Finding the Laser Position

The blaster should fire a red beam of light at its target. The function for this will be inside a ModuleScript so it can be reused in other scripts later on. First, the script will need to find the position where the laser beam should be rendered.

  1. Create a ModuleScript named LaserRenderer, parented to StarterPlayerScripts under StarterPlayer.

  2. Open the script and rename the module table to the name of the script LaserRenderer.

  3. Declare a variable named SHOT_DURATION with a value of 0.15. This will be the amount of time (in seconds) the laser is visible for.

  4. Create a function of LaserRenderer named createLaser with two parameters called toolHandle and endPosition.

    local LaserRenderer = {}
    
    local SHOT_DURATION = 0.15 -- Time that the laser is visible for
    
    -- Create a laser beam from a start position towards an end position
    function LaserRenderer.createLaser(toolHandle, endPosition)
    
    end
    
    return LaserRenderer
  5. Declare a variable named startPosition and set the Position property of toolHandle as its value. This will be the position of the player’s laser blaster.

  6. Declare a variable named laserDistance and subtract endPosition from startPosition to find the difference between the two vectors. Use the Magnitude property of this to get the length of the laser beam.

    function LaserRenderer.createLaser(toolHandle, endPosition)
        local startPosition = toolHandle.Position
    
        local laserDistance = (startPosition - endPosition).Magnitude
    end
  7. Declare a laserCFrame variable to store the position and orientation of the laser beam. The position needs to be the midpoint of the start and end of the beam. Use CFrame.lookAt to create a new CFrame located at startPosition and facing towards endPosition. Multiply this by a new CFrame with a Z axis value of half of negative laserDistance to get the midpoint.

    function LaserRenderer.createLaser(toolHandle, endPosition)
        local startPosition = toolHandle.Position
    
        local laserDistance = (startPosition - endPosition).Magnitude
        local laserCFrame = CFrame.lookAt(startPosition, endPosition) * CFrame.new(0, 0, -laserDistance / 2)
    end

Creating the Laser Part

Now that you know where to create a laser beam, you need to add the beam itself. This can be done easily with a Neon part.

  1. Declare a variable laserPart and assign to it a new Part instance.

  2. Set the following properties of laserPart:

  • Size: Vector3.new(0.2, 0.2, laserDistance)
  • CFrame: laserCFrame
  • Anchored: true
  • CanCollide: false
  • Color: Color3.fromRGB(225, 0, 0) (a strong red color)
  • Material: Enum.Material.Neon
  1. Parent laserPart to Workspace.

  2. Add the part to the Debris service so that it gets removed after the amount of seconds in the SHOT_DURATION variable.

    function LaserRenderer.createLaser(toolHandle, endPosition)
        local startPosition = toolHandle.Position
    
        local laserDistance = (startPosition - endPosition).Magnitude
        local laserCFrame = CFrame.lookAt(startPosition, endPosition) * CFrame.new(0, 0, -laserDistance / 2)
    
        local laserPart = Instance.new("Part")
        laserPart.Size = Vector3.new(0.2, 0.2, laserDistance)
        laserPart.CFrame = laserCFrame
        laserPart.Anchored = true
        laserPart.CanCollide = false
        laserPart.Color = Color3.fromRGB(225, 0, 0)
        laserPart.Material = Enum.Material.Neon
        laserPart.Parent = workspace
    
        -- Add laser beam to the Debris service to be removed & cleaned up
        game.Debris:AddItem(laserPart, SHOT_DURATION)
    end

Now the function to render the laser beam is complete, it can be called by the ToolController.

  1. At the top of the ToolController script, declare a variable named LaserRenderer and require the LaserRenderer ModuleScript located in PlayerScripts.
    local UserInputService = game:GetService("UserInputService")
    local Players = game:GetService("Players")
    
    local LaserRenderer = require(Players.LocalPlayer.PlayerScripts.LaserRenderer)
    
    local tool = script.Parent
  2. At the bottom of the fireWeapon function, call the LaserRenderer createLaser function using the tool handle and hitPosition as arguments.
            -- Calculate the end position based on maximum laser distance
            hitPosition = tool.Handle.Position + directionVector
        end
    
        LaserRenderer.createLaser(tool.Handle, hitPosition)
    end
  3. Test the weapon by clicking the Play button. A laser beam should be visible between the weapon and the mouse when the tool is activated.

Controlling Weapon Fire Rate

Weapons need a delay between each shot to stop players from dealing too much damage in a short amount of time. This can be controlled by checking if enough time has passed since a player last fired.

  1. Declare a variable at the top of the ToolController called FIRE_RATE. This will be the minimum time between each shot. Give it a value of your choosing; this example uses 0.3 seconds.

  2. Declare another variable underneath called timeOfPreviousShot with a value of 0. This stores the last time the player fired and will be updated with each shot.

    local MAX_MOUSE_DISTANCE = 1000
    local MAX_LASER_DISTANCE = 300
    local FIRE_RATE = 0.3
    local timeOfPreviousShot = 0
  3. Create a function called canShootWeapon with no parameters. This function will look at how much time has passed since the previous shot and return true or false.

    local FIRE_RATE = 0.3
    local timeOfPreviousShot = 0
    
    -- Check if enough time has passed since previous shot was fired
    local function canShootWeapon()
     
    end
    
    local function getWorldMousePosition()
  4. Inside the function declare a variable named currentTime; assign to it the result of calling the tick function. This returns how much time has elapsed, in seconds, since the 1st of January 1970 (an arbitrary date widely used to calculate time).

  5. Subtract the timeOfPreviousShot from currentTime and return false if the result is smaller than FIRE_RATE; otherwise, return true.

    -- Check if enough time has passed since previous shot was fired
    local function canShootWeapon()
        local currentTime = tick()
        if currentTime - timeOfPreviousShot < FIRE_RATE then
            return false
        end
        return true
    end
  6. At the end of the fireWeapon function, update timeOfPreviousShot each time the weapon is fired using tick.

            hitPosition = tool.Handle.Position + directionVector
        end
        
        timeOfPreviousShot = tick()
    
        LaserRenderer.createLaser(tool.Handle, hitPosition)
    end
  7. Inside the toolActivated function, create an if statement and call canShootWeapon to check if the weapon can be fired.

    local function toolActivated()
        if canShootWeapon() then
            tool.Handle.Activate:Play()
            fireWeapon()
        end
    end

When you test the blaster you should find that no matter how fast you click, there will always be a short 0.3 seconds delay between each shot.


Previous Page Firing Towards the Target Next Page Client to Server Communication