mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 09:30:45 +00:00
Add new icon shapes and filter for filtering icons on the layer (#1348)
## Description: Add triangle shape for missile silos, square for sam, octagon for defense posts, and add a filter in the topbar to highlight structures   ## 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: Vivacious Box
This commit is contained in:
Generated
+19
@@ -49,6 +49,7 @@
|
||||
"nanoid": "^3.3.6",
|
||||
"obscenity": "^0.4.3",
|
||||
"pg": "^8.13.3",
|
||||
"pixi-filters": "^6.1.3",
|
||||
"pixi.js": "^8.10.1",
|
||||
"prom-client": "^15.1.3",
|
||||
"protobufjs": "^7.3.2",
|
||||
@@ -9371,6 +9372,12 @@
|
||||
"integrity": "sha512-40um9QqwHjRS92qnOaDpL7RmDK15NuZYo9HihiJRbYkMQZlWnuH8AdvbMy8/o6lgLmKbDUKa+OALCltHdbOTpQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/gradient-parser": {
|
||||
"version": "0.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/gradient-parser/-/gradient-parser-0.1.5.tgz",
|
||||
"integrity": "sha512-r7K3NkJz3A95WkVVmjs0NcchhHstC2C/VIYNX4JC6tieviUNo774FFeOHjThr3Vw/WCeMP9kAT77MKbIRlO/4w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/hammerjs": {
|
||||
"version": "2.0.46",
|
||||
"resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.46.tgz",
|
||||
@@ -19609,6 +19616,18 @@
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pixi-filters": {
|
||||
"version": "6.1.3",
|
||||
"resolved": "https://registry.npmjs.org/pixi-filters/-/pixi-filters-6.1.3.tgz",
|
||||
"integrity": "sha512-bmdI2Ytz+z/NcADkjew2phKq300aQ9p9nVx9OfkMNuoYEl4gW99ZDNQZfsF834V/jj3CKTsIV4jxA+BI45UYOQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/gradient-parser": "^0.1.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"pixi.js": ">=8.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/pixi.js": {
|
||||
"version": "8.10.1",
|
||||
"resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-8.10.1.tgz",
|
||||
|
||||
@@ -123,6 +123,7 @@
|
||||
"nanoid": "^3.3.6",
|
||||
"obscenity": "^0.4.3",
|
||||
"pg": "^8.13.3",
|
||||
"pixi-filters": "^6.1.3",
|
||||
"pixi.js": "^8.10.1",
|
||||
"prom-client": "^15.1.3",
|
||||
"protobufjs": "^7.3.2",
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 238 B After Width: | Height: | Size: 224 B |
@@ -1,4 +1,5 @@
|
||||
import { EventBus, GameEvent } from "../core/EventBus";
|
||||
import { UnitType } from "../core/game/Game";
|
||||
import { UnitView } from "../core/game/GameView";
|
||||
import { UserSettings } from "../core/game/UserSettings";
|
||||
import { ReplaySpeedMultiplier } from "./utilities/ReplaySpeedMultiplier";
|
||||
@@ -64,6 +65,10 @@ export class CloseViewEvent implements GameEvent {}
|
||||
|
||||
export class RefreshGraphicsEvent implements GameEvent {}
|
||||
|
||||
export class ToggleStructureEvent implements GameEvent {
|
||||
constructor(public readonly structureType: UnitType | null) {}
|
||||
}
|
||||
|
||||
export class ShowBuildMenuEvent implements GameEvent {
|
||||
constructor(
|
||||
public readonly x: number,
|
||||
|
||||
@@ -217,7 +217,7 @@ export function createRenderer(
|
||||
new TerritoryLayer(game, eventBus, transformHandler, userSettings),
|
||||
new RailroadLayer(game),
|
||||
structureLayer,
|
||||
new StructureIconsLayer(game, transformHandler),
|
||||
new StructureIconsLayer(game, eventBus, transformHandler),
|
||||
new UnitLayer(game, eventBus, transformHandler),
|
||||
new FxLayer(game),
|
||||
new UILayer(game, eventBus, transformHandler),
|
||||
|
||||
@@ -24,7 +24,11 @@ import { UnitType } from "../../../core/game/Game";
|
||||
import { GameUpdateType } from "../../../core/game/GameUpdates";
|
||||
import { GameView } from "../../../core/game/GameView";
|
||||
import { UserSettings } from "../../../core/game/UserSettings";
|
||||
import { AlternateViewEvent, RefreshGraphicsEvent } from "../../InputHandler";
|
||||
import {
|
||||
AlternateViewEvent,
|
||||
RefreshGraphicsEvent,
|
||||
ToggleStructureEvent,
|
||||
} from "../../InputHandler";
|
||||
import { renderNumber, renderTroops } from "../../Utils";
|
||||
import { Layer } from "./Layer";
|
||||
|
||||
@@ -33,6 +37,7 @@ export class GameTopBar extends LitElement implements Layer {
|
||||
public game: GameView;
|
||||
public eventBus: EventBus;
|
||||
private _userSettings: UserSettings = new UserSettings();
|
||||
private _selectedStructure: UnitType | null = null;
|
||||
private _population = 0;
|
||||
private _troops = 0;
|
||||
private _cities = 0;
|
||||
@@ -140,6 +145,12 @@ export class GameTopBar extends LitElement implements Layer {
|
||||
this.eventBus.emit(new RefreshGraphicsEvent());
|
||||
}
|
||||
|
||||
private onToggleStructureClick(structureType: UnitType) {
|
||||
this._selectedStructure =
|
||||
this._selectedStructure === structureType ? null : structureType;
|
||||
this.eventBus.emit(new ToggleStructureEvent(this._selectedStructure));
|
||||
}
|
||||
|
||||
private onToggleRandomNameModeButtonClick() {
|
||||
this._userSettings.toggleRandomName();
|
||||
}
|
||||
@@ -280,9 +291,19 @@ export class GameTopBar extends LitElement implements Layer {
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="grid grid-rows-1 auto-cols-max grid-flow-col gap-1 bg-slate-800/20 border border-slate-400 p-0.5 md:px-1 lg:px-2 md:gap-2"
|
||||
class="grid grid-rows-1 auto-cols-max grid-flow-col bg-slate-800/20 border border-slate-400 p-0.5 md:px-1 lg:px-2"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
class="md:px-2 px-1 flex items-center gap-2"
|
||||
style="background: ${this._selectedStructure ===
|
||||
UnitType.City
|
||||
? "#ffffff2e"
|
||||
: "none"}"
|
||||
@mouseenter="${() =>
|
||||
this.onToggleStructureClick(UnitType.City)}"
|
||||
@mouseleave="${() =>
|
||||
this.onToggleStructureClick(UnitType.City)}"
|
||||
>
|
||||
<img
|
||||
src=${cityIcon}
|
||||
alt="gold"
|
||||
@@ -292,7 +313,17 @@ export class GameTopBar extends LitElement implements Layer {
|
||||
/>
|
||||
${renderNumber(this._cities)}
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
class="md:px-2 px-1 flex items-center gap-2"
|
||||
style="background: ${this._selectedStructure ===
|
||||
UnitType.Factory
|
||||
? "#ffffff2e"
|
||||
: "none"}"
|
||||
@mouseenter="${() =>
|
||||
this.onToggleStructureClick(UnitType.Factory)}"
|
||||
@mouseleave="${() =>
|
||||
this.onToggleStructureClick(UnitType.Factory)}"
|
||||
>
|
||||
<img
|
||||
src=${factoryIcon}
|
||||
alt="gold"
|
||||
@@ -302,7 +333,17 @@ export class GameTopBar extends LitElement implements Layer {
|
||||
/>
|
||||
${renderNumber(this._factories)}
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
class="md:px-2 px-1 flex items-center gap-2"
|
||||
style="background: ${this._selectedStructure ===
|
||||
UnitType.Port
|
||||
? "#ffffff2e"
|
||||
: "none"}"
|
||||
@mouseenter="${() =>
|
||||
this.onToggleStructureClick(UnitType.Port)}"
|
||||
@mouseleave="${() =>
|
||||
this.onToggleStructureClick(UnitType.Port)}"
|
||||
>
|
||||
<img
|
||||
src=${portIcon}
|
||||
alt="gold"
|
||||
@@ -312,7 +353,17 @@ export class GameTopBar extends LitElement implements Layer {
|
||||
/>
|
||||
${renderNumber(this._port)}
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
class="md:px-2 px-1 flex items-center gap-2"
|
||||
style="background: ${this._selectedStructure ===
|
||||
UnitType.DefensePost
|
||||
? "#ffffff2e"
|
||||
: "none"}"
|
||||
@mouseenter="${() =>
|
||||
this.onToggleStructureClick(UnitType.DefensePost)}"
|
||||
@mouseleave="${() =>
|
||||
this.onToggleStructureClick(UnitType.DefensePost)}"
|
||||
>
|
||||
<img
|
||||
src=${defensePostIcon}
|
||||
alt="gold"
|
||||
@@ -322,7 +373,17 @@ export class GameTopBar extends LitElement implements Layer {
|
||||
/>
|
||||
${renderNumber(this._defensePost)}
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
class="md:px-2 px-1 flex items-center gap-2"
|
||||
style="background: ${this._selectedStructure ===
|
||||
UnitType.MissileSilo
|
||||
? "#ffffff2e"
|
||||
: "none"}"
|
||||
@mouseenter="${() =>
|
||||
this.onToggleStructureClick(UnitType.MissileSilo)}"
|
||||
@mouseleave="${() =>
|
||||
this.onToggleStructureClick(UnitType.MissileSilo)}"
|
||||
>
|
||||
<img
|
||||
src=${missileSiloIcon}
|
||||
alt="gold"
|
||||
@@ -332,7 +393,17 @@ export class GameTopBar extends LitElement implements Layer {
|
||||
/>
|
||||
${renderNumber(this._missileSilo)}
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
class="md:px-2 px-1 flex items-center gap-2"
|
||||
style="background: ${this._selectedStructure ===
|
||||
UnitType.SAMLauncher
|
||||
? "#ffffff2e"
|
||||
: "none"}"
|
||||
@mouseenter="${() =>
|
||||
this.onToggleStructureClick(UnitType.SAMLauncher)}"
|
||||
@mouseleave="${() =>
|
||||
this.onToggleStructureClick(UnitType.SAMLauncher)}"
|
||||
>
|
||||
<img
|
||||
src=${samLauncherIcon}
|
||||
alt="gold"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { OutlineFilter } from "pixi-filters";
|
||||
import * as PIXI from "pixi.js";
|
||||
import bitmapFont from "../../../../resources/fonts/round_6x6_modified.xml";
|
||||
import anchorIcon from "../../../../resources/images/AnchorIcon.png";
|
||||
@@ -7,12 +8,16 @@ import missileSiloIcon from "../../../../resources/images/MissileSiloUnit.png";
|
||||
import SAMMissileIcon from "../../../../resources/images/SamLauncherUnit.png";
|
||||
import shieldIcon from "../../../../resources/images/ShieldIcon.png";
|
||||
import { Theme } from "../../../core/configuration/Config";
|
||||
import { EventBus } from "../../../core/EventBus";
|
||||
import { Cell, PlayerID, UnitType } from "../../../core/game/Game";
|
||||
import { GameUpdateType } from "../../../core/game/GameUpdates";
|
||||
import { GameView, UnitView } from "../../../core/game/GameView";
|
||||
import { GameView, PlayerView, UnitView } from "../../../core/game/GameView";
|
||||
import { ToggleStructureEvent } from "../../InputHandler";
|
||||
import { TransformHandler } from "../TransformHandler";
|
||||
import { Layer } from "./Layer";
|
||||
|
||||
type ShapeType = "triangle" | "square" | "octagon" | "circle";
|
||||
|
||||
class StructureRenderInfo {
|
||||
public isOnScreen: boolean = false;
|
||||
constructor(
|
||||
@@ -24,7 +29,16 @@ class StructureRenderInfo {
|
||||
public underConstruction: boolean = true,
|
||||
) {}
|
||||
}
|
||||
const ZOOM_THRESHOLD = 2.5;
|
||||
|
||||
const STRUCTURE_SHAPES: Partial<Record<UnitType, ShapeType>> = {
|
||||
[UnitType.City]: "circle",
|
||||
[UnitType.Port]: "circle",
|
||||
[UnitType.Factory]: "circle",
|
||||
[UnitType.DefensePost]: "octagon",
|
||||
[UnitType.SAMLauncher]: "square",
|
||||
[UnitType.MissileSilo]: "triangle",
|
||||
};
|
||||
const ZOOM_THRESHOLD = 3.5;
|
||||
const ICON_SIZE = 24;
|
||||
const OFFSET_ZOOM_Y = 5; // offset for the y position of the icon to avoid hiding the structure beneath
|
||||
|
||||
@@ -40,18 +54,28 @@ export class StructureIconsLayer implements Layer {
|
||||
private seenUnits: Set<UnitView> = new Set();
|
||||
private structures: Map<
|
||||
UnitType,
|
||||
{ iconPath: string; image: HTMLImageElement | null }
|
||||
{ visible: boolean; iconPath: string; image: HTMLImageElement | null }
|
||||
> = new Map([
|
||||
[UnitType.City, { iconPath: cityIcon, image: null }],
|
||||
[UnitType.Factory, { iconPath: factoryIcon, image: null }],
|
||||
[UnitType.DefensePost, { iconPath: shieldIcon, image: null }],
|
||||
[UnitType.Port, { iconPath: anchorIcon, image: null }],
|
||||
[UnitType.MissileSilo, { iconPath: missileSiloIcon, image: null }],
|
||||
[UnitType.SAMLauncher, { iconPath: SAMMissileIcon, image: null }],
|
||||
[UnitType.City, { visible: true, iconPath: cityIcon, image: null }],
|
||||
[UnitType.Factory, { visible: true, iconPath: factoryIcon, image: null }],
|
||||
[
|
||||
UnitType.DefensePost,
|
||||
{ visible: true, iconPath: shieldIcon, image: null },
|
||||
],
|
||||
[UnitType.Port, { visible: true, iconPath: anchorIcon, image: null }],
|
||||
[
|
||||
UnitType.MissileSilo,
|
||||
{ visible: true, iconPath: missileSiloIcon, image: null },
|
||||
],
|
||||
[
|
||||
UnitType.SAMLauncher,
|
||||
{ visible: true, iconPath: SAMMissileIcon, image: null },
|
||||
],
|
||||
]);
|
||||
|
||||
constructor(
|
||||
private game: GameView,
|
||||
private eventBus: EventBus,
|
||||
private transformHandler: TransformHandler,
|
||||
) {
|
||||
this.theme = game.config().theme();
|
||||
@@ -114,6 +138,9 @@ export class StructureIconsLayer implements Layer {
|
||||
}
|
||||
|
||||
async init() {
|
||||
this.eventBus.on(ToggleStructureEvent, (e) =>
|
||||
this.toggleStructure(e.structureType),
|
||||
);
|
||||
window.addEventListener("resize", () => this.resizeCanvas());
|
||||
await this.setupRenderer();
|
||||
this.redraw();
|
||||
@@ -143,6 +170,17 @@ export class StructureIconsLayer implements Layer {
|
||||
});
|
||||
}
|
||||
|
||||
private toggleStructure(toggleStructureType: UnitType | null): void {
|
||||
for (const [structureType, infos] of this.structures) {
|
||||
infos.visible =
|
||||
structureType === toggleStructureType || toggleStructureType === null;
|
||||
}
|
||||
for (const render of this.renders) {
|
||||
this.modifyVisibility(render);
|
||||
}
|
||||
this.shouldRedraw = true;
|
||||
}
|
||||
|
||||
private findRenderByUnit(
|
||||
unitView: UnitView,
|
||||
): StructureRenderInfo | undefined {
|
||||
@@ -173,6 +211,32 @@ export class StructureIconsLayer implements Layer {
|
||||
}
|
||||
}
|
||||
|
||||
private modifyVisibility(render: StructureRenderInfo) {
|
||||
const structureType =
|
||||
render.unit.type() === UnitType.Construction
|
||||
? render.unit.constructionType()!
|
||||
: render.unit.type();
|
||||
const structureInfos = this.structures.get(structureType);
|
||||
|
||||
let focusStructure = false;
|
||||
for (const infos of this.structures.values()) {
|
||||
if (infos.visible === false) {
|
||||
focusStructure = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (structureInfos) {
|
||||
render.iconContainer.alpha = structureInfos.visible ? 1 : 0.3;
|
||||
if (structureInfos.visible && focusStructure) {
|
||||
render.iconContainer.filters = [
|
||||
new OutlineFilter({ thickness: 2, color: "rgb(255, 255, 255)" }),
|
||||
];
|
||||
} else {
|
||||
render.iconContainer.filters = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private checkForConstructionState(
|
||||
render: StructureRenderInfo,
|
||||
unit: UnitView,
|
||||
@@ -184,6 +248,7 @@ export class StructureIconsLayer implements Layer {
|
||||
render.underConstruction = false;
|
||||
render.iconContainer?.destroy();
|
||||
render.iconContainer = this.createIconSprite(unit);
|
||||
this.modifyVisibility(render);
|
||||
this.shouldRedraw = true;
|
||||
}
|
||||
}
|
||||
@@ -193,6 +258,7 @@ export class StructureIconsLayer implements Layer {
|
||||
render.owner = unit.owner().id();
|
||||
render.iconContainer?.destroy();
|
||||
render.iconContainer = this.createIconSprite(unit);
|
||||
this.modifyVisibility(render);
|
||||
this.shouldRedraw = true;
|
||||
}
|
||||
}
|
||||
@@ -204,6 +270,7 @@ export class StructureIconsLayer implements Layer {
|
||||
render.levelContainer?.destroy();
|
||||
render.iconContainer = this.createIconSprite(unit);
|
||||
render.levelContainer = this.createLevelSprite(unit);
|
||||
this.modifyVisibility(render);
|
||||
this.shouldRedraw = true;
|
||||
}
|
||||
}
|
||||
@@ -251,6 +318,21 @@ export class StructureIconsLayer implements Layer {
|
||||
return this.textureCache.get(cacheKey)!;
|
||||
}
|
||||
|
||||
const shape = STRUCTURE_SHAPES[structureType];
|
||||
const texture = shape
|
||||
? this.createIcon(unit.owner(), structureType, isConstruction, shape)
|
||||
: PIXI.Texture.EMPTY;
|
||||
|
||||
this.textureCache.set(cacheKey, texture);
|
||||
return texture;
|
||||
}
|
||||
|
||||
private createIcon(
|
||||
owner: PlayerView,
|
||||
structureType: UnitType,
|
||||
isConstruction: boolean,
|
||||
shape: "triangle" | "square" | "octagon" | "circle",
|
||||
) {
|
||||
const structureCanvas = document.createElement("canvas");
|
||||
structureCanvas.width = ICON_SIZE;
|
||||
structureCanvas.height = ICON_SIZE;
|
||||
@@ -262,39 +344,93 @@ export class StructureIconsLayer implements Layer {
|
||||
borderColor = "rgb(128, 127, 127)";
|
||||
} else {
|
||||
context.fillStyle = this.theme
|
||||
.territoryColor(unit.owner())
|
||||
.territoryColor(owner)
|
||||
.lighten(0.06)
|
||||
.toRgbString();
|
||||
borderColor = this.theme
|
||||
.borderColor(unit.owner())
|
||||
.darken(0.08)
|
||||
.toRgbString();
|
||||
borderColor = this.theme.borderColor(owner).darken(0.08).toRgbString();
|
||||
}
|
||||
|
||||
context.strokeStyle = borderColor;
|
||||
context.beginPath();
|
||||
context.arc(
|
||||
ICON_SIZE / 2,
|
||||
ICON_SIZE / 2,
|
||||
ICON_SIZE / 2 - 1,
|
||||
0,
|
||||
Math.PI * 2,
|
||||
);
|
||||
context.fill();
|
||||
context.lineWidth = 1;
|
||||
context.stroke();
|
||||
|
||||
switch (shape) {
|
||||
case "triangle":
|
||||
context.beginPath();
|
||||
context.moveTo(ICON_SIZE / 2, 0); // Top
|
||||
context.lineTo(ICON_SIZE, ICON_SIZE); // Bottom right
|
||||
context.lineTo(0, ICON_SIZE); // Bottom left
|
||||
context.closePath();
|
||||
context.fill();
|
||||
context.stroke();
|
||||
break;
|
||||
|
||||
case "square":
|
||||
context.fillRect(0, 0, ICON_SIZE - 2, ICON_SIZE - 2);
|
||||
context.strokeRect(0.5, 0.5, ICON_SIZE - 3, ICON_SIZE - 3);
|
||||
break;
|
||||
|
||||
case "octagon":
|
||||
{
|
||||
const cx = ICON_SIZE / 2;
|
||||
const cy = ICON_SIZE / 2;
|
||||
const r = ICON_SIZE / 2 - 1;
|
||||
const step = (Math.PI * 2) / 8;
|
||||
|
||||
context.beginPath();
|
||||
for (let i = 0; i < 8; i++) {
|
||||
const angle = step * i - Math.PI / 8; // slight rotation for flat top
|
||||
const x = cx + r * Math.cos(angle);
|
||||
const y = cy + r * Math.sin(angle);
|
||||
if (i === 0) {
|
||||
context.moveTo(x, y);
|
||||
} else {
|
||||
context.lineTo(x, y);
|
||||
}
|
||||
}
|
||||
context.closePath();
|
||||
context.fill();
|
||||
context.stroke();
|
||||
}
|
||||
break;
|
||||
|
||||
case "circle":
|
||||
context.beginPath();
|
||||
context.arc(
|
||||
ICON_SIZE / 2,
|
||||
ICON_SIZE / 2,
|
||||
ICON_SIZE / 2 - 1,
|
||||
0,
|
||||
Math.PI * 2,
|
||||
);
|
||||
context.fill();
|
||||
context.stroke();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown shape: ${shape}`);
|
||||
}
|
||||
|
||||
const structureInfo = this.structures.get(structureType);
|
||||
if (!structureInfo?.image) {
|
||||
console.warn(`Image not loaded for unit type: ${structureType}`);
|
||||
return PIXI.Texture.from(structureCanvas);
|
||||
}
|
||||
|
||||
const SHAPE_OFFSETS = {
|
||||
triangle: [4, 8],
|
||||
square: [3, 3],
|
||||
octagon: [4, 4],
|
||||
circle: [4, 4],
|
||||
};
|
||||
const [offsetX, offsetY] = SHAPE_OFFSETS[shape] || [0, 0];
|
||||
|
||||
context.drawImage(
|
||||
this.getImageColored(structureInfo.image, borderColor),
|
||||
4,
|
||||
4,
|
||||
offsetX,
|
||||
offsetY,
|
||||
);
|
||||
const texture = PIXI.Texture.from(structureCanvas);
|
||||
this.textureCache.set(cacheKey, texture);
|
||||
return texture;
|
||||
|
||||
return PIXI.Texture.from(structureCanvas);
|
||||
}
|
||||
|
||||
private createLevelSprite(unit: UnitView): PIXI.Container {
|
||||
@@ -423,19 +559,14 @@ export class StructureIconsLayer implements Layer {
|
||||
const render = new StructureRenderInfo(
|
||||
unitView,
|
||||
unitView.owner().id(),
|
||||
this.createUnitContainer(unitView, {
|
||||
addIcon: true,
|
||||
stage: this.iconsStage,
|
||||
}),
|
||||
this.createUnitContainer(unitView, {
|
||||
addIcon: false,
|
||||
stage: this.levelsStage,
|
||||
}),
|
||||
this.createIconSprite(unitView),
|
||||
this.createLevelSprite(unitView),
|
||||
unitView.level(),
|
||||
unitView.type() === UnitType.Construction,
|
||||
);
|
||||
this.renders.push(render);
|
||||
this.computeNewLocation(render);
|
||||
this.modifyVisibility(render);
|
||||
this.shouldRedraw = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ const underConstructionColor = colord({ r: 150, g: 150, b: 150 });
|
||||
const BASE_BORDER_RADIUS = 16.5;
|
||||
const BASE_TERRITORY_RADIUS = 13.5;
|
||||
const RADIUS_SCALE_FACTOR = 0.5;
|
||||
const ZOOM_THRESHOLD = 2.5; // below this zoom level, structures are not rendered
|
||||
const ZOOM_THRESHOLD = 3.5; // below this zoom level, structures are not rendered
|
||||
|
||||
interface UnitRenderConfig {
|
||||
icon: string;
|
||||
|
||||
Reference in New Issue
Block a user