How to create a fireball ability

Note

This tutorial is older and uses the deprecated form of raycasting which is now replaced by RaycastParams. I may update this tutorial.


This is something many beginner scripters are so inspired to do the moment they want to script, so I made a tutorial for it.

Let’s start with what you should know:
-Remote events and how client to server works
-UserInputService

Animation

First, create the animation for throwing your fireball. Don’t include any limbs that won’t be useful, so if you only throw a fireball with an arm, only use that arm. Make sure your animation has Action priority.

I create a keyframe that represents the arm going upward and the other two are just the arm’s original position and rotation. You can use your own animation if you’d like.

Right click the keyframe that represents when the fireball is going to be thrown and click Add Animation Event Here:
image

Create an animation event to something you will remember later, I will use “Activate”.

Publish your animation and remember the ID for it:

Local script

Make a local script into either StarterGui or StarterPack, I will put it in StarterGui for my case.
image

Setup the code like so:
image

UIS is the service we will use to detect input (when you press any keyboard button)

KeyToUse is the KeyCode Enum we will use to get what the player is pressing. We will use “E” since we want the player to shoot a fireball when they press “E”.

The animation is an Animation Instance we will create, change its AnimationId to the animation ID you want after “rbxassetid://”.

We will then try to retrieve the humanoid from the player’s character like this:

We are using a loop to get the humanoid since sometimes, the humanoid is not a descendant of game which breaks the script. (Find out why here)

Next, load the animation by using :LoadAnimation(animation instance) on the humanoid,
image

We then will start detecting when the player presses E by using the InputBegan event of UserInputService (we defined as UIS).

It will return to us two parameters which is the InputObject and a boolean called gameProcessed (true or false). gameProcessed if true usually means that the player has clicked on a GUI like the chat. We don’t want them to start activating fireballs while typing in the chat so we will use a guard clause.

The guard clause looks like this:

if gameProcessed then return end -- return to stop the function from continuing

A guard clause looks more readable and will do exactly what we want, to stop the function if the gameProcessed variable is true.

The properties you see on the right is the properties of an InputObject, which we are getting from the parameter called input.

Define the camera for what we will do soon and the remote for later under our loaded animation variable.

After the if statement we create to check if the pressed input was exactly what we wanted, we will first define the location of our mouse as a variable.
image

:GetMouseLocation() is something we can call on UserInputService to get a Vector2 value of where the mouse is (Vector2 is a X and Y value, just two coordinates).

Then, play our animation and we wait for the marker event we created earlier in the Animation Editor using the AnimationTrack we got from loading the animation and using :GetMarkerReachedSignal(name of our event) to get the event and then use :Wait() on it.

We will then proceed to use the mouse location to raycast from the camera to shoot our fireball towards.

We use :ViewportPointToRay which will shoot the ray for us with the mouse location we got and then we will redefine the ray variable as a new Ray using the ray we got from :ViewportPointToRay.

A ray has an origin property and direction property so we will utilize those. We multiply the direction by 200 as in that the ray will go in its direction by 200 studs, which would be the range the fireball can reach.

We then calculate the pos to shoot the fireball towards, we don’t need to know if a target was hit or not since the fireball isn’t going to be instantly getting there so we leave the first variable with an underscore (_) to indicate we don’t need it.

Server script

Now, create a server script and place it in ServerScriptService then create a RemoteEvent in ReplicatedStorage. In the server script we will start with the following code:
image

Define our Tween variables for later:

Then setup a variable that was our range from before and an OnServerEvent function for the RemoteEvent we defined, it will give us the parameter for player which we use to get the HumanoidRootPart.

Our second parameter will be the position that the client sent us as a Vector3.

We will also have setup a guard clause for changing the Magnitude of the distance from each other to make sure they’re within range as a tiny anti-exploit protection.

Add the right hand or right arm variable as you want. If you want to make it R6 only then just replace that line where rightHand is defined with:

local rightHand = player.Character["Right Arm"]

Then, we create a part as well with what we want as our fireball

And we CFrame it to what we want and set its Parent to workspace so that it exists:

