Players can now collect coins and lose them when they die, but the coins don't do anything, and most of the 3D world is inaccessible without the ability to jump very high. This section of the tutorial teaches you how to finish the logic for your game by adding an on-screen button that spends coins to increase jumping power.
Create the upgrade button
2D interfaces in Roblox are typically made up of a collection of GUI components inside of a GUI container. In this case, you only need a TextButton component that says Upgrade Jump (5 Coins) inside a ScreenGui container.
Set up the upgrade GUIIn ReplicatedStorage, create a folder named Instances.Inside the Instances folder, create a ScreenGui named JumpPurchaseGui with ResetOnSpawn disabled.Inside JumpPurchaseGui, create a TextButton named JumpButton with the following properties:- Text: "Upgrade Jump (5 Coins)"- TextSize: 25- AnchorPoint: 1, 1- Position: {1, 0}, {1, 0}Also inside the Instances folder, create a RemoteFunction named IncreaseJumpPowerFunction.Finally, on the StarterPlayer service, enable the CharacterUseJumpPower property.
Define jump power data
Currently, only coin count is stored for each player in the PlayerData module script. You need to also store and update jump power in the same way. Because the functions in PlayerData are non-specific to the data being changed, all that's required to store player jump power is to add a Jump key and initialize its initial value in defaultPlayerData().
Update PlayerData with jump powerIn ServerStorage, replace the existing PlayerData ModuleScript's code with the following:```lualocal PlayerData = {}PlayerData.COIN_KEY_NAME = "Coins"PlayerData.JUMP_KEY_NAME = "Jump"local playerData = {--[[[userId: string] = {["Coins"] = coinAmount: number,["Jump"] = jumpPower: number}--]]}local function defaultPlayerData()return {[PlayerData.COIN_KEY_NAME] = 0,[PlayerData.JUMP_KEY_NAME] = 0,}endlocal function getData(player)local data = playerData[tostring(player.UserId)] or defaultPlayerData()playerData[tostring(player.UserId)] = datareturn dataendfunction PlayerData.getValue(player, key)return getData(player)[key]endfunction PlayerData.updateValue(player, key, updateFunction)local data = getData(player)local oldValue = data[key]local newValue = updateFunction(oldValue)data[key] = newValuereturn newValueendreturn PlayerData```
Update jump power data
Now that PlayerData is able to track jump power, you need to implement logic on the server to upgrade jump power from a player's client request.
The server and client can communicate through either RemoteEvents or RemoteFunctions. Remote events don't yield when they're fired and can be used for one-way communication. Remote functions, on the other hand, yield until they receive a reply, which allows for two-way communication.
For this tutorial, the client needs to know if the server upgraded the player's jump power successfully, so you should use a remote function.
Create JumpServiceIn ServerScriptService, create a Script named JumpService with the following code:```lua-- Serviceslocal ReplicatedStorage = game:GetService("ReplicatedStorage")local ServerStorage = game:GetService("ServerStorage")local Players = game:GetService("Players")-- Moduleslocal Leaderboard = require(ServerStorage.Leaderboard)local PlayerData = require(ServerStorage.PlayerData)-- Eventslocal IncreaseJumpPowerFunction = ReplicatedStorage.Instances.IncreaseJumpPowerFunctionlocal JUMP_KEY_NAME = PlayerData.JUMP_KEY_NAMElocal COIN_KEY_NAME = PlayerData.COIN_KEY_NAMElocal JUMP_POWER_INCREMENT = 30local JUMP_COIN_COST = 5local function updateJumpPower(player, updateFunction)-- Update the jump power tablelocal newJumpPower = PlayerData.updateValue(player, JUMP_KEY_NAME, updateFunction)-- Update the players jump powerlocal character = player.Character or player.CharacterAdded:Wait()local humanoid = character:FindFirstChildWhichIsA("Humanoid")if humanoid thenhumanoid.JumpPower = newJumpPower-- Update the jump leaderboardLeaderboard.setStat(player, JUMP_KEY_NAME, newJumpPower)endendlocal function onPurchaseJumpIncrease(player)local coinAmount = PlayerData.getValue(player, COIN_KEY_NAME)if coinAmount < JUMP_COIN_COST thenreturn falseend-- Increase player's jump powerupdateJumpPower(player, function(oldJumpPower)oldJumpPower = oldJumpPower or 0return oldJumpPower + JUMP_POWER_INCREMENTend)-- Update the coin tablelocal newCoinAmount = PlayerData.updateValue(player, COIN_KEY_NAME, function(oldCoinAmount)return oldCoinAmount - JUMP_COIN_COSTend)-- Update the coin leaderboardLeaderboard.setStat(player, COIN_KEY_NAME, newCoinAmount)return trueendlocal function onCharacterAdded(player)-- Reset player's jump power when the character is addedupdateJumpPower(player, function(_)return 0end)end-- Initialize any players added before connecting to PlayerAdded eventfor _, player in Players:GetPlayers() doonCharacterAdded(player)end-- Normal initialization of players from PlayerAdded eventlocal function onPlayerAdded(player)player.CharacterAdded:Connect(function()onCharacterAdded(player)end)endlocal function onPlayerRemoved(player)updateJumpPower(player, function(_)return nilend)endIncreaseJumpPowerFunction.OnServerInvoke = onPurchaseJumpIncreasePlayers.PlayerAdded:Connect(onPlayerAdded)Players.PlayerRemoving:Connect(onPlayerRemoved)```
The following sections describe the code in more detail.
Update the jump power data - updateJumpPower() updates the jump power of the player and the leaderboard to provide visual feedback. This function resembles the code that damages players in Create player hazards. Provided a Character model and Humanoid exist for the player being upgraded, the function updates the JumpPower property to the new value stored by PlayerData, increasing it by 30. If you want your game to last slightly longer, you can decrease this number.
Validate server requests - onPurchaseJumpIncrease() first checks that the player actually has the number of coins required to purchase the upgrade. All requests from clients to the server should be validated to prevent bad actors submitting false requests and exploiting your game.
Add the button to the player GUI
A ScreenGui object only shows on-screen if it is parented to a player's PlayerGui object. By default, this contains the system GUI such as the chat window. You now need to create a script in ReplicatedStorage to copy the upgrade button into each player's GUI and implement behavior for when the button is pressed.
Create JumpButtonClickHandlerIn ReplicatedStorage, create a Script named JumpButtonClickHandler with RunContext set to Client and the following code:```lualocal ReplicatedStorage = game:GetService("ReplicatedStorage")local Players = game:GetService("Players")local player = Players.LocalPlayerlocal playerGui = player.PlayerGuilocal IncreaseJumpPowerFunction = ReplicatedStorage.Instances.IncreaseJumpPowerFunctionlocal jumpPurchaseGui = ReplicatedStorage.Instances.JumpPurchaseGuilocal jumpButton = jumpPurchaseGui.JumpButtonlocal function onButtonClicked()local success, purchased = pcall(IncreaseJumpPowerFunction.InvokeServer, IncreaseJumpPowerFunction)if not success then-- purchased will be the error message if success is falseerror(purchased)elseif success and not purchased thenwarn("Not enough coins!")endendjumpButton.Activated:Connect(onButtonClicked)-- Add the JumpPurchaseGui to the player's GuijumpPurchaseGui.Parent = playerGui```
The following sections describe the code in more detail.
- Obtain references to the GUI and server function - The variables IncreaseJumpPowerFunction, jumpPurchaseGui, and jumpButton contain references to the function and GUI that calls the function that you'll need later.
- Define the event handler - onButtonClicked() defines logic for when users click the upgrade button. It uses pcall() (protected call) to invoke the RemoteFunction. Any client-server communication like this requires pcall() to handle errors or connection issues.
- Connect the handler to the button - The Activated event is compatible on all platforms, including mouse, touchscreen, or gamepad contexts. It triggers when a click, touch, or gamepad button is released.
Playtest
Select Test from the dropdown and click Play. The Upgrade Jump button shows up in the bottom-right corner.
Try clicking the button before you collect any coins to check that it doesn't award you additional jumping power, then try collecting some coins and see if the upgrade works when you click again.
With the code complete, try tuning the difficulty: add coins if the pace feels slow, or remove a few and tuck them in trickier spots if upgrades come too easily.