foitin/engine/core/input_buffer.gd
m3ultra b067bf7f0b Scaffold: deterministic 60Hz combat core, drop-in character format, MODELBEAST pipeline
- Godot 4.7 project; fixed-tick FSM fighter, facing-relative input buffer
  with numpad motion parsing, box collision, training-mode hitbox overlay
- characters/ = self-describing drop-in folders (spec in _spec/); two
  generated placeholder fighters (alpha, beta)
- pipeline/: pack_character.py + autohitbox.py (pose/silhouette hurtboxes)
- STUDY.md: reverse-engineering study of the BKB reference games

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-28 18:45:44 +10:00

64 lines
1.5 KiB
GDScript

class_name InputBuffer
## Ring buffer of per-tick input snapshots for one fighter.
## Directions are stored FACING-RELATIVE (FWD = toward opponent) so
## motion inputs are side-agnostic, exactly like classic fighters.
const UP := 1
const DOWN := 2
const BACK := 4
const FWD := 8
const P := 16
const K := 32
const SIZE := 90
var _buf := PackedInt32Array()
var _head := -1
var _count := 0
func _init() -> void:
_buf.resize(SIZE)
_buf.fill(0)
func push(mask: int) -> void:
_head = (_head + 1) % SIZE
_buf[_head] = mask
_count = mini(_count + 1, SIZE)
## Snapshot from `ticks_ago` ticks in the past (0 = current tick).
func at(ticks_ago: int) -> int:
if ticks_ago >= _count:
return 0
return _buf[(_head - ticks_ago + SIZE) % SIZE]
## Edge detection: button went down this tick.
func pressed(btn: int) -> bool:
return (at(0) & btn) != 0 and (at(1) & btn) == 0
func held(btn: int) -> bool:
return (at(0) & btn) != 0
## Numpad-notation digit for the snapshot `ticks_ago` (5 = neutral).
static func numpad(mask: int) -> int:
var col := 5
if mask & FWD:
col = 6
elif mask & BACK:
col = 4
if mask & DOWN:
return col - 3 # 4->1 5->2 6->3
if mask & UP:
return col + 3 # 4->7 5->8 6->9
return col
## True if the numpad sequence `seq` (e.g. [2,3,6] = QCF) was entered
## within the last `window` ticks. Gaps between steps are allowed.
func motion(seq: Array, window: int = CFG.MOTION_WINDOW) -> bool:
var ptr := seq.size() - 1
for t in range(window):
if InputBuffer.numpad(at(t)) == seq[ptr]:
ptr -= 1
if ptr < 0:
return true
return false