mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 09:30:45 +00:00
Players on the same team get a distinct color based on the team color (#1297)
## Description: Instead of all teams having the same color, they get a different color. ### 2 teams  ### All teams  ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors ## Please put your Discord username so you can be contacted if a bug or regression is found: pineappleprince --------- Co-authored-by: Drills Kibo <59177241+drillskibo@users.noreply.github.com> Co-authored-by: Scott Anderson <662325+scottanderson@users.noreply.github.com>
This commit is contained in:
@@ -6,14 +6,14 @@ import { ColoredTeams, Team } from "../game/Game";
|
||||
import { PseudoRandom } from "../PseudoRandom";
|
||||
import { simpleHash } from "../Util";
|
||||
import {
|
||||
blue,
|
||||
botColor,
|
||||
green,
|
||||
orange,
|
||||
purple,
|
||||
red,
|
||||
teal,
|
||||
yellow,
|
||||
blueTeamColors,
|
||||
botTeamColors,
|
||||
greenTeamColors,
|
||||
orangeTeamColors,
|
||||
purpleTeamColors,
|
||||
redTeamColors,
|
||||
tealTeamColors,
|
||||
yellowTeamColors,
|
||||
} from "./Colors";
|
||||
extend([lchPlugin]);
|
||||
extend([labPlugin]);
|
||||
@@ -22,12 +22,36 @@ export class ColorAllocator {
|
||||
private availableColors: Colord[];
|
||||
private fallbackColors: Colord[];
|
||||
private assigned = new Map<string, Colord>();
|
||||
private teamPlayerColors = new Map<string, Colord>();
|
||||
|
||||
constructor(colors: Colord[], fallback: Colord[]) {
|
||||
this.availableColors = [...colors];
|
||||
this.fallbackColors = [...colors, ...fallback];
|
||||
}
|
||||
|
||||
private getTeamColorVariations(team: Team): Colord[] {
|
||||
switch (team) {
|
||||
case ColoredTeams.Blue:
|
||||
return blueTeamColors;
|
||||
case ColoredTeams.Red:
|
||||
return redTeamColors;
|
||||
case ColoredTeams.Teal:
|
||||
return tealTeamColors;
|
||||
case ColoredTeams.Purple:
|
||||
return purpleTeamColors;
|
||||
case ColoredTeams.Yellow:
|
||||
return yellowTeamColors;
|
||||
case ColoredTeams.Orange:
|
||||
return orangeTeamColors;
|
||||
case ColoredTeams.Green:
|
||||
return greenTeamColors;
|
||||
case ColoredTeams.Bot:
|
||||
return botTeamColors;
|
||||
default:
|
||||
throw new Error(`Unknown team color: ${team}`);
|
||||
}
|
||||
}
|
||||
|
||||
assignColor(id: string): Colord {
|
||||
if (this.assigned.has(id)) {
|
||||
return this.assigned.get(id)!;
|
||||
@@ -58,26 +82,23 @@ export class ColorAllocator {
|
||||
}
|
||||
|
||||
assignTeamColor(team: Team): Colord {
|
||||
switch (team) {
|
||||
case ColoredTeams.Blue:
|
||||
return blue;
|
||||
case ColoredTeams.Red:
|
||||
return red;
|
||||
case ColoredTeams.Teal:
|
||||
return teal;
|
||||
case ColoredTeams.Purple:
|
||||
return purple;
|
||||
case ColoredTeams.Yellow:
|
||||
return yellow;
|
||||
case ColoredTeams.Orange:
|
||||
return orange;
|
||||
case ColoredTeams.Green:
|
||||
return green;
|
||||
case ColoredTeams.Bot:
|
||||
return botColor;
|
||||
default:
|
||||
return this.assignColor(team);
|
||||
const teamColors = this.getTeamColorVariations(team);
|
||||
return teamColors[0];
|
||||
}
|
||||
|
||||
assignTeamPlayerColor(team: Team, playerId: string): Colord {
|
||||
if (this.teamPlayerColors.has(playerId)) {
|
||||
return this.teamPlayerColors.get(playerId)!;
|
||||
}
|
||||
|
||||
const teamColors = this.getTeamColorVariations(team);
|
||||
const hashValue = simpleHash(playerId);
|
||||
const colorIndex = hashValue % teamColors.length;
|
||||
const color = teamColors[colorIndex];
|
||||
|
||||
this.teamPlayerColors.set(playerId, color);
|
||||
|
||||
return color;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,45 @@
|
||||
import { colord, Colord, extend } from "colord";
|
||||
import labPlugin from "colord/plugins/lab";
|
||||
import lchPlugin from "colord/plugins/lch";
|
||||
|
||||
extend([lchPlugin]);
|
||||
extend([labPlugin]);
|
||||
|
||||
export const red: Colord = colord({ r: 235, g: 53, b: 53 }); // Bright Red
|
||||
export const blue: Colord = colord({ r: 41, g: 98, b: 255 }); // Royal Blue
|
||||
export const red = colord({ h: 0, s: 82, l: 56 });
|
||||
export const blue = colord({ h: 224, s: 100, l: 58 });
|
||||
export const teal = colord({ h: 172, s: 66, l: 50 });
|
||||
export const purple = colord({ h: 271, s: 81, l: 56 });
|
||||
export const yellow = colord({ h: 45, s: 93, l: 47 });
|
||||
export const orange = colord({ h: 25, s: 95, l: 53 });
|
||||
export const green = colord({ h: 128, s: 49, l: 50 });
|
||||
export const botColor: Colord = colord({ r: 210, g: 206, b: 200 }); // Muted Beige Gray
|
||||
export const botColor = colord({ h: 36, s: 10, l: 80 });
|
||||
|
||||
export const redTeamColors: Colord[] = generateTeamColors(red);
|
||||
export const blueTeamColors: Colord[] = generateTeamColors(blue);
|
||||
export const tealTeamColors: Colord[] = generateTeamColors(teal);
|
||||
export const purpleTeamColors: Colord[] = generateTeamColors(purple);
|
||||
export const yellowTeamColors: Colord[] = generateTeamColors(yellow);
|
||||
export const orangeTeamColors: Colord[] = generateTeamColors(orange);
|
||||
export const greenTeamColors: Colord[] = generateTeamColors(green);
|
||||
export const botTeamColors: Colord[] = [colord(botColor)];
|
||||
|
||||
function generateTeamColors(baseColor: Colord): Colord[] {
|
||||
const { h: baseHue, s: baseSaturation, l: baseLightness } = baseColor.toHsl();
|
||||
const colorCount = 64;
|
||||
|
||||
return Array.from({ length: colorCount }, (_, index) => {
|
||||
const progression = index / (colorCount - 1);
|
||||
|
||||
const saturation = baseSaturation * (1.0 - 0.3 * progression);
|
||||
const lightness = Math.min(100, baseLightness + progression * 30);
|
||||
|
||||
return colord({
|
||||
h: baseHue,
|
||||
s: saturation,
|
||||
l: lightness,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export const nationColors: Colord[] = [
|
||||
colord({ r: 230, g: 100, b: 100 }), // Bright Red
|
||||
|
||||
@@ -42,7 +42,7 @@ export class PastelTheme implements Theme {
|
||||
territoryColor(player: PlayerView): Colord {
|
||||
const team = player.team();
|
||||
if (team !== null) {
|
||||
return this.teamColor(team);
|
||||
return this.teamColorAllocator.assignTeamPlayerColor(team, player.id());
|
||||
}
|
||||
if (player.type() === PlayerType.Human) {
|
||||
return this.humanColorAllocator.assignColor(player.id());
|
||||
|
||||
@@ -42,7 +42,7 @@ export class PastelThemeDark implements Theme {
|
||||
territoryColor(player: PlayerView): Colord {
|
||||
const team = player.team();
|
||||
if (team !== null) {
|
||||
return this.teamColor(team);
|
||||
return this.teamColorAllocator.assignTeamPlayerColor(team, player.id());
|
||||
}
|
||||
if (player.type() === PlayerType.Human) {
|
||||
return this.humanColorAllocator.assignColor(player.id());
|
||||
|
||||
+68
-2
@@ -3,7 +3,16 @@ import {
|
||||
ColorAllocator,
|
||||
selectDistinctColorIndex,
|
||||
} from "../src/core/configuration/ColorAllocator";
|
||||
import { blue, botColor, red, teal } from "../src/core/configuration/Colors";
|
||||
import {
|
||||
blue,
|
||||
botColor,
|
||||
green,
|
||||
orange,
|
||||
purple,
|
||||
red,
|
||||
teal,
|
||||
yellow,
|
||||
} from "../src/core/configuration/Colors";
|
||||
import { ColoredTeams } from "../src/core/game/Game";
|
||||
|
||||
const mockColors: Colord[] = [
|
||||
@@ -72,12 +81,69 @@ describe("ColorAllocator", () => {
|
||||
expect(c2.isEqual(c2Again)).toBe(true);
|
||||
});
|
||||
|
||||
test("assignTeamColor returns the expected static color for known teams", () => {
|
||||
test("assignTeamColor returns the base color from the team", () => {
|
||||
expect(allocator.assignTeamColor(ColoredTeams.Blue)).toEqual(blue);
|
||||
expect(allocator.assignTeamColor(ColoredTeams.Red)).toEqual(red);
|
||||
expect(allocator.assignTeamColor(ColoredTeams.Teal)).toEqual(teal);
|
||||
expect(allocator.assignTeamColor(ColoredTeams.Purple)).toEqual(purple);
|
||||
expect(allocator.assignTeamColor(ColoredTeams.Yellow)).toEqual(yellow);
|
||||
expect(allocator.assignTeamColor(ColoredTeams.Orange)).toEqual(orange);
|
||||
expect(allocator.assignTeamColor(ColoredTeams.Green)).toEqual(green);
|
||||
expect(allocator.assignTeamColor(ColoredTeams.Bot)).toEqual(botColor);
|
||||
});
|
||||
|
||||
test("assignTeamPlayerColor always returns the same color for the same playerID", () => {
|
||||
const playerId = "player123";
|
||||
|
||||
const blueColor1 = allocator.assignTeamPlayerColor(
|
||||
ColoredTeams.Blue,
|
||||
playerId,
|
||||
);
|
||||
const blueColor2 = allocator.assignTeamPlayerColor(
|
||||
ColoredTeams.Blue,
|
||||
playerId,
|
||||
);
|
||||
|
||||
expect(blueColor1.isEqual(blueColor2)).toBe(true);
|
||||
|
||||
const redColor1 = allocator.assignTeamPlayerColor(
|
||||
ColoredTeams.Red,
|
||||
playerId,
|
||||
);
|
||||
const redColor2 = allocator.assignTeamPlayerColor(
|
||||
ColoredTeams.Red,
|
||||
playerId,
|
||||
);
|
||||
|
||||
expect(redColor1.isEqual(redColor2)).toBe(true);
|
||||
});
|
||||
|
||||
test("assignTeamPlayerColor returns a different color when the playerID is different", () => {
|
||||
const playerIdOne = "player1";
|
||||
const playerIdTwo = "player2";
|
||||
|
||||
const blueColorPlayerOne = allocator.assignTeamPlayerColor(
|
||||
ColoredTeams.Blue,
|
||||
playerIdOne,
|
||||
);
|
||||
const blueColorPlayerTwo = allocator.assignTeamPlayerColor(
|
||||
ColoredTeams.Blue,
|
||||
playerIdTwo,
|
||||
);
|
||||
|
||||
expect(blueColorPlayerOne.isEqual(blueColorPlayerTwo)).toBe(false);
|
||||
|
||||
const redColorPlayerOne = allocator.assignTeamPlayerColor(
|
||||
ColoredTeams.Red,
|
||||
playerIdOne,
|
||||
);
|
||||
const redColorPlayerTwo = allocator.assignTeamPlayerColor(
|
||||
ColoredTeams.Red,
|
||||
playerIdTwo,
|
||||
);
|
||||
|
||||
expect(redColorPlayerOne.isEqual(redColorPlayerTwo)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("selectDistinctColor", () => {
|
||||
|
||||
Reference in New Issue
Block a user