Hello there! It is I, InfernalProgrammer.
Today I’ll be showing you How to Make a Boss Battle using functions and such.
Also, A quick Little Note before we begin. The Player’s RigType will be R6, not R15 as most weapons aren’t R15 Compatible.
I WILL BE GOING QUITE IN DEPTH HERE! THIS WILL COVER MAKING A.I AND SUCH!
Step 1 - Design
The first thing that goes Into making a Boss battle is Not only the scripting, But Coming up with an idea that Fits the Theme of your game. I won’t be going in-depth about building as I am not that great with it. I’ll be going with a Blank template for this Tutorial.
(Ah yes, The stereotypical Sword-Wielding Dummy)
Scripting Pt.1
Alright, So you (hopefully) have your Boss all Modeled, Rigged, and Maybe even Animated. Let’s do this!
NOTE: YOU DO NOT NEED TO COPY THIS LINE FOR LINE! FEEL FREE TO CUSTOMIZE HOWEVER YOU MAY LIKE!
First off, Let’s put a “ServerScript” in “ServerScriptService”.
I’d recommend naming it “BossMain”, to help with Organization.
Step 1 - Variables
local Boss = game.Workspace.BossandEnemies.Boss
local BossHum = Boss:WaitForChild("Humanoid")
local BossRoot = Boss:WaitForChild("HumanoidRootPart")
local char -- This will Be Declared Later.
local players = game:GetService("Players")
In Lua (Which is the Programming Language Roblox Studio uses), “Local” is declaring either a Shortcut, or a Variable.
Now, I know I could’ve done
game.Players
For the “players” Variable, But, This is the way most people do it. (Including me lol)
Scripting Pt.2 - Animations
Now, Animations are a little bit tricky to learn, Especially if you are…Somewhat new, Like I am.
To load an Animation, You want to
A) Make the Animation
and
B) Load The Animation
To Load The Animation, You want to do
(This is also declaring a Variable)
NOTE: YOU WILL NEED A SCRIPT INSIDE OF YOUR BOSS CALLED “ANIMATE” AND A “ANIMATOR” OBJECT INSIDE YOUR HUMANOID!
local [animation Name here]Anim = Boss.Animate.[animation Name here]
local [animation Name here]Track = BossHum.Animator:LoadAnimation([animation Name here]Anim)
The “[animation Name here]Track” Global will play a HUGE part later on. If you don’t have any Animations, I’d make them now.
Scripting Pt.3 - Functions and Such
First, Before we get into the meat of this, We need to declare some more variables, and Get our Players Character! You may be thinking to use “Player.Character”. Your partially right.
If we we’re to do “players.Character” we would get the Error:
"Attempt to index nil with “Character”.
This is why we need to do this:
game.Players.PlayerAdded:Connect(function(plr)
char = plr.Character or plr.CharacterAdded:Wait()
end)
This Function is telling the Client:
Hey, If a Player joins the game, make the global named “char” (Short for “character”) that players Character.
Now, Lets get onto the MEAT of this code.
Setting the Bosses Health
Now, Lets set the Boss’s Maximum Allotted Health. (Allotted is a fancier term for “Allowed”)
if game.Players.PlayerAdded then
BossHum.MaxHealth = 500 --Sets Boss's Maximum Allotted Health
BossHum.Health = 500 --Sets Boss's Health
pcall(main)
end
This is saying “If a Player joins the game, Then Declare the Boss’s Maximum Allotted Health, then Set the Boss’s Health to that Maximum Health.”
You can set the Boss’s Max Health to whatever you want. Like I said, Be Creative!
NOTE: THIS SECTION GETS VERY COMPLICATED VERY QUICKLY! You’ve been Warned.
Setting Up the First Function
function main()
decide = math.random(1,4) -- Picks a Random Number Between 1 and 4
print(decide)
--This tells the Boss to Face the player While the Function is doing its Job.
while true do
wait(0.1)
BossRoot.CFrame = CFrame.new(BossRoot.Position,Vector3.new(char.Torso.Position.X,BossRoot.Position.Y,char.Torso.Position.Z))
end
end
This Function is the “Brain” of the Boss. Just like our own Brains, It Tells us what to do, just like this Function. Now, Pay attention to this Line here.
BossRoot.CFrame = CFrame.new(BossRoot.Position,Vector3.new(char.Torso.Position.X,BossRoot.Position.Y,char.Torso.Position.Z))
This Line here is telling the Boss to Face the Player AT ALL TIMES. (At Least Thats what I hope It’ll do for you.)
If it Didn’t work, Answer This to yourself: Is my Character R15?
If the answer was yes, Then, I’d change it if You want to use weapons, as a Majority of them aren’t R15 Compatible.
Now, How are we going to get the Action functions to Activate? Well, thats why we have this Life saver:
--Calls functions based on the result of the Variable "Decide"
if decide == 1 then
pcall(avoid) --Replace this With your Neutral Function
print(decide)
elseif decide ==2 then
pcall(attack01) --Replace this with the Attack You Want
print(decide)
elseif decide == 3 then
pcall(swing02) --Replace this With the Attack you Want
print(decide)
elseif decide == 4 then
pcall(charge) --Replace this with the Attack you want
print(decide)
end
"Function 2 - The "Dash" Function
function avoid()
local dashDecide --Declares the Variable
dashDecide = math.random(1,2) --Decides whether to Dash or Not
if dashDecide == 1 then
BossHum:Move(Vector3.new(math.random(-15,15),0, 0)) -- This says "Hey, Im telling you to move anywhere in between -15 and 15 studs."
wait(2) -- Wait 2 seconds before continuing
pcall(main) -- Call the "main" Function
elseif dashDecide == 2 then --If "dashDecide" is not equal to "1" then Call the "main" function
pcall(main)
end
end
This will tell the Boss to Move either Left or right on the “X” Axis, or from side to side.
Attack Functions
Now, This can vary a lot, but here’s what I did for my Attacks.
function attack01() --Tells The Boss to Commence attack
BossHum:MoveTo(Vector3.new(char.Torso.Position.X,char.Torso.Position.Y,char.Torso.Position.Z)) --Tells The boss to get Up close and personal with the PLayer
BossHum.MoveToFinished:Wait() --Once the MoveTo Is finished, Play the swing Animation.
swing01Track:Play()
Boss.SwordOfDarkness.Handle.Touched:Connect(function (hit) --If the Sword is touched during the attack, Damage the Player
if hit.Parent == char then
hit.Parent.Humanoid.Health = hit.Parent.Humanoid.Health - 10 --Damages the Player
BossHum.Health = BossHum.Health + 10 --Heals the Boss
end
end)
pcall(main)
end
Im gonna break this down into simpler terms.
If the attack Function is Called, then Rush towards the player at a Normal WalkSpeed, then, Once the MoveTo is finished, Play the Swing Animation. If the Sword hits the Player, Damage the Player and Heal the Boss.
2nd Function - The Vulnerability Attack
function swing02()
--This Function allows for the Boss's Damage to be exponential.
local ableToBeStunned = true
Boss.Vulnerable:Play() --Plays the Vulnerable Sounds
if ableToBeStunned == true and BossHum.Health == BossHum.Health - NumberRange.new(30, 100) then --If the Boss is ABLE TO BE STUNNED, And the Boss is Damage, Do this
BossHum.WalkSpeed = 0 --Freezes the Boss for More damage
if BossHum.Health == BossHum.Health - NumberRange.new(30,100) then --Damage the Boss
BossHum.Health = BossHum.Health - math.random(15,30) --Adds Xtra Damage to the Boss
print(BossHum.Health) --Prints the Boss's Health
wait(3) --Waits 3 seconds then Resets the Boss's WalkSpeed
BossHum.WalkSpeed = 16 --Resets WalkSpeed
pcall(main) -- Calls the Main Function
end
elseif ableToBeStunned == true and BossHum.Health == not BossHum.Health - NumberRange.new(30,100) then
--If ableToBeStunned is True and the Boss HAS NOT BEEN HIT, It'll commence the more Damaging attack.
wait(1)
swing01Track:Play()
--If the Sword is Touched,Then The Player will be Damaged.
Boss.SwordOfDarkness.Handle.Touched:Connect(function (hitx2)
if hitx2.Parent == char then
hitx2.Parent.Humanoid.Health = hitx2.Parent.Humanoid.Health - 40 --Damages the Player for MASSIVE Damage
BossHum.Health = BossHum.Health + 40 --Heals the Boss
wait(1.5) --Waits 1.5 seconds
pcall(main) -- Calls the Main Function
end
end)
end
end
This function Tells the Boss: “Hey, Your going to deal a Massively Damaging attack with the Risk of Being stunned”.
FINAL FUNCTION - The Charge Attack
This function will deal Not as much damage as the previous attack, But will momentarily Slow the Player Down.
function charge()
local success = false
--Sets WalkSpeed for Dashing
BossHum.WalkSpeed = 32
--Dashes towards Player
Boss.ChargeWarning:Play()
wait(3.108)
BossHum:MoveTo(BossHum:MoveTo(Vector3.new(char.Torso.Position.X,char.Torso.Position.Y,char.Torso.Position.Z)))
BossHum.MoveToFinished:Wait()
--If the Attack commences and nothing was hit, Prepare for another action
if wait(3) and success == false then
pcall(main)
end
--Detects if the Attack was a Success
Boss.SwordOfDarkness.Handle.Touched:Connect(function (extraDamage)
success = true
if extraDamage.Parent == char then
--Adds Boss health
BossHum.Health = BossHum.Health + 30
--Removes Players Health
extraDamage.Parent.BossHumanoid.Health = extraDamage.Parent.BossHumanoid.Health - 30
end
end)
--Sets WalkSpeed to Default (16)
BossHum.WalkSpeed = 16
char.Humanoid.WalkSpeed = 5 -- Slows down the Player
wait(2) --Waits 2 seconds
char.Humanoid.WalkSpeed = 16 --Resets the Players WalkSpeed
--Recalls Main
pcall(main)
end
The Final Script (With Annotations) and Resolution
local Boss = game.Workspace.BossandEnemies.Boss
local BossHum = Boss:WaitForChild("BossHumanoid")
local BossRoot = Boss:WaitForChild("BossHumanoidRootPart")
local char
local players = game:GetService("Players")
--// ANIMATIONS
local swing01Anim = Boss.Animate.Swing01Anim
local swing01Track = BossHum.Animator:LoadAnimation(swing01Anim)
local decide
game.Players.PlayerAdded:Connect(function(plr)
char = plr.Character or plr.CharacterAdded:Wait()
end)
game.Players.PlayerAdded:Connect(function(setHealth)
BossHum.MaxHealth = 500
BossHum.Health = 500
pcall(main)
end)
function main()
decide = math.random(1,4) -- Picks a Number Between 1 and 4
print(decide)
--This tells the Boss to Face the player While the Function is doing its Job.
while true do
wait(0.1)
BossRoot.CFrame = CFrame.new(BossRoot.Position,Vector3.new(char.Torso.Position.X,BossRoot.Position.Y,char.Torso.Position.Z))
end
end
--Calls functions based on the result of the Variable "Decide"
if decide == 1 then
pcall(avoid)
print(decide)
elseif decide ==2 then
pcall(attack01)
print(decide)
elseif decide == 3 then
pcall(swing02)
print(decide)
elseif decide == 4 then
pcall(charge)
print(decide)
end
function avoid()
local dashDecide
dashDecide = math.random(1,2)
if dashDecide == 1 then
BossHum:Move(Vector3.new(math.random(-15,15),0, 0))
wait(2)
pcall(main)
elseif dashDecide == 2 then
pcall(main)
end
end
function attack01() --Tells The Boss to Commence attack
BossHum:MoveTo(Vector3.new(char.Torso.Position.X,char.Torso.Position.Y,char.Torso.Position.Z)) --Tells The boss to get Up close and personal with the PLayer
BossHum.MoveToFinished:Wait() --Once the MoveTo Is finished, Play the swing Animation.
swing01Track:Play()
Boss.SwordOfDarkness.Handle.Touched:Connect(function (hit) --If the Sword is touched during the attack, Damage the Player
if hit.Parent == char then
hit.Parent.Humanoid.Health = hit.Parent.Humanoid.Health - 10 --Damages the Player
BossHum.Health = BossHum.Health + 10 --Heals the Boss
end
end)
pcall(main)
end
function swing02()
--This Function allows for the Boss's Damage to be exponential.
local ableToBeStunned = true
Boss.Vulnerable:Play() --Plays the Vulnerable Sounds
if ableToBeStunned == true and BossHum.Health == BossHum.Health - NumberRange.new(30, 100) then --If the Boss is ABLE TO BE STUNNED, And the Boss is Damage, Do this
BossHum.WalkSpeed = 0 --Freezes the Boss for More damage
if BossHum.Health == BossHum.Health - NumberRange.new(30,100) then --Damage the Boss
BossHum.Health = BossHum.Health - math.random(15,30) --Adds Xtra Damage to the Boss
print(BossHum.Health) --Prints the Boss's Health
wait(3) --Waits 3 seconds then Resets the Boss's WalkSpeed
BossHum.WalkSpeed = 16 --Resets WalkSpeed
pcall(main) -- Calls the Main Function
end
elseif ableToBeStunned == true and BossHum.Health == not BossHum.Health - NumberRange.new(30,100) then
--If ableToBeStunned is True and the Boss HAS NOT BEEN HIT, It'll commence the more Damaging attack.
wait(1)
swing01Track:Play()
--If the Sword is Touched,Then The Player will be Damaged.
Boss.SwordOfDarkness.Handle.Touched:Connect(function (hitx2)
if hitx2.Parent == char then
hitx2.Parent.Humanoid.Health = hitx2.Parent.Humanoid.Health - 40 --Damages the Player for MASSIVE Damage
BossHum.Health = BossHum.Health + 40 --Heals the Boss
wait(1.5) --Waits 1.5 seconds
pcall(main) -- Calls the Main Function
end
end)
end
end
function charge()
local success = false
--Sets WalkSpeed for Dashing
BossHum.WalkSpeed = 32
--Dashes towards Player
Boss.ChargeWarning:Play()
wait(3.108)
BossHum:MoveTo(BossHum:MoveTo(Vector3.new(char.Torso.Position.X,char.Torso.Position.Y,char.Torso.Position.Z)))
BossHum.MoveToFinished:Wait()
--If the Attack commences and nothing was hit, Prepare for another action
if wait(3) and success == false then
pcall(main)
end
--Detects if the Attack was a Success
Boss.SwordOfDarkness.Handle.Touched:Connect(function (extraDamage)
success = true
if extraDamage.Parent == char then
--Adds Boss health
BossHum.Health = BossHum.Health + 30
--Removes Players Health
extraDamage.Parent.BossHumanoid.Health = extraDamage.Parent.BossHumanoid.Health - 30
end
end)
--Sets WalkSpeed to Default (16)
BossHum.WalkSpeed = 16
char.Humanoid.WalkSpeed = 5 -- Slows down the Player
wait(2) --Waits 2 seconds
char.Humanoid.WalkSpeed = 16 --Resets the Players WalkSpeed
--Recalls Main
pcall(main)
end
Hello! If you reached the end, Thank you for reading this.
Share any corrections you have made, and I will input them and Credit you.
ALSO, MAKE SURE YOUR BOSS IS NEVER ANCHORED!
This page is (Somewhat) of a WIP.
Also, Share some of you creations you make with this!
-InfernalProgrammer
P.S:
This script isn’t perfect, I know. But, This will give you a basic Idea.
Link to the Model for the Boss:
BossTemplate