Custom scripts, NPCs and blocks may need some extra code in order to work properly online. This guide acts as a basic introduction to how to write scripts with the online system in mind.
For this example, we will demonstrate a basic script, and how to sync it online. We want a script that launches the player upwards and plays a sound effect when they press the drop item key.
Here is how you might do that in normal SMBX2:
function onTick()
if player.keys.dropItem == KEYS_PRESSED then
player.speedY = -20
SFX.play(43)
end
end
To make this work online, we must first address the lack of multiplayer compatibility:
function onTick()
for _,p in ipairs(Player.get()) do
if p.keys.dropItem == KEYS_PRESSED then
p.speedY = -20
SFX.play(43)
end
end
end
On its own, this probably works decently in online play. However, to reduce any possible weirdness, it's best to use a command to synchronise the event of a player launching. Here, we create the "launchPlayerCommand":
-- Gotta load the library!
local onlinePlay = require("scripts/onlinePlay")
-- Remember to give your command a unique enough name!
local launchPlayerCommand = onlinePlay.createCommand("launchPlayer",onlinePlay.IMPORTANCE_MAJOR)
-- The logic for launching the player has been moved into its own function.
-- This helps to reduce duplicate code.
local function launchPlayer(p)
p.speedY = -20
SFX.play(43)
end
-- When the command is received, it should call the launchPlayer function.
-- Note that, since player objects cannot be directly sent, a player index is used instead.
function launchPlayerCommand.onReceive(sourcePlayerIdx, playerIdx)
local p = Player(playerIdx)
launchPlayer(p)
end
function onTick()
for _,p in ipairs(Player.get()) do
if p.keys.dropItem == KEYS_PRESSED then
-- If online, send an event to everyone else
if onlinePlay.currentMode ~= onlinePlay.MODE_OFFLINE then
launchPlayerCommand:send(0,p.idx)
end
launchPlayer(p)
end
end
end
A lot changed very quickly here. The core of it is just that there is now a command that, when received, launches the player just like what would happen when a player presses drop item. We also send out this command when a player launches themselves. Now, the event of being launched is properly synced!
For the finishing touches, there are two other little changes to make. For one, we can still hear the sound effect even if the player is way off screen. We can fix this by using the onlinePlayPlayers.canMakeSound function. Just replace SFX.play(43) with the following (and don't forget to load the library!):
if onlinePlayPlayers.canMakeSound(p) then
SFX.play(43)
end
And finally, players other than the one we are controlling will actually be launched twice for just one button press. This is because we receive the event of them being launched, but we also launch them again since they're also registered as pressing drop item in onTick. To fix this, we can use the onlinePlayPlayers.ownsPlayer function. Replacing the p.keys.dropItem == KEYS_PRESSED line:
if p.keys.dropItem == KEYS_PRESSED and onlinePlayPlayers.ownsPlayer(p) then
And now our script works perfectly online! You can apply this same sort of system - one player sending a command, and everyone else listening for it - to just about anything you want to be synchronised online.
You can read the documentation linked above for more about individual systems.