npm.io
0.3.1 • Published 2d ago

miaoda-game-combat2d-core

Licence
MIT
Version
0.3.1
Deps
0
Size
56 kB
Vulns
0
Weekly
0

miaoda-game-combat2d-core

Use this package to turn 2D overlaps into deterministic combat events. It applies team masks, once-per-attack deduplication, invincibility frames, and pierce limits. It does not move bodies, calculate damage, render, or decide what a hit means.

Install

pnpm add miaoda-game-combat2d-core

Register boxes and resolve a frame

import { CombatField, aabb, layerBit } from 'miaoda-game-combat2d-core';

const PLAYER = layerBit(0);
const ENEMY = layerBit(1);
const field = new CombatField();

field.addHurtbox({
  id: 'slime', x: 100, y: 40, shape: aabb(8, 8),
  layer: ENEMY, enabled: true, owner: slime,
});
field.addHitbox({
  id: 'sword', x: 92, y: 40, shape: aabb(12, 6),
  mask: ENEMY, enabled: true, attackId: 'swing-42',
  damage: 7, knockback: { x: 120, y: -40 }, owner: player,
});

field.update('slime', slime.x, slime.y);
field.update('sword', swordX, swordY);

for (const hit of field.resolve(6)) {
  stats.applyDamage(hit.target, hit.damage);
  movement.knockback(hit.target, hit.knockback);
}

Call update for changed positions, then call resolve once per logic frame. A hitbox connects only when hitbox.mask & hurtbox.layer is non-zero. resolve returns accepted HitEvents; your game routes their payload to stats, status, movement, hitstop, or effects.

Combat rules

  • Attack deduplication: keep the same attackId while a sword arc overlaps across several frames. It can hit that target once; use a new ID for the next swing.
  • Invincibility frames: resolve(defaultIframes) grants frames to accepted targets. Use grantIframes for dodges, revives, or scripted protection.
  • Pierce: a hitbox defaults to one target. Set pierce to a larger value or -1 for unlimited targets such as explosions and lasers.
  • Geometry: aabb, circle, and shapesOverlap cover headless AABB/circle checks. An engine adapter can instead pass broadphase pairs to resolveContacts.

Broadphase and contacts

const hits = field.resolveContacts([
  { hitboxId: 'sword', hurtboxId: 'slime' },
], 6);

Use contacts from Cocos or Phaser physics when scanning every registered pair is too broad. Core masks, deduplication, i-frames, and pierce still apply; input order decides which target consumes a limited pierce budget first.

API guide

API Use it for
addHitbox / addHurtbox Register attack and target shapes
update Move a registered box before resolving
resolve Scan registered geometry for one logic frame
resolveContacts Resolve pairs supplied by an engine broadphase
grantIframes / isInvincible Add or inspect target protection
resetAttack Allow a persistent hitbox to use an attack ID again
snapshot Inspect stable combat state for tests and telemetry
layerBit / ALL_LAYERS Build team and collision masks

The package owns combat acceptance, not physics response. Pair it with miaoda-game-stats-core for damage formulas, miaoda-game-status-core for effects, miaoda-game-beam-core or miaoda-game-shooter-core for attack generation, and a movement package for knockback.

Keywords