Making an in-game phone interface

Well hello there! You’re probably here for the tutorial, so let’s get started!

THIS TUTORIAL IS UNFINISHED AND WILL BE RELEASED ONTO COMMUNITY TUTORIALS WHEN DONE

What you’ll need to know before you start:

  • GUI manipulation.
  • Roblox’s client server model
  • Context action service
  • Tween service
  • For loops
  • Datastores (optional)

This tutorial should be begginer friendly, except for the optional part, which may be a little bit harder to follow. What we will make is a simple phone gui similar to Watch dogs or other open world games.

What our phone will include:

  • Rather easy “app” support
  • Changeable main screen (with optional background saving)
  • A few basic apps such as maps and utilities (extra)

Step 1) Creating the phone

This will be the first and probably easiest part in the tutorial. It’s up to you how you’ll desgin it. Maybe you want it to look like an android phone. Or apple? Maybe even Arch linux for whatever reason? It’s time to get creative! Don’t worry, I’ll drop my phone’s setup below and also leave a .rbxm file if needed.

My ui looks like this in the tree: image

And in game it looks like this:

You can find all the files at the bottom of the tutorial

Step 2) Coding the booting of our phone

But wizard, what do you mean with this? No worries, it’s nothing too hard. We will code an opening part to it. You can use a gui button or context action service. I’ll go with context action service. Why? It does the job well and you can always unbind the function from the service, say in a cutscene.

We’ll need to create a local script, in starter character scripts. I’ll call mine: “OpenPhone”
Now let’s add some text to that script, shall we?

Keep in mind I have disabled the visible property of my “MainContainer” frame

We’ll start with some variables:

local tweenservice = game:GetService("TweenService") --Getting tween service
local contextactionservice = game:GetService("ContextActionService") --Getting ContextActionService
local plr = game.Players.LocalPlayer --Getting our player
local phone = plr.PlayerGui:WaitForChild("Phone") --Getting our phone screen gui from the player's gui folder
local phonemain = phone:WaitForChild("MainContainer") --Getting the container frame
local open = false --This is a boolean value we'll use to keep track of the phone's state

Great! Let’s move onwards! All information needed will be found in the comments.

local function openphone()
	--This is the function we'll bind to contextactionservice and it should open the phone
	if open == false then --Checking if our phone is open; if not we will set the value to true and open it; else we will set the value to false and close it
		phonemain.Visible = true
		open = true
	else
		phonemain.Visible = false
		open = false
	end
end

Nothing too hard, right? Now off to binding our function!

contextactionservice:BindAction("OpenPhone", openphone, false, Enum.KeyCode.Tab) --Binding the function to the key tab

To unbind it you’d do:

contextactionservice:UnbindAction("OpenPhone") --It's that simple, really. We used the name we gave to our action above to unbind it. You can unbind and bind at any time!

And done! If you followed through, your gui should open when pressing TAB! If not, check your output. You’ll be able to troubleshoot there. It would be best to have a similar phone tree, it does matter.

Result:

https://streamable.com/0zt8tm

Now, we’ll add some extra eyecandy to make it look better! First of all, we’ll add a simple blur effect.

In the function, simply add a blur effect to the camera. Our variable declaration should know look like this:

local tweenservice = game:GetService("TweenService") --Getting tween service
local contextactionservice = game:GetService("ContextActionService") --Getting ContextActionService
local plr = game.Players.LocalPlayer --Getting our player
local phone = plr.PlayerGui:WaitForChild("Phone") --Getting our phone screen gui from the player's gui folder
local phonemain = phone:WaitForChild("MainContainer") --Getting the container frame
local open = false --This is a boolean value we'll use to keep track of the phone's state
local camera = workspace.CurrentCamera --The player's camera

Now for the function we’ll create a new instance using Instance.new(), a blur effect

local function openphone()
	--This is the function we'll bind to contextactionservice and it should open the phone
	if open == false then --Checking if our phone is open; if not we will set the value to true and open it; else we will set the value to false and close it
		phonemain.Visible = true
		blur = Instance.new("BlurEffect") --We are creating our blur effect and parenting it to the camera
		blur.Parent = camera
		open = true
	else
		phonemain.Visible = false
		blur:Destroy() --We are destroying our blur effect
		open = false
	end
end

Pretty cool, isn’t it?

https://streamable.com/xsu1yt

