Multiplayer

How can I make a multiplayer game in Easel?
In this example, we will create a simple "cursor party" multiplayer game where the people can dance around the screen together by shaking their mouse cursors. There will be some fireworks to celebrate the fact that now anyone can make a multiplayer game with Easel!
See Multiplayer for a broader overview of how multiplayer works in Easel.
Step 1: Set max players
To make your game multiplayer,
simply set the maxHumanPlayers parameter in your World.Main function to a number greater than 1.
pub game fn World.Main(maxHumanPlayers=10) {
// ...
}
Now your game is multiplayer and can support up to 10 players at once! From this point forward, you can pretend as if all your players are in one shared world, like a singleplayer game, and Easel will take care of the rest.
Step 2: Take an owner parameter
In our game, each player will have a Hero unit that they control with their mouse cursor.
Each Hero needs to know which player owns it so that it can follow the correct mouse cursor.
You can do this by taking an owner parameter in your Hero function:
pub fn unit.Hero([owner]) {
use body=this
Body(pos=Pointer) // Spawn at the mouse cursor of our `owner`
// ...
}
We put this in square brackets to indicate that the owner parameter is implicitly found from context.
You'll see how this works next.
Step 3: Spawn each player
Use the SpawnEachPlayer function to define what happens for each player in the game.
In our case, we are going to spawn a Hero unit for each player in the game.
Notice, this is also how the owner parameter, representing the player, is implicitly passed to the Hero function.
SpawnEachPlayer owner { // adds the `owner` to context for this block
Subspawn unit {
Hero // implicitly takes `owner` from context
}
}
We use Subspawn to spawn the Hero unit for each player so that if the player leaves the game,
their Hero will be automatically removed from the game as well.
Step 4: Display your Hero's name
Players want to know who they are playing with.
You can do this by adding a TextSprite to the Hero unit that displays the player's name, like this:
pub fn unit.Hero([owner]) {
// ...
TextSprite(PlayerName, radius=0.5, ownerColor=true, screenOffset=@(0, 0.75), strobe=false, vAlign=VAlign:Top)
}
Notice we also set ownerColor=true so that the text will be displayed in the player's color.
Easel automatically assigns a color to every player in the game, so that each player can be easily distinguished from one another.
See Player Colors for more information about how player colors work.
Step 5: Add some fireworks
We've made a multiplayer game. Let's celebrate with some fireworks!
on Tick(1s * Random) {
let pos = @(12*SignedRandom, 8*SignedRandom)
let color = PickRandom(FireworkColors)
repeat 10 {
Spark(
body=pos,
radius=0.03, color=,
luminous=1, bloom=1, glare=1, fade=1,
speed=4,
acceleration=@(0, 3),
dissipate=5s,
)
}
}
Full Code Listing
We've made a little party game where each player is dancing around the screen. Try the game out, invite your friends, or maybe just open it in multiple tabs to see what happens.
const FireworkColors = [ #f00, #0f0, #f80, #00f, #b0f ]
pub game fn World.Main(maxHumanPlayers=10) {
TopContent {
InsetPanel {
P { "Welcome to the cursor party!" }
}
}
BottomRightContent {
HStack(padding=1) {
RaisedButton(ShareIntent, backgroundColor=Color:Primary) { "Invite others to party!" }
}
}
Camera(@(0, 0), radius=8)
SolidBackground(color=#000008)
on Tick(1s * Random) {
let pos = @(12*SignedRandom, 8*SignedRandom)
let color = PickRandom(FireworkColors)
repeat 10 {
Spark(
body=pos,
radius=0.03, color=,
luminous=1, bloom=1, glare=1, fade=1,
speed=4,
acceleration=@(0, 3),
dissipate=5s,
)
}
}
SpawnEachPlayer owner {
Subspawn unit {
Hero
}
}
}
pub fn unit.Hero([owner]) {
use body=this
Body(pos=Pointer)
ImageSprite(image=@pointer.png, radius=1, ownerColor=true)
behavior {
loop {
Strobe(growth=0.1, rotate=-0.05rev, swell=0.45, dissipate=0.5s)
await Tick(0.5s)
Strobe(growth=0.1, rotate=0.05rev, swell=0.45, dissipate=0.5s)
await Tick(0.5s)
}
}
TextSprite(PlayerName, radius=0.25, ownerColor=true, screenOffset=@(0, 0.75), strobe=false, vAlign=VAlign:Top)
with BeforePhysics {
Move(0.1 * (Pointer - Pos))
}
}