sotc-battle-show-ability : affichage des capacités en combat
This commit is contained in:
parent
84aa6b3437
commit
e35a3996ee
11 changed files with 1363 additions and 0 deletions
150
sotc-clash-arrow/scripts/ClashArrowLayer.js
Normal file
150
sotc-clash-arrow/scripts/ClashArrowLayer.js
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
/**
|
||||
* sotc-clash-arrow | ClashArrowLayer.js
|
||||
*
|
||||
* En Foundry v11, les CanvasLayer custom ne se montent pas via CONFIG.Canvas.layers.
|
||||
* Solution : attacher deux PIXI.Graphics directement sur canvas.interface
|
||||
* (le groupe PIXI qui contient tokens, drawings, etc.).
|
||||
*
|
||||
* API publique (identique à l'ancienne classe) :
|
||||
* ClashArrowLayer.init() – à appeler au canvasReady
|
||||
* ClashArrowLayer.tearDown() – à appeler au canvasTearDown
|
||||
* ClashArrowLayer.redraw() – redessine toutes les flèches du store
|
||||
* ClashArrowLayer.drawPreview() – flèche temporaire pendant le drag
|
||||
* ClashArrowLayer.clearPreview()
|
||||
*/
|
||||
|
||||
import { ArrowStore } from "./ArrowStore.js";
|
||||
|
||||
// ── Constantes visuelles ──────────────────────────────────────────────────────
|
||||
const COLOR_BLUE = 0x4a9eff;
|
||||
const COLOR_YELLOW = 0xffd84a;
|
||||
const COLOR_PREVIEW = 0x888899;
|
||||
const COLOR_USED = 0x8B4513; // marron "Used"
|
||||
|
||||
const ALPHA_USED = 0.35; // légèrement visible
|
||||
|
||||
const LINE_WIDTH = 3;
|
||||
const LINE_ALPHA = 0.92;
|
||||
const ARROW_HEAD_SIZE = 14;
|
||||
const BEZIER_CURVE = 0.35;
|
||||
|
||||
// ── Helpers géométriques ──────────────────────────────────────────────────────
|
||||
|
||||
function bezierControlPoints(x1, y1, x2, y2, curvature = BEZIER_CURVE) {
|
||||
const mx = (x1 + x2) / 2;
|
||||
const my = (y1 + y2) / 2;
|
||||
const dx = x2 - x1;
|
||||
const dy = y2 - y1;
|
||||
const nx = -dy * curvature;
|
||||
const ny = dx * curvature;
|
||||
return { cp1x: mx + nx, cp1y: my + ny };
|
||||
}
|
||||
|
||||
function bezierPoint(t, p0, p1, p2, p3) {
|
||||
const mt = 1 - t;
|
||||
return mt*mt*mt*p0 + 3*mt*mt*t*p1 + 3*mt*t*t*p2 + t*t*t*p3;
|
||||
}
|
||||
|
||||
function drawArrowHead(gfx, tx, ty, dx, dy, size, color, alpha) {
|
||||
const angle = Math.atan2(dy, dx);
|
||||
const spread = Math.PI / 6;
|
||||
const lx = tx - size * Math.cos(angle - spread);
|
||||
const ly = ty - size * Math.sin(angle - spread);
|
||||
const rx = tx - size * Math.cos(angle + spread);
|
||||
const ry = ty - size * Math.sin(angle + spread);
|
||||
gfx.lineStyle(0);
|
||||
gfx.beginFill(color, alpha);
|
||||
gfx.drawPolygon([tx, ty, lx, ly, rx, ry]);
|
||||
gfx.endFill();
|
||||
}
|
||||
|
||||
// ── Module singleton ──────────────────────────────────────────────────────────
|
||||
|
||||
/** @type {PIXI.Graphics|null} */
|
||||
let _arrowsGfx = null;
|
||||
/** @type {PIXI.Graphics|null} */
|
||||
let _previewGfx = null;
|
||||
|
||||
function _drawArrow(gfx, x1, y1, x2, y2, color, alpha = LINE_ALPHA) {
|
||||
const { cp1x, cp1y } = bezierControlPoints(x1, y1, x2, y2);
|
||||
|
||||
gfx.lineStyle(LINE_WIDTH, color, alpha);
|
||||
gfx.moveTo(x1, y1);
|
||||
gfx.bezierCurveTo(cp1x, cp1y, cp1x, cp1y, x2, y2);
|
||||
|
||||
const t = 0.98;
|
||||
const px = bezierPoint(t, x1, cp1x, cp1x, x2);
|
||||
const py = bezierPoint(t, y1, cp1y, cp1y, y2);
|
||||
drawArrowHead(gfx, x2, y2, x2 - px, y2 - py, ARROW_HEAD_SIZE, color, alpha);
|
||||
}
|
||||
|
||||
export const ClashArrowLayer = {
|
||||
|
||||
/**
|
||||
* Initialise les Graphics PIXI et les attache au canvas.
|
||||
* Appelé au canvasReady depuis Hooks.js.
|
||||
*/
|
||||
init() {
|
||||
// Si déjà initialisé et Graphics toujours valides, juste redessiner
|
||||
if (_arrowsGfx && !_arrowsGfx.destroyed) {
|
||||
this.redraw();
|
||||
return;
|
||||
}
|
||||
|
||||
// Nettoyer si les Graphics sont corrompus
|
||||
this.tearDown();
|
||||
|
||||
const parent = canvas.interface ?? canvas.stage;
|
||||
|
||||
_arrowsGfx = parent.addChild(new PIXI.Graphics());
|
||||
_previewGfx = parent.addChild(new PIXI.Graphics());
|
||||
|
||||
_arrowsGfx.zIndex = 900;
|
||||
_previewGfx.zIndex = 901;
|
||||
|
||||
ArrowStore.on("change", () => this.redraw());
|
||||
|
||||
// Dessiner les flèches déjà présentes dans le store
|
||||
this.redraw();
|
||||
|
||||
console.log("sotc-clash-arrow | ClashArrowLayer initialisé sur canvas.interface.");
|
||||
},
|
||||
|
||||
/** Nettoie et retire les Graphics du canvas. */
|
||||
tearDown() {
|
||||
ArrowStore.off("change");
|
||||
if (_arrowsGfx) { _arrowsGfx.parent?.removeChild(_arrowsGfx); _arrowsGfx.destroy(); _arrowsGfx = null; }
|
||||
if (_previewGfx) { _previewGfx.parent?.removeChild(_previewGfx); _previewGfx.destroy(); _previewGfx = null; }
|
||||
},
|
||||
|
||||
/** Redessine toutes les flèches persistantes. */
|
||||
redraw() {
|
||||
if (!_arrowsGfx) return;
|
||||
_arrowsGfx.clear();
|
||||
for (const arrow of ArrowStore.all()) {
|
||||
if (arrow.used) {
|
||||
_drawArrow(_arrowsGfx, arrow.x1, arrow.y1, arrow.x2, arrow.y2, COLOR_USED, ALPHA_USED);
|
||||
} else {
|
||||
const color = arrow.mutual ? COLOR_YELLOW : COLOR_BLUE;
|
||||
_drawArrow(_arrowsGfx, arrow.x1, arrow.y1, arrow.x2, arrow.y2, color);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Flèche de preview pendant le drag.
|
||||
* @param {number} x1 @param {number} y1 Origine (coords monde)
|
||||
* @param {number} x2 @param {number} y2 Position courante (coords monde)
|
||||
* @param {number} color
|
||||
*/
|
||||
drawPreview(x1, y1, x2, y2, color = COLOR_PREVIEW) {
|
||||
if (!_previewGfx) return;
|
||||
_previewGfx.clear();
|
||||
_drawArrow(_previewGfx, x1, y1, x2, y2, color, 0.55);
|
||||
},
|
||||
|
||||
/** Efface la flèche de preview. */
|
||||
clearPreview() {
|
||||
_previewGfx?.clear();
|
||||
},
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue