mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 14:41:35 +00:00
Move indicator fx for warships. (#2871)
Been playing this game for months, and after i feel myself enough experienced about the game, decided to start contributing to the project. This is my first one! ## Description: Move indicator fx for warships. Listening MoveWarshipIntentEvent to draw the fx. Code is basic, respectly layered and written regarding project's structure.  ## 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 ## Please put your Discord username so you can be contacted if a bug or regression is found: 420coder --------- Co-authored-by: Ryan <7389646+ryanbarlow97@users.noreply.github.com>
This commit is contained in:
@@ -258,7 +258,7 @@ export function createRenderer(
|
||||
new UILayer(game, eventBus, transformHandler),
|
||||
new NukeTrajectoryPreviewLayer(game, eventBus, transformHandler, uiState),
|
||||
new StructureIconsLayer(game, eventBus, uiState, transformHandler),
|
||||
new DynamicUILayer(game, transformHandler),
|
||||
new DynamicUILayer(game, transformHandler, eventBus),
|
||||
new NameLayer(game, transformHandler, eventBus),
|
||||
eventsDisplay,
|
||||
chatDisplay,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { renderNumber } from "src/client/Utils";
|
||||
import { EventBus } from "src/core/EventBus";
|
||||
import { UnitType } from "src/core/game/Game";
|
||||
import {
|
||||
BonusEventUpdate,
|
||||
@@ -6,7 +7,9 @@ import {
|
||||
GameUpdateType,
|
||||
} from "src/core/game/GameUpdates";
|
||||
import type { GameView, UnitView } from "../../../core/game/GameView";
|
||||
import { MoveWarshipIntentEvent } from "../../Transport";
|
||||
import { TransformHandler } from "../TransformHandler";
|
||||
import { MoveIndicatorUI } from "../ui/MoveIndicatorUI";
|
||||
import { NavalTarget } from "../ui/NavalTarget";
|
||||
import { NukeTelegraph } from "../ui/NukeTelegraph";
|
||||
import { TextIndicator } from "../ui/TextIndicator";
|
||||
@@ -24,8 +27,18 @@ export class DynamicUILayer implements Layer {
|
||||
constructor(
|
||||
private readonly game: GameView,
|
||||
private transformHandler: TransformHandler,
|
||||
private eventBus: EventBus,
|
||||
) {}
|
||||
|
||||
init() {
|
||||
// Listen for warship move clicks for MoveIndicatorUI
|
||||
this.eventBus.on(MoveWarshipIntentEvent, (e) => {
|
||||
const x = this.game.x(e.tile);
|
||||
const y = this.game.y(e.tile);
|
||||
this.uiElements.push(new MoveIndicatorUI(this.transformHandler, x, y));
|
||||
});
|
||||
}
|
||||
|
||||
shouldTransform(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
import { Cell } from "src/core/game/Game";
|
||||
import { TransformHandler } from "../TransformHandler";
|
||||
import { UIElement } from "./UIElement";
|
||||
|
||||
/**
|
||||
* move indicator fx for warship, similar to moba games.
|
||||
*/
|
||||
export class MoveIndicatorUI implements UIElement {
|
||||
private lifeTime = 0;
|
||||
private readonly duration = 800; // ms
|
||||
private readonly startRadius = 13; // starting distance from center (screen pixels)
|
||||
private readonly chevronSize = 5; // size in screen pixels
|
||||
private readonly cell: Cell;
|
||||
|
||||
constructor(
|
||||
private transformHandler: TransformHandler,
|
||||
public x: number,
|
||||
public y: number,
|
||||
) {
|
||||
this.cell = new Cell(this.x + 0.5, this.y + 0.5);
|
||||
}
|
||||
|
||||
render(ctx: CanvasRenderingContext2D, delta: number): boolean {
|
||||
this.lifeTime += delta;
|
||||
if (this.lifeTime >= this.duration) return false;
|
||||
|
||||
const t = this.lifeTime / this.duration;
|
||||
const alpha = 1 - t; // fade out
|
||||
|
||||
// Scale with zoom level (same pattern as NavalTarget)
|
||||
const transformScale = this.transformHandler.scale;
|
||||
const scale = transformScale > 10 ? 1 + (transformScale - 10) / 10 : 1;
|
||||
|
||||
const radius = this.startRadius * scale * (1 - t * 0.7); // converge inward
|
||||
const chevronSize = this.chevronSize * scale;
|
||||
|
||||
// Get screen coordinates
|
||||
const screenPos = this.transformHandler.worldToScreenCoordinates(this.cell);
|
||||
const centerX = screenPos.x;
|
||||
const centerY = screenPos.y;
|
||||
|
||||
ctx.save();
|
||||
ctx.globalAlpha = alpha;
|
||||
ctx.strokeStyle = "#ff0000";
|
||||
ctx.lineWidth = 2 * scale;
|
||||
ctx.lineCap = "round";
|
||||
ctx.lineJoin = "round";
|
||||
|
||||
// pre calculation of offsets
|
||||
const tipOffset = chevronSize * 0.4;
|
||||
const wingOffset = chevronSize * 0.6;
|
||||
const width = chevronSize;
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
// Top (pointing down)
|
||||
ctx.moveTo(centerX - width, centerY - radius - wingOffset);
|
||||
ctx.lineTo(centerX, centerY - radius + tipOffset);
|
||||
ctx.lineTo(centerX + width, centerY - radius - wingOffset);
|
||||
|
||||
// Bottom (pointing up)
|
||||
ctx.moveTo(centerX - width, centerY + radius + wingOffset);
|
||||
ctx.lineTo(centerX, centerY + radius - tipOffset);
|
||||
ctx.lineTo(centerX + width, centerY + radius + wingOffset);
|
||||
|
||||
// Left (pointing right)
|
||||
ctx.moveTo(centerX - radius - wingOffset, centerY - width);
|
||||
ctx.lineTo(centerX - radius + tipOffset, centerY);
|
||||
ctx.lineTo(centerX - radius - wingOffset, centerY + width);
|
||||
|
||||
// Right (pointing left)
|
||||
ctx.moveTo(centerX + radius + wingOffset, centerY - width);
|
||||
ctx.lineTo(centerX + radius - tipOffset, centerY);
|
||||
ctx.lineTo(centerX + radius + wingOffset, centerY + width);
|
||||
|
||||
ctx.stroke();
|
||||
|
||||
ctx.restore();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user