Create in-game Ad (#853)

## Description:

Inserts an ad under the leaderboard & above the control panel. Only
shown on larger screens.

## Please complete the following:

- [x] I have added screenshots for all UI updates
- [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:
evan
This commit is contained in:
evanpelle
2025-05-23 13:19:53 -07:00
committed by GitHub
parent 9563c189eb
commit 530784f487
3 changed files with 122 additions and 0 deletions
+10
View File
@@ -15,6 +15,7 @@ import { EventsDisplay } from "./layers/EventsDisplay";
import { FxLayer } from "./layers/FxLayer";
import { Layer } from "./layers/Layer";
import { Leaderboard } from "./layers/Leaderboard";
import { LeftInGameAd } from "./layers/LeftInGameAd";
import { MultiTabModal } from "./layers/MultiTabModal";
import { NameLayer } from "./layers/NameLayer";
import { OptionsMenu } from "./layers/OptionsMenu";
@@ -171,6 +172,14 @@ export function createRenderer(
}
playerTeamLabel.game = game;
const leftInGameAd = document.querySelector(
"left-in-game-ad",
) as LeftInGameAd;
if (!(leftInGameAd instanceof LeftInGameAd)) {
console.error("left in game ad not found");
}
leftInGameAd.g = game;
const layers: Layer[] = [
new TerrainLayer(game, transformHandler),
new TerritoryLayer(game, eventBus),
@@ -204,6 +213,7 @@ export function createRenderer(
playerPanel,
playerTeamLabel,
multiTabModal,
leftInGameAd,
];
return new GameRenderer(
+111
View File
@@ -0,0 +1,111 @@
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators.js";
import { GameView } from "../../../core/game/GameView";
import { Layer } from "./Layer";
declare global {
interface Window {
aiptag: {
cmd: {
display: {
push: (callback: () => void) => void;
};
};
};
aipDisplayTag: {
display: (id: string) => void;
};
}
}
const BREAKPOINT = {
width: 1000,
height: 800,
};
const AD_SIZE = "openfront-io_300x250_ingame";
@customElement("left-in-game-ad")
export class LeftInGameAd extends LitElement implements Layer {
public g: GameView;
@state()
private isVisible: boolean = false;
// Override createRenderRoot to disable shadow DOM
createRenderRoot() {
return this;
}
static styles = css`
.ad-container {
position: fixed;
left: 0;
top: 50%;
transform: translateY(-50%);
z-index: 9000;
pointer-events: auto;
}
`;
constructor() {
super();
}
public show(): void {
this.isVisible = true;
this.requestUpdate();
// Refresh the ad when showing
setTimeout(() => this.refreshAd(), 100);
}
public hide(): void {
this.isVisible = false;
this.requestUpdate();
}
public async tick() {
if (!this.isVisible && !this.g.inSpawnPhase() && this.screenLargeEnough()) {
console.log("showing left in game ad");
this.show();
}
if (this.isVisible && !this.screenLargeEnough()) {
console.log("hiding left in game ad");
this.hide();
}
}
private screenLargeEnough(): boolean {
return (
window.innerWidth > BREAKPOINT.width &&
window.innerHeight > BREAKPOINT.height
);
}
private refreshAd(): void {
if (window.aiptag && window.aiptag.cmd && window.aiptag.cmd.display) {
window.aiptag.cmd.display.push(
function () {
if (window.aipDisplayTag) {
window.aipDisplayTag.display(AD_SIZE);
}
}.bind(this),
);
}
}
render() {
if (!this.isVisible) {
return html``;
}
return html`
<div
class="ad-container"
style="position: fixed; left: 0; top: 50%; transform: translateY(-50%); z-index: 9999;"
>
<div id="${AD_SIZE}"></div>
</div>
`;
}
}
+1
View File
@@ -421,6 +421,7 @@
<user-setting></user-setting>
<multi-tab-modal></multi-tab-modal>
<news-modal></news-modal>
<left-in-game-ad></left-in-game-ad>
<div
id="language-modal"
class="fixed inset-0 bg-black bg-opacity-50 z-50 hidden flex justify-center items-center"