Structuring a story-driven game

How can I structure my code for a story-driven game? This would involve NPCs, location-based events (e.g. entering a room), and cutscenes. I’ve done a little bit of searching, so my guess is that it involves a finite-state machine and a governing module for each stage. These modules would react to the states and construct/destruct the stages accordingly.

EDIT: Specifically, think like a Call of Duty campaign. It has a linear storyline with different locations, NPCs that respond to your actions, and cutscenes. I want to avoid the spaghetti of a million if statements to determine what comes next in the story. I proposed a solution above, but I’m wondering if anybody has worked on a game like this and could share their knowledge.

8 Likes

Okay, before we start, it’s way much simpler than a

Anyways, lets get to it!

Hello! So you’re going camping style, right? Anyways, you would first want a eye-catching design. But don’t spend too much time on it, nothing is perfect. Anyways, this is how I would do it:

Making Design

This is the 'design' I was talking about. Start by making a ScreenGui into StarterGui. Name this TalkingGui. It should now look like this: ![](https://i.imgur.com/DDddZki.png) So, inside of that gui you made, Insert a Frame. Name that whatever you want, I'll just name it TalkingFrame. Now, I'm going to make it so it fits to any screen. If you don't do that, if you are on a small phone, or a big screen, it would be too big/small. I reccomend using [this](https://www.roblox.com/library/150152826/Gui-Rescaler) plugin. It automatically rescales it on each screen so it has a perfect fit. To use it, select the frame, open the plugin, and click the frames name in the Explorer. Viola! It rescales. Now, duplicate the frame you just made. Now rename it to ImageHolder. Customize that how you want, too.

Hooray! We have part 1 done!

Well then, lets make Part Two: NPCs

Making NPCs

This step is probably the easiest. I would use [this](https://www.roblox.com/library/752585459/Load-Character-Lite) plugin to make them. By the way, when you install plugins, you have to restart roblox studio once they're finished installing. So, click the Load Character button and type the players username that will be the npc. I'll enter my username, TheWorstOne_2. Now, click Spawn R15. If you do R6, the animate script I give wont work. Now, you have your character. Inside of the players model, unanchor HumanoidRootPart. Now get this model: https://www.roblox.com/library/4614519405/R15-Animate Once you have that, put it in the players model. Your NPC is a living, breathing thing! Once again, make sure that the part HumanoidRootPart inside of the players model is unanchored. This is **essential.**

Welcome to Part 3: Moving the NPC

Moving the NPC

The bad thing about doing this is that when it moves, it moves to a parts position. So if a wall is in front of that, you’d have to make multiple parts to make the path.
Before we do that, insert a Folder into workspace. You do this so the players cant push the NPC. If they can, they could push them when they’re not moving, or even push them off the map! Put the NPC in the folder, and keep the folders name to Folder. Now, insert a Script into ServerScriptService named NPCPhysics. Type this into the script:

local npcs=workspace.Folder

local ps=game:GetService("PhysicsService")

ps:CreateCollisionGroup("PlayersGroup")
ps:CreateCollisionGroup("NpcsGroup")

ps:CollisionGroupSetCollidable("PlayersGroup", "NpcsGroup", false)

for _,npc in pairs(npcs:GetChildren()) do
 for _,v in pairs(npc:GetDescendants()) do
      if v:IsA("BasePart") then
           ps:SetPartCollisionGroup(v,"NpcsGroup")
      end
 end

end

game.Players.PlayerAdded:Connect(function(plr)
 plr.CharacterAdded:Connect(function(char)
      wait()
      for _,v in pairs(char:GetChildren()) do
           if v:IsA("BasePart") then
                ps:SetPartCollisionGroup(v,"PlayersGroup")
           end
      end
 end)
end)

Okay! You have that code in. Now you can walk through the player. That may sound weird, but I’m just trying to help. Now, they can’t move the player. Insert another script into ServerScriptService. Lets name this NPCHandler. Lets type some code into that.

local npc = game.Workspace:WaitForChild("Folder"):WaitForChild("TheWorstOne_2")

So, you typed your first line of code. Change the word TheWorstOne_2 to your NPCs name. While you change that, don’t remove the " "
Here’s the second line
local hum = npc:WaitForChild(“Humanoid”)

Your code should now be
local npc = game.Workspace:WaitForChild(“Folder”):WaitForChild(“TheWorstOne_2”)
local hum = npc:WaitForChild(“Humanoid”)

I use WaitForChild so it gives the game time to load the object, then when it’s done loading it, it will resume the script. We’re going to be using waits alot in this. Hopefully you know what they are, but if you dont, here’s what they are. So basically, wait is just waiting the time you put in there. You cant time minutes or anything. You just type the number you want it to wait. That number is in seconds.
So if I were to type wait(10) then it would wait 10 seconds. Now, if I changed that number to 60, then it would wait a full minute, then resume the script. So, get out of the script for now, and go back into workspace. Insert a part. Name that Walk1 or Walk2 and so on. Now make sure you have the properties window open. Select that part and set Transparency to 1, and Uncheck CanCollide. Also, make sure you anchor than part. Go back into the script. Type

hum:MoveTo(game.Workspace:WaitForChild("Walk1").Position)

hum.MoveToFinished:Connect(function()

wait(3) --wait three seconds

hum:MoveTo(game.Workspace:WaitForChild("Walk2").Position)
hum.MoveToFinished:Connect(function()
--and so on
end)
end)

After each walk, do a hum.MoveToFinished:Connect(function()
and put code inside of that
and put end) at the end of it. You might want to put a wait, or maybe not if you are making a path that will move to different parts right after finished. Well, you have that part finished! Finally, that one took me a while to type.

Welcome to part I lost count: Custscenes

Making Custscenes

This one is quite easy, as I do it all the time. I used a plugin, but it broke. Good news! I’ll teach you how to fix it. So press the New Cutscene button and whenever you want to take a Camera Shot, press the Capture camera button. Mess with those settings and press done. When you are finished, press save cutscene, then Executable Local Script. Press done. Now, you have that script. Put that in StarterGui. Now, insert a RemoteEvent into ReplicatedStorage and name it Custscene1. Go into the NPCHandler script and put this line of code when you want to play the cutscene. I’ll do it after the first walk. Put this code in:

local plrs = game.Players:GetChildren()
local randomplr = plrs[math.random(1,#plrs)]
game.ReplicatedStorage:WaitForChild('Cutscene1'):FireClient(randomplr)

You have to do the randomplr thing, because roblox requires at least one player variable. Now, insert another localscript into StarterGui. Name this Cutscene1Handler. The Executable Script you made with the Custscene plugin should be parented to StarterGui, and not inside anything inside of StarterGui. Now, put this code in Cutscene1Handler:

game.ReplicatedStorage:WaitForChild('Cutscene1').OnClientEvent:Connect(function(hi)

script.Parent.CutsceneScript.Disabled = false
end)

By the way, I just checked. It didn’t have a error. It just does for the PlayerEntered script.

By the way times two, rename every cutscene script to something different, or it will chose a random one.

That’s part 4 finished! Hooray! :tada:

By the way, if you want me to teach you how to do text in the gui, I’ll be happy to do so.

Tell me anything wrong by replying to this. Bye! :smiley:

Edit: Oh my gosh, I just realised I typed 7153 characters in this. I’m proud of myself!

14 Likes

Thank you so much for your response! It’s well-written and easy to follow, so kudos to you. I should have worded my title differently because my question was more about games with linear progression in general, not necessarily a Camping style game. Think like a Call of Duty campaign. That’s my fault for wording it poorly, but this would be helpful for people who are looking to create a Camping-style game. You might consider posting it in #resources:community-tutorials.

1 Like

Okay, I’ll try. I have to get accepted by roblox : p I’ll also add on to it a bit.

2 Likes