*/ public array $baseColor; public int $health; public int $maxHealth; public float $knockback; public float $knockbackDamping; public int $scoreValue; /** @var null|callable(Zombie):void */ public $onDeath; protected Vector2 $hitKnockback; protected float $flash = 0.0; protected float $time = 0.0; public float $broken; protected float $emergeTotal; protected float $emerge; public function __construct( float $x, float $y, EntityList $container, Room $room, array $config = [], ?callable $onDeath = null, ) { parent::__construct($x, $y); $this->container = $container; $this->room = $room; $this->speed = $config['speed'] ?? 110.0; $this->size = $config['size'] ?? 24.0; $this->baseColor = $config['color'] ?? [0.15, 0.65, 0.2, 1.0]; $this->health = $config['health'] ?? 1; $this->maxHealth = $this->health; $this->knockback = $config['knockback'] ?? 260.0; $this->knockbackDamping = $config['knockbackDamping'] ?? 10.0; $this->scoreValue = $config['scoreValue'] ?? 1; $emergeTime = $config['emergeTime'] ?? 0.0; $this->emergeTotal = $emergeTime; $this->emerge = $emergeTime; $this->onDeath = $onDeath; $this->broken = rand(0, 100000) / 100000.0 * M_PI * 2.0; $this->hitKnockback = Vector2::zero(); $this->width = $this->size; $this->height = $this->size; } public function kind(): string { return 'zombie'; } public function die(): void { if ($this->onDeath !== null) { ($this->onDeath)($this); } $this->removeAllReferences(); $this->container->remove($this); } protected function removeAllReferences(): void {} public function hit(Vector2 $impulse, int $damage = 1): bool { $this->health -= $damage; if ($this->health < 0) { $this->health = 0; } $this->hitKnockback = $impulse->mulS($this->knockback); $this->flash = 0.08; return $this->health <= 0; } public function update(float $dt): void { $this->time += $dt; if ($this->updateEmerge($dt)) { return; } if ($this->target === null) { return; } $delta = $this->target->pos->subV($this->pos); $distance = $delta->length(); $chaseVelocity = Vector2::zero(); if ($distance > 1.0) { $chaseVelocity = $delta->divS($distance)->mulS($this->speed); } $this->velocity = $chaseVelocity->addV($this->hitKnockback); parent::update($dt); $this->hitKnockback = $this->hitKnockback->mulS(max(0.0, 1 - $dt * $this->knockbackDamping)); $this->flash = max(0.0, $this->flash - $dt); } public function updateEmerge(float $dt): bool { if ($this->emerge <= 0.0) { return false; } $this->emerge -= $dt; if ($this->emerge <= 0.0) { $this->emerge = 0.0; $this->onEmergeComplete(); } return true; } protected function onEmergeComplete(): void {} protected function rand01(): float { return random_int(0, 1000000) / 1000000.0; } public function toSnapshot(): array { $snapshot = [ 'eid' => $this->eid, 'd' => $this->kind(), 'x' => round($this->pos->x, 1), 'y' => round($this->pos->y, 1), 's' => $this->size, 'hp' => $this->health, 'mhp' => $this->maxHealth, 'c' => array_slice($this->baseColor, 0, 3), ]; if ($this->emergeTotal > 0.0) { $snapshot['et'] = round($this->emergeTotal, 2); $snapshot['er'] = round($this->emerge, 2); } return $snapshot; } }