We are basically moving it from the right hand’s front (which is downward in the Y direction) and then adding the part’s size so it won’t be colliding with the hand then we add an offset of 1 stud to make it a little farther away from the hand.

We divide the Y property in Size by 2 since we are using the center of the rightHand which is the position then going half the size to the surface of the hand.

Next, use the Create method of TweenService to start making our tween. We will utilize the tweenInfo variable from earlier with the TweenService. The third argument we send is a table of properties we want to change, in this case we want to change the Position value to our desired endpoint.

We then play the tween then make a Touched event that checks when something with a Humanoid has touched it.

Next we will check if what we hit was actually our character to prevent damaging ourselves and to deal damage if it’s a different person.

We are making the humanoid take 25 damage, adding a fire object that we edit the heat property to 20 and then removing it 2 seconds later, disconnecting our event, and then destroying the part. EDIT: Since we destroy the part anyways, you may skip the disconnection and setting the connection as a variable.

Since there’s a possibility the part would be destroyed of course after we wait for our tween to be completed, if the part remains we destroy it.

Next, we’ll implement our debounce. We do it server-side as it prevents exploitation. We’ll first have to go back to where we created our OnServerEvent connection.

Then we’ll create a table that will store our players as a debounce when they shoot a fireball and use a guard clause to prevent them from shooting a fireball too fast by checking if they’re in the table. We’ll also add them to the table if they’re not in the table already.

And then go to the end of the code to implement a delay which will run a function for us 1 second ahead of time which is our debounce.

Result

Local script code
local UIS = game:GetService("UserInputService")
local KeyToUse = Enum.KeyCode.E
local animation = Instance.new("Animation")
animation.AnimationId = "rbxassetid://5000364357"

local player = game.Players.LocalPlayer
local humanoid = player.Character:WaitForChild("Humanoid")

while humanoid and not humanoid:IsDescendantOf(workspace) do
    humanoid.AncestryChanged:Wait()
end

local anim = humanoid:LoadAnimation(animation)

local event = game.ReplicatedStorage.FireballRemote

local camera = workspace.CurrentCamera

UIS.InputBegan:Connect(function(input, gameProcessed)
	if gameProcessed then return end
	if input.KeyCode == KeyToUse then
		local mouseLocation = UIS:GetMouseLocation()
		anim:Play()
		anim:GetMarkerReachedSignal("Activate"):Wait()
		local ray = camera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
		ray = Ray.new(ray.Origin, ray.Direction * 200)
		local _, pos = workspace:FindPartOnRay(ray, player.Character)
		event:FireServer(pos)
	end
end)
Server script code
local replicatedStorage = game.ReplicatedStorage
local fireballRemote = replicatedStorage.FireballRemote

local maxRange = 200

local TweenService = game:GetService("TweenService")
local tweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)

local playerDebounces = {}
fireballRemote.OnServerEvent:Connect(function(player, targetPos)
	if table.find(playerDebounces, player) then return end
	local humanoidRootPart = player.Character.Humanoid.RootPart
	if not humanoidRootPart then return end
	if (humanoidRootPart.Position - targetPos).Magnitude > maxRange then return end
	local rightHand = player.Character.RightHand
	
	table.insert(playerDebounces, player)
	
	local part = Instance.new("Part")
	part.Anchored = true
	part.CanCollide = false
	part.Shape = Enum.PartType.Ball
	part.BrickColor = BrickColor.new("Medium red")
	local size = Vector3.new(3, 3, 3)
	part.Size = size
	
	part.CFrame = rightHand.CFrame * CFrame.new(0, -(rightHand.Size.Y/2 + size.Y + 1), 0)
	
	part.Parent = workspace
	
	local createTween = TweenService:Create(part, tweenInfo, {
		Position = targetPos
	})
	createTween:Play()
	hasBeenTouched = part.Touched:Connect(function(hit)
		local parentOfHit = hit.Parent
		local humanoid = parentOfHit:FindFirstChild("Humanoid")
		if not humanoid then return end
		if parentOfHit == player.Character then return end
		humanoid:TakeDamage(25)
		local fire = Instance.new("Fire")
		fire.Heat = 20
		fire.Parent = hit
		game.Debris:AddItem(fire, 2)
		hasBeenTouched:Disconnect()
		part:Destroy()
	end)
	createTween.Completed:Wait()
	if part then
		part:Destroy()
	end
	delay(1, function()
		if not player then return end
		table.remove(playerDebounces, table.find(playerDebounces, player))
	end)
end)

Here is a place file of the fireball product after I added the extras from below.
Fireball.rbxl (38.7 KB)

Extras

If you want to smoothen the surfaces of the part you can do this:

If you want to create a burning audio effect upon hitting something you can do go to where we created our fire instance before in the server script and create a sound instance and set its ID.
image

You can similarly create a trailing fireball audio effect by doing the same (without using Debris:AddItem since it is going to be destroyed anyways) but parent it inside the part after it’s made.

57 Likes

Nice tutorial, but I wouldn’t run any tweens on the server, let the client handle that.

5 Likes

Thank you for the suggestion, I just didn’t want the client to handle anything related to the part since I was scared of possible exploitation but I realized Touched is just as exploitable even if I call a tween via FireClient.

2 Likes

Great tutorial! I actually never even heard of animation events so that is really nice to know for future reference.

When implementing this into a game I also recommend just handling all animations on the client(like @Scrizonn said) and have the server check to make sure the fireball does actually hit a player. Never trust the client!

4 Likes

Clients can spoof Touched event, a solution is to not utilize Touched events but the point of this tutorial is to for beginners so I avoided that on this tutorial.

Animation events are essentially Markers, different from Keyframe events.

1 Like

Nice tutorial, I am a little confused on why in the tutorial you tell people to add the debounce table server side and yet when you provide the code near the bottom of the post you added a simple debounce in the local script and kept the table debounce out of the server script.

Also I noticed in the image for the player Debounce you are adding the table at line 19 when anyone who was following along with the same indentations and spacing between lines of code would be adding that at line 9 implying that there is additional code or at the very least spacing that was left out of the tutorial. This could be confusing to some people (especially beginners) if they are following along with the images and see that what they are doing doesn’t exactly match up to what you’ve been doing.

Sorry for the lengthy reply, still a good tutorial with many fundamentals covered for actions such as this. Take care.

1 Like

I think I mixed some wrong code in it, I’ll fix it.

For the image issues, it is because I kept changing code so much that I got a little lazy and kept some images. I believed I changed images around over 10 times because of how careless I was with some mistakes.

As a first tutorial, I probably made the wrong impression I wanted. :anguished:

Not at all, as I said it was a good tutorial. Cleaning up those small little mistakes are what turns a good tutorial into a great tutorial. :slight_smile:

The code has been fixed now. Unfortunately, it’d be too much to fix the images with their weird lining since I was making this tutorial while making the code. I’ll be careful to not have this mistake occur again.

It would better for people to just copy the code I give at the end anyways and try to follow from there.

Well explained tutorial, worth reading it.
But I wouldn’t be sure about the part where the client sends the target position to the server, since
any exploiter could call the event and send the position of another player, even though it is not in sight.

You can only get the position of the mouse from
the client, do you have another way to go about it then that you think is more secure? They could still use a fake position as where their mouse is if I raycasted from the server.

It’s a good tutorial but it doesn’t work (anymore?), i used the file.

1 Like

Nice to know how to make animation keybinds lol

1 Like

It might be because an animation is being used which I own since you’ll have to custom implement your own. (file was just an example where you could replace the animation ID)

I might redo the tutorial but let me know what you see wrong with it (errors in output? etc).

2 Likes

the only error was I was using the wrong anim so when I changed it to my own there were no errors at all but it wasn’t working

Could you describe it to me specifically with defail how it doesn’t work? Did you correctly add in the animation event?

Discuss with me via DMs so to not flood this thread’s replies.

Thats really nice tutorial can you make more advanced version of it? Like explosion effect when it hits to player or baseplate or buildings. It has been 1 year since this tutorial created and i believe you got way more experience so your advanced tutorial can help us a lot! Thanks for tutorials!

3 Likes

maybe :IsA can solve your problem!

1 Like