How to Make a Raycasting Lasergun

From Legacy Roblox Wiki
Revision as of 07:10, 10 July 2011 by >ZackZak
Jump to navigationJump to search

Introduction

Hey there!
I'm going to show you the built in ROBLOX raycasting, and a practical application: A Lasergun.
And in less than 30 lines of code too...

Raycasting is basically checking for collisions in a direction. ROBLOX raycasting is used with the workspace :FindPartOnRay(Ray,Ignore) method. It takes two arguments. The first argument is a ray. To construct a ray you use Ray.new(Start,Offset). Start is the point the ray checks for collisions from, offset is how far to check away from it. The second argument is an instance. The ray will ignore all the stuff inside the descendants of that instance.

Tutorial

Getting The Base

The first thing we want to do is get an actual laser gun for us to script! We could make a tool, insert a handle and a mesh and all that or we could just use the ROBLOX paintball gun. Let's start by grabbing that from the toolbox under tools & weapons. Next just take all the stuff out of the tool except the handle and mesh. Now we have a nice tool that we can easily script. Insert a script from insert > object > script and start editing.

Equipping And Clicking

Next up we need to code our base. In our script let's start with this:

local Tool = script.Parent
local User

These will be our starter variables. We didn't set a value for User, as it can change when a new person picks it up. Now we need to make it so that it'll do something when we equip. Let's connect the equipped event for the tool to a function. Note: You don't have to explicitly create a function for this, you can just put an unnamed function inside the :connect perimeters, like this:

local Tool = script.Parent
local User
Tool.Equipped:connect(function(mouse)

end)

Now we have our function connected to the event, and we have access to the mouse because that's what equipped sends in. Now we can do almost the same thing with the button1down event in the mouse, except it doesn't send anything:

local Tool = script.Parent
local User
Tool.Equipped:connect(function(mouse)
    mouse.Button1Down:connect(function()

    end)
end)

When we click the left button on the mouse, our event will be fired!

Raycasting

Now we need to create a ray, but first we should get the character of the player so the ray won't collide with them. When a tool is picked up or equipped it moves its parent into their character, so we can just do this:

local Tool = script.Parent
local User
Tool.Equipped:connect(function(mouse)
    User = Tool.Parent
    mouse.Button1Down:connect(function()

    end)
end)

Now we're ready! Rays take two arguments, a start and an offset. The start is basically where the ray is coming from and the offset is how far to check off of the start. Let's create a ray between the tool handle and the mouse:

local Tool = script.Parent
local User
Tool.Equipped:connect(function(mouse)
    User = Tool.Parent
    mouse.Button1Down:connect(function()
        local Ray = Ray.new(Tool.Handle.CFrame.p,(mouse.Hit.p-Tool.Handle.CFrame.p).unit*300)
    end)
end)

Now we have our ray! We made the offset with the direction between the tool handle and the mouse click position, and multiplied it by 300 so that it won't have too long of a range. Next we should check for a collision with game.Workspace:FindPartOnRay(Ray,Ignore). We'll supply our ray, and for ignore we'll use User. It returns two values, the hit part and the position it hit at. If it didn't hit anything it returns nil and the end point of the ray. Here's our code now:

local Tool = script.Parent
local User
Tool.Equipped:connect(function(mouse)
    User = Tool.Parent
    mouse.Button1Down:connect(function()
        local Ray = Ray.new(Tool.Handle.CFrame.p,(mouse.Hit.p-Tool.Handle.CFrame.p).unit*300)
        local Hit,Position = game.Workspace:FindPartOnRay(Ray,User)
    end)
end)

Now we have two variables we can use to do damage and draw a laser.

Doing Damage And Drawing Lines

Now we need to make it check if it hit something, see if there's a humanoid and do damage if they don't have a forcefield. You most likely know how to do the first two things if you've come this far, but to stop it from doing damage if they have a forcefield we'll use the :TakeDamage(Damage) method on the humanoid. Here we go:

local Tool = script.Parent
local User
Tool.Equipped:connect(function(mouse)
    User = Tool.Parent
    mouse.Button1Down:connect(function()
        local Ray = Ray.new(Tool.Handle.CFrame.p,(mouse.Hit.p-Tool.Handle.CFrame.p).unit*300)
        local Hit,Position = game.Workspace:FindPartOnRay(Ray,User)
        if Hit then
	    if Hit.Parent:FindFirstChild("Humanoid") then
	        Hit.Parent.Humanoid:TakeDamage(30)
	    end
	end
    end)
end)

Excellent! If you fire at something with a humanoid it will take 30 damage. It's kind of hard to visualize the path though, so let's draw a laser. To do this we'll create a nice skinny custom part and stretch it to the length between the points, then set its CFrame to the point in the middle of the points. Here we go:

local Tool = script.Parent
local User
Tool.Equipped:connect(function(mouse)
    User = Tool.Parent
    mouse.Button1Down:connect(function()
        local Ray = Ray.new(Tool.Handle.CFrame.p,(mouse.Hit.p-Tool.Handle.CFrame.p).unit*300)
        local Hit,Position = game.Workspace:FindPartOnRay(Ray,User)
        if Hit then
	    if Hit.Parent:FindFirstChild("Humanoid") then
	        Hit.Parent.Humanoid:TakeDamage(30)
	    end
	end
        local RayPart = Instance.new("Part",User)
	RayPart.Name = "RayPart"
	RayPart.BrickColor = BrickColor.new("Bright red")
	RayPart.Transparency = 0.5
	RayPart.Anchored = true
	RayPart.CanCollide = false
	RayPart.TopSurface = Enum.SurfaceType.Smooth
	RayPart.BottomSurface = Enum.SurfaceType.Smooth
	RayPart.formFactor = Enum.FormFactor.Custom
	local Distance = (Position-Tool.Handle.CFrame.p).magnitude
	RayPart.Size = Vector3.new(0.2,0.2,Distance)
	RayPart.CFrame = CFrame.new(Position,Tool.Handle.CFrame.p) * CFrame.new(0,0,-Distance/2)
	game.Debris:AddItem(RayPart,0.1)
    end)
end)

That'll draw a nice semi visible red line between the two points. We're using magnitude to determine the distance, and then setting the CFrame with two arguments which will point the CFrame from the first argument to the second. Then we offset it by negative the distance between the points divided by two, so we end up in the middle. Adding it to the debris will make it delete after 0.1 the second argument number of seconds.

Final Product

local Tool = script.Parent --Set a variable for the tool.
local User --Create a nil value for the character which we can't find yet.
Tool.Equipped:connect(function(mouse) --When it's equipped fire a function.
    User = Tool.Parent --Set the User variable to the character of the person using the tool.
    mouse.Button1Down:connect(function() --When the left mouse button is clicked fire a function.
        local Ray = Ray.new(Tool.Handle.CFrame.p,(mouse.Hit.p-Tool.Handle.CFrame.p).unit*300) --Make a the ray.
        local Hit,Position = game.Workspace:FindPartOnRay(Ray,User) --Check for collisions along the ray.
        if Hit then --If it hits something.
	    if Hit.Parent:FindFirstChild("Humanoid") then --If the thing the ray hit has a humanoid.
	        Hit.Parent.Humanoid:TakeDamage(30) --Do 30 damage if they don't have a forcefield.
	    end --End the humanoid check.
	end --End the hit check.
        local RayPart = Instance.new("Part",User) --Create a part in the user.
	RayPart.Name = "RayPart" --Set its name.
	RayPart.BrickColor = BrickColor.new("Bright red") --Set its color.
	RayPart.Transparency = 0.5 --Set its transparency.
	RayPart.Anchored = true --Set whether it will fall or not.
	RayPart.CanCollide = false --Set whether people can walk though it or not.
	RayPart.TopSurface = Enum.SurfaceType.Smooth --Make it smooth on the top.
	RayPart.BottomSurface = Enum.SurfaceType.Smooth --Make it smooth on the bottom.
	RayPart.formFactor = Enum.FormFactor.Custom --Make it so it can be small.
	local Distance = (Position-Tool.Handle.CFrame.p).magnitude --Find the distance between the click and the gun.
	RayPart.Size = Vector3.new(0.2,0.2,Distance) --Set its size to the distance.
	RayPart.CFrame = CFrame.new(Position,Tool.Handle.CFrame.p) * CFrame.new(0,0,-Distance/2) --Move it halfway.
	game.Debris:AddItem(RayPart,0.1) --Add it to the debris.
    end)
end)
The finished raycasting laser gun.

See Also