DE

Elfs & Orcs Tower Defense

von malabke · Strategie
5,0 (1)
▶ Spielen 💬 Feedback Quellcode 🕘 Versionen Bearbeiten GitHub
games/elfs-orcs-tower-defense / src / Ui / MixedFont.php · commit 65500d9
<?phpnamespace App\Ui;use JumPHP\Renderer\Renderer;use JumPHP\Renderer\TextDrawer;use JumPHP\Util\Color;/** * Two fonts as one: the characters of the CJK blocks (kana, hanzi / kanji, hangul) with the fallback font, * everything else with the main one. The language menu writes "日本語" in a Latin language this way. */final class MixedFont implements TextDrawer{    public function __construct(private TextDrawer $main, private TextDrawer $fallback)    {    }    public function draw(Renderer $r, string $text, float $x, float $y, float $scale = 1, Color|array|string $color = [255, 255, 255],                         string $align = 'left', Color|array|string|null $shadow = null): void    {        $line = $this->lineHeight($scale);        foreach (explode("\n", $text) as $n => $row) {            $w = $this->width($row, $scale);            $cx = $align === 'center' ? $x - $w / 2 : ($align === 'right' ? $x - $w : $x);            foreach (self::runs($row) as [$cjk, $run]) {                $font = $cjk ? $this->fallback : $this->main;                // runs share a vertical middle                $dy = ($line - $font->lineHeight($scale)) / 2;                $font->draw($r, $run, $cx, $y + $n * $line + $dy, $scale, $color, 'left', $shadow);                $cx += $font->width($run, $scale);            }        }    }    public function width(string $text, float $scale = 1): int    {        $max = 0;        foreach (explode("\n", $text) as $row) {            $w = 0;            foreach (self::runs($row) as [$cjk, $run]) {                $w += ($cjk ? $this->fallback : $this->main)->width($run, $scale);            }            $max = max($max, $w);        }        return $max;    }    /** The main font's: the fallback only writes a few words in another script (the names of languages). */    public function height(float $scale = 1): int    {        return $this->main->height($scale);    }    public function lineHeight(float $scale = 1): int    {        return $this->main->lineHeight($scale);    }    public static function isCjk(string $char): bool    {        return mb_ord($char, 'UTF-8') >= 0x2E80;    }    /** @return list<array{0: bool, 1: string}> pieces of text of one font */    private static function runs(string $text): array    {        $runs = [];        foreach (preg_split('//u', $text, -1, PREG_SPLIT_NO_EMPTY) ?: [] as $char) {            $cjk = self::isCjk($char);            $last = count($runs) - 1;            if ($last >= 0 && $runs[$last][0] === $cjk) {                $runs[$last][1] .= $char;            } else {                $runs[] = [$cjk, $char];            }        }        return $runs;    }}