For our last addition (You can make more yourself, we’ll create a shut down/startup effect using for loops. Let’s goooo!

For this task, I made the welcome screen and apps frame invisible, as well for the descendants of the background image, located in the apps frame. The background is still, visible. Sorry if this is hard to understand. I tried my best explaining this setup. You’ll find all the files you might need if the explanation was too complicated at the end.

We will update our variable declaration by adding the following:

local phoneapps = phonemain.PhoneFrame.Apps.Background --Getting the apps frame

Here is the full declaration, so far:

local tweenservice = game:GetService("TweenService") --Getting tween service
local contextactionservice = game:GetService("ContextActionService") --Getting ContextActionService
local plr = game.Players.LocalPlayer --Getting our player
local phone = plr.PlayerGui:WaitForChild("Phone") --Getting our phone screen gui from the player's gui folder
local phonemain = phone:WaitForChild("MainContainer") --Getting the container frame
local phoneapps = phonemain.PhoneFrame.Apps.Background --Getting the apps frame
local open = false --This is a boolean value we'll use to keep track of the phone's state
local camera = workspace.CurrentCamera --The player's camera

Amazing! Now we’ll update our function, accordingly:

local function openphone()
	--This is the function we'll bind to contextactionservice and it should open the phone
	if open == false then --Checking if our phone is open; if not we will set the value to true and open it; else we will set the value to false and close it
		phonemain.Visible = true
		blur = Instance.new("BlurEffect") --We are creating our blur effect and parenting it to the camera
		blur.Parent = camera
		open = true
		phonemain.PhoneFrame.Apps.Visible = true --We'll make the apps and welcome screen visible
		phonemain.PhoneFrame.WelcomeTitle.Visible = true
		for index, v in pairs(phoneapps:GetDescendants()) do --We are looping through the gui's descendants and making them visible, once the phone "booted up", to achive a sort of lagging that is natural for most OS'es when powered on
			if not v:IsA("UICorner") then
				v.Visible = true
				wait(0.1)
			end
		end
	else
		phonemain.Visible = false
		blur:Destroy() --We are destroying our blur effect
		open = false
		phonemain.PhoneFrame.Apps.Visible = false --We'll make the apps and welcome screen invisible
		phonemain.PhoneFrame.WelcomeTitle.Visible = false 
		for index, v in pairs(phoneapps:GetDescendants()) do --We are looping through the gui's descendants and making them invisible, once the phone "shut down"
			if not v:IsA("UICorner") then
				v.Visible = false
			end
		end
	end
end

We added a for loop at to make every app visible one by one. And another one to make each app invisible one by one, similar how most OSes boot up.

I’ve used if not v:IsA("UICorner") then to check if the ui element is not an ui corner. If there’s any other instance type that you do not want to be made visible, or is simply impossible to make visible (Example: gradients), simply add them here.

Alright then, you should have something like this by now:

https://streamable.com/c0ps30

Not so hard after all! Now that our opening up code is finished, we will take care of some basic settings

But before we continue, here is the finished code, if you need to double check:

local tweenservice = game:GetService("TweenService") --Getting tween service
local contextactionservice = game:GetService("ContextActionService") --Getting ContextActionService
local plr = game.Players.LocalPlayer --Getting our player
local phone = plr.PlayerGui:WaitForChild("Phone") --Getting our phone screen gui from the player's gui folder
local phonemain = phone:WaitForChild("MainContainer") --Getting the container frame
local phoneapps = phonemain.PhoneFrame.Apps.Background --Getting the apps frame
local open = false --This is a boolean value we'll use to keep track of the phone's state
local camera = workspace.CurrentCamera --The player's camera

local function openphone()
	--This is the function we'll bind to contextactionservice and it should open the phone
	if open == false then --Checking if our phone is open; if not we will set the value to true and open it; else we will set the value to false and close it
		phonemain.Visible = true
		blur = Instance.new("BlurEffect") --We are creating our blur effect and parenting it to the camera
		blur.Parent = camera
		open = true
		phonemain.PhoneFrame.Apps.Visible = true --We'll make the apps and welcome screen visible
		phonemain.PhoneFrame.WelcomeTitle.Visible = true
		for index, v in pairs(phoneapps:GetDescendants()) do --We are looping through the gui's descendants and making them visible, once the phone "booted up", to achive a sort of lagging that is natural for most OS'es when powered on
			if not v:IsA("UICorner") then
				v.Visible = true
				wait(0.1)
			end
		end
	else
		phonemain.Visible = false
		blur:Destroy() --We are destroying our blur effect
		open = false
		phonemain.PhoneFrame.Apps.Visible = false --We'll make the apps and welcome screen invisible
		phonemain.PhoneFrame.WelcomeTitle.Visible = false 
		for index, v in pairs(phoneapps:GetDescendants()) do --We are looping through the gui's descendants and making them invisible, once the phone "shut down"
			if not v:IsA("UICorner") then
				v.Visible = false
			end
		end
	end
end

contextactionservice:BindAction("OpenPhone", openphone, false, Enum.KeyCode.Tab) --Binding the function to the key tab
--contextactionservice:UnbindAction("OpenPhone") --It's that simple, really. We used the name we gave to our action above to unbind it. You can unbind and bind at any time!

Step 3) Making the settings app.

Why a settings app? How is it helpful?
Well… What if your players wanted to change background like on a real phone? We’ll take care of that on our settings app!

In our local script, which we will use to handle most events (not necesarry, you can change this if you want), we will use a mouse click event to open the settings app. We will make a new frame inside the phone and open it when the button is clicked. Better get creative! This and the map app will serve as “Templates” for your own apps!

Here’s my current phone gui setup. I’ve added the settings app frame under the PhoneFrame: image

I’ve got two buttons in my settings interface, one for backgrounds and one for “System information”. The last one is purely cosmetic, I won’t use it.

Alright now that we’re set, hopefully, we can start coding the app.


3 Likes