JA
games/open-lemmings / src / View / Pinch.php · commit 04e2e2a
<?phpnamespace App\View;use JumPHP\Input\TouchControls;use JumPHP\Renderer\Renderer;/** * Watches the fingers on the screen (the engine only follows one): two fingers moving apart or together are a pinch. * Installed as the input's touch observer; what was there before (the phone app's own controls) still gets everything. */final class Pinch extends TouchControls{    /** @var array<string, array{0: float, 1: float}> finger id => position, 0..1 of the screen */    private array $fingers = [];    private float $factor = 1.0;    private ?float $last = null;    public function __construct(private ?TouchControls $inner = null)    {    }    public function beforeEvents(): void    {        $this->inner?->beforeEvents();    }    public function handle($event, Renderer $renderer): bool    {        $f = $event->tfinger;        $id = (string)$f->fingerId;        if ($event->type === \SDL_FINGERUP) {            unset($this->fingers[$id]);            $this->last = null;        } else {            $this->fingers[$id] = [(float)$f->x, (float)$f->y];        }        if (count($this->fingers) > 2) {   // a third finger: start again with the newest two            $this->fingers = array_slice($this->fingers, -2, null, true);            $this->last = null;        }        if (count($this->fingers) === 2) {            [$a, $b] = array_values($this->fingers);            $d = hypot(($a[0] - $b[0]) * 16, ($a[1] - $b[1]) * 9);            if ($this->last !== null && $this->last > 0.01 && $d > 0.01) {                $this->factor *= $d / $this->last;            }            $this->last = $d;        }        return $this->inner?->handle($event, $renderer) ?? false;    }    public function draw(Renderer $r): void    {        $this->inner?->draw($r);    }    /** Forgets every finger (a lost finger-up must not leave a pinch on forever). */    public function reset(): void    {        $this->fingers = [];        $this->factor = 1.0;        $this->last = null;    }    /** Two fingers are down. */    public function active(): bool    {        return count($this->fingers) >= 2;    }    /** How much the fingers spread since the last call (1: nothing), and where their middle is (0..1). @return array{0: float, 1: float, 2: float} */    public function take(): array    {        $factor = $this->factor;        $this->factor = 1.0;        $pts = array_values($this->fingers);        $n = max(1, count($pts));        return [$factor, array_sum(array_column($pts, 0)) / $n, array_sum(array_column($pts, 1)) / $n];    }}