Skip to main content

Player Colors

In Easel, every player has a color. Sprites can be tinted with the player's color, and every chat message is also tinted with the player's color. This helps players quickly recognize who is on their team and who is not.

Manual Colors

In some games, you want every player to have a consistent color regardless of who is observing them. In an RTS like StarCraft or Age of Empires, when a player says "let's go attack Red's base now", the team Red must mean the same thing to everyone.

In this case, you can assign the player color as part of your game logic.

Manually Assign Colors to Individual Players

For example, you could always assign a color from a predefined list whenever a player joins:

pub game fn World.Main(maxHumanPlayers=4) {
SpawnEachPlayer owner {
PlayerColor = ChooseLeastFrequentPlayerColor
Print(audience=Audience:All) {
P {
PlayerNameDisplay
" has entered the game"
}
}
}
}

pub const PlayerColors = [#ff0000, #0000ff, #00ff00, #ffff00] // red, blue, green, yellow
fn ChooseLeastFrequentPlayerColor() -> color {
let frequencies = {}
for player in QueryPlayers {
frequencies[player.PlayerColor] += 1
}

return PlayerColors.MinBy(|color| frequencies[color] ?? 0)
}
  • In this example, we have a predefined list of colors in PlayerColors.
  • Whenever a player joins, we assign them the color that is currently used by the fewest number of players. The reason we do this is that players can leave and join before the game starts, so you may want the ability to reuse colors that have been freed up by players who have left.

Manually Assign Colors to Teams

Or if you have two fixed teams, you could assign each team a color, then assign a player to a team when they join so they automatically inherit that team's color:

pub const Team1 = Spawn team {
team.PlayerColor = #ff0000
}
pub const Team2 = Spawn team {
team.PlayerColor = #0000ff
}
pub const Teams = [Team1, Team2] // put the teams in an array for easy access

pub game fn World.Main(maxHumanPlayers=10) {
SpawnEachPlayer owner {
Team = Teams.MinBy(|team| CountPlayers(team=))
Subspawn hero {
Hero
}
}
}

See the PlayerColor property of teams to learn more.

Automatic Colors

In some MOBA games like League of Legends, the player always sees themselves as team blue, and their opponents as team red. This helps them quickly recognize themselves in the heat of battle, rather than having to re-learn their team color every game.

To achieve this, configure your player colors in the easel.toml file like this:

[players]
selfColor = "#0000ff" # blue for yourself
colors = ["#ff0000"] # red for your opponents

Or you can have more than one opponent color if you want to support more than one opposing team:

[players]
selfColor = "#0000ff" # blue for yourself
allyColor = "#33bbdd" # if you like, include a different shade of blue for allies
colors = ["#f58c81", "#b69cf6", "#54c794", "#e09f47", "#e08747", "#e58cc5", "#a9b852", "#6eb2fd"]

See the Player Colors section of the [players] configuration to learn more.

warning

When using Automatic Colors, the PlayerColor property of players and teams will return undefined as there is no single color which it can return which is true for all observers. The color is only known at render time and not available to the game logic.

Default Colors

By default, Easel uses Automatic Colors. It comes with a list of 8 default colors, and also has a separate selfColor which defaults to a bright cyan color that lets the player recognize themselves.

You can choose to override this by using either the Manual Colors or Automatic Colors method, described above.

Tinting Sprites

You can tint a sprite with the team color by setting ownerColor=true parameter.

pub game fn World.Main(maxHumanPlayers=10) {
SpawnEachPlayer owner {
Subspawn hero {
use body=hero, radius=1
Body(pos=@(0,0))
PolygonSprite(Equilateral(numPoints=3), ownerColor=true) // will be tinted with the team color
}
}
}

It is better to use this method rather than using the PlayerColor property because:

  • It allows you to delegate the work of tinting the sprite to the renderer, which is better for performance
  • It still works even when using Automatic Colors and the player color is not known to the game logic