Playtest #3 fixes: lost models, picking, live LP, temp overflow, 蕾缪安 S3, 回环射手, FX, detail card, spinners
- #1 lost operator models: the Spine store no longer hands out a skeleton whose unload is in flight (PIXI.Assets.unload is async); eviction runs 1 s after a release and the empty-scene budget only after 3 s - #7 picking: one shared rule (render/pick.js, pixel probe where bodies overlap) for prep/battle clicks, hover, the enemy pen and equipment drops; the drag ghost stands on its drop tile; hover probes capped at one per frame - #2 the top-bar LP drops live as the own battle's enemies enter the blue gate (−N, 联防中), teammates' pending LP in the team panel - #3 temp overflow pieces that arrive after a prep deadline survive through the next prep (tempDue); temp-row warning and ready-button reason - #4 蕾缪安 S3: locks every 0.5 s, then one shell every 0.3 s in lock order (PRTS notes), bombardShell fx - #5 回环射手: real boomerang (out 15, back 3.75 tiles/s, attack only when every boomerang is caught) - #6 visible projectiles, muzzle flashes, slashes, skill bursts and auras at unchanged frame cost - #8 特质 right under the detail card header, with its official type icon - #9 no spinning busy cursors / spinners next to texts; game data warmed before the match - docs, recordings and tests updated (2414 unit tests, all browser suites green)
This commit is contained in:
1 parent
01a44cd288
commit
0aba602ecf
72 files changed
+5132
-571
No files matched your search
@@ -18,6 +18,7 @@ import { GEO, PHASE, UF } from '../../../shared/constants.js';
|
||||
import { resolveLoadout, loadoutOptions, MODULE_NONE } from '../../../shared/protocol.js';
|
||||
import { resolveRecordLoadout, loadoutRecord } from '../../../shared/loadoutRecord.js';
|
||||
import { layoutPen } from '../render/pen.js';
|
||||
import { pickBody } from '../render/pick.js';
|
||||
import { bossLevelSeconds } from './matchStatus.js';
|
||||
|
||||
// ---- small helpers -------------------------------------------------------------------------------
|
||||
@@ -871,17 +872,31 @@ export function dropIntent(ctx, uid, target) {
|
||||
}
|
||||
|
||||
/**
|
||||
* The front-most piece whose screen rect contains (x, y): the one standing nearest the camera (largest bottom).
|
||||
* @param {Array<{uid:number, left:number, top:number, right:number, bottom:number}|null>} rects
|
||||
* The piece under a screen point (user playtest #3 item 7). Rects of the render engine carry the drawn body
|
||||
* (`shape`, view.pieceScreenRect) and are picked by the shared rule of render/pick.js — the face / torso of a unit is
|
||||
* its own; elsewhere the piece standing on the tile under the pointer (`tile`, same space as the rects' `tile`) wins.
|
||||
* Plain rects (the DOM fallback) go to the one whose centre is nearest relative to its size (a unit standing in front
|
||||
* no longer takes the whole overlap), ties → the front-most (largest bottom).
|
||||
* @param {Array<{uid:number, left:number, top:number, right:number, bottom:number, shape?:object, tile?:{row:number,col:number}}|null>} rects
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @param {{row:number, col:number}|null} [tile] the tile under the point
|
||||
* @returns {number|null} uid
|
||||
*/
|
||||
export function pickPieceAt(rects, x, y) {
|
||||
export function pickPieceAt(rects, x, y, tile = null) {
|
||||
if (!Number.isFinite(x) || !Number.isFinite(y)) return null;
|
||||
let best = null;
|
||||
for (const r of Array.isArray(rects) ? rects : []) {
|
||||
if (!isObj(r) || !Number.isInteger(r.uid)) continue;
|
||||
const list = (Array.isArray(rects) ? rects : []).filter((r) => isObj(r) && Number.isInteger(r.uid));
|
||||
const shaped = list.filter((r) => isObj(r.shape) && r.shape.s > 0);
|
||||
if (shaped.length && shaped.length === list.length) {
|
||||
const hit = pickBody(shaped.map((r) => ({ ...r.shape, tile: r.tile || null, uid: r.uid })), x, y, tile);
|
||||
return hit ? hit.uid : null;
|
||||
}
|
||||
let best = null, bestD = Infinity;
|
||||
for (const r of list) {
|
||||
if (x < r.left || x > r.right || y < r.top || y > r.bottom) continue;
|
||||
if (!best || r.bottom > best.bottom) best = r;
|
||||
const hw = Math.max(1, (r.right - r.left) / 2), hh = Math.max(1, (r.bottom - r.top) / 2);
|
||||
const d = Math.hypot((x - (r.left + r.right) / 2) / hw, (y - (r.top + r.bottom) / 2) / hh);
|
||||
if (d < bestD - 1e-9 || (Math.abs(d - bestD) <= 1e-9 && r.bottom > best.bottom)) { best = r; bestD = d; }
|
||||
}
|
||||
return best ? best.uid : null;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user