diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Collision/Collision.php | 141 | ||||
-rw-r--r-- | src/Main.php | 22 | ||||
-rw-r--r-- | src/World/Boid.php | 76 | ||||
-rw-r--r-- | src/World/World.php | 57 | ||||
-rw-r--r-- | src/bootstrap.php | 3 |
5 files changed, 299 insertions, 0 deletions
diff --git a/src/Collision/Collision.php b/src/Collision/Collision.php new file mode 100644 index 0000000..a896777 --- /dev/null +++ b/src/Collision/Collision.php @@ -0,0 +1,141 @@ +<?php + +namespace App\Collision; + + +class Collision +{ + protected const BUFFER = 0.1; + + public static function circleRectangle(int $c_radius, int $c_x, int $c_y, int $r_w, int $r_h, int $r_x, int $r_y): bool + { + $test_x = $c_x; + $test_y = $c_y; + + if ($c_x < $r_x) { + $test_x = $r_x; + } elseif ($c_x > $r_x + $r_w) { + $test_x = $r_x + $r_w; + } + + if ($c_y < $r_y) { + $test_y = $r_y; + } elseif ($c_y > $r_y + $r_h) { + $test_y = $r_y + $r_h; + } + + $dist_x = $c_x - $test_x; + $dist_y = $c_y - $test_y; + + $distance = sqrt( ($dist_x * $dist_y) + ($dist_y * $dist_y) ); + + if ($distance <= $c_radius) { + return true; + } + + return false; + } + + public static function circleWorld(int $c_radius, int $c_x, int $c_y, int $w_w, int $w_h, int $w_x, int $w_y): bool + { + if (static::circleOutsideRectangle($c_radius, $c_x, $c_y, $w_w, $w_h, $w_x, $w_y)) { + return true; + } + + if (static::lineCircle($w_x, $w_x, $w_y, $w_y+$w_h, $c_x, $c_y, $c_radius)) { + return true; + } + + if (static::lineCircle($w_x+$w_w, $w_x+$w_w, $w_y, $w_y+$w_h, $c_x, $c_y, $c_radius)) { + return true; + } + + if (static::lineCircle($w_x, $w_x+$w_w, $w_y, $w_y, $c_x, $c_y, $c_radius)) { + return true; + } + + if (static::lineCircle($w_x, $w_x+$w_w, $w_y+$w_h, $w_y+$w_h, $c_x, $c_y, $c_radius)) { + return true; + } + + return false; + + } + + public static function circleOutsideRectangle(int $c_radius, int $c_x, int $c_y, int $w_w, int $w_h, int $w_x, int $w_y) + { + if ($c_x + $c_radius < $w_x) { + return true; + } + + if ($c_x - $c_radius > $w_x + $w_w) { + return true; + } + + if ($c_y + $c_radius < $w_y) { + return true; + } + + if ($c_y - $c_radius > $w_y + $w_h) { + return true; + } + + return false; + } + + public static function lineCircle(int $x_1, int $x_2, int $y_1, int $y_2, int $c_x, int $c_y, int $c_radius): bool + { + if (static::pointCircle($x_1, $y_1, $c_x, $c_y, $c_radius)) { + return true; + } + + if (static::pointCircle($x_2, $y_2, $c_x, $c_y, $c_radius)) { + return true; + } + + $length = static::distance($x_1, $x_2, $y_1, $y_2); + + $dot = ((($c_x - $x_1) * ($x_2 - $x_1)) + (($c_y - $y_1) * ($y_2 - $y_1))) / ($length * $length); + $dot = number_format($dot, 4); + + $closest_x = $x_1 + ($dot * ($x_2 - $x_1)); + $closest_y = $y_1 +_($dot * ($y_2 - $y_1)); + + if (!static::linePoint($x_1, $x_2, $y_1, $y_2, $closest_x, $closest_y)) { + return false; + } + + $distance = static::distance($closest_x, $c_x, $closest_y, $c_y); + + return $distance <= $c_radius; + } + + public static function linePoint(int $x_1, int $x_2, int $y_1, int $y_2, int $p_x, int $p_y) + { + $d_1 = static::distance($p_x, $x_1, $p_y, $y_1); + $d_2 = static::distance($p_x, $x_2, $p_y, $y_2); + + $length = static::distance($x_1, $x_2, $y_1, $y_2); + + return $d_1 + $d_2 >= $length - static::BUFFER + && $d_1 + $d_2 <= $length + static::BUFFER; + } + + public static function pointCircle(int $p_x, int $p_y, int $c_x, int $c_y, int $c_radius): bool + { + $distance = static::distance($p_x, $c_x, $p_y, $c_y); + + return $distance <= $c_radius; + } + + public static function distance(int $x_1, int $x_2, int $y_1, int $y_2): float + { + $d_x = $x_1 - $x_2; + $d_y = $y_1 - $y_2; + + return number_format( + sqrt( ($d_x * $d_x) + ($d_y * $d_y)), + 2 + ); + } +} diff --git a/src/Main.php b/src/Main.php new file mode 100644 index 0000000..5678111 --- /dev/null +++ b/src/Main.php @@ -0,0 +1,22 @@ +<?php + +namespace App; + +use App\World\Boid; +use App\World\World; + +class Main +{ + public function __construct() + { + } + + public function run() + { + $world = new World(200, 200); + echo "New World Created. `{$world->name()}` ({$world->width()} x {$world->height()})." . PHP_EOL; + + $boid = new Boid(5, 10, 10); + echo "New Boid Created. `{$boid->name()}` ({$boid->position()[0]}, {$boid->position()[1]})." . PHP_EOL; + } +} diff --git a/src/World/Boid.php b/src/World/Boid.php new file mode 100644 index 0000000..3787516 --- /dev/null +++ b/src/World/Boid.php @@ -0,0 +1,76 @@ +<?php + +namespace App\World; + +use App\Collision\Collision; +use Exception; + +class Boid +{ + protected $radius; + private $initial_x; + private $initial_y; + + protected $x; + protected $y; + + public function __construct(int $radius, int $initial_x, int $initial_y, ?string $name = null) + { + $this->radius($radius); + $this->initial_x = $initial_x; + $this->initial_y = $initial_y; + + $this->position($initial_x, $initial_y); + + if (!$name) { + $name = $this->generateName(); + } + + $this->name($name); + } + + public function radius(int $radius = null): int|Boid + { + if ($radius) { + $this->radius = $radius; + return $this; + } + + return $this->radius; + } + + public function position(int $x = null, int $y = null): array|Boid + { + if ($x !== null xor $y !== null) { + throw new Exception('Either 0 or 2 arguments are requried for Boid::position()'); + } + + if ($x !== null) { + $this->x = $x; + $this->y = $y; + return $this; + } + + return [$this->x, $this->y]; + } + + public function name(string $name = null): string|Boid + { + if ($name) { + $this->name = $name; + return $this; + } + + return $this->name; + } + + public function isCollisionWithWorld(int $w_w, int $w_h, int $w_x, int $w_y): bool + { + return Collision::circleWorld($this->radius, $this->x, $this->y, $w_w, $w_h, $w_x, $w_y); + } + + protected function generateName() + { + return uniqid('boid'); + } +} diff --git a/src/World/World.php b/src/World/World.php new file mode 100644 index 0000000..06499e8 --- /dev/null +++ b/src/World/World.php @@ -0,0 +1,57 @@ +<?php + +namespace App\World; + +class World +{ + protected $width; + protected $height; + protected $name; + + public function __construct(int $width, int $height, ?string $name = null) + { + $this->width($width); + $this->height($height); + + if (!$name) { + $name = $this->generateName(); + } + + $this->name($name); + } + + public function width(int $width = null): int|World + { + if ($width) { + $this->width = $width; + return $this; + } + + return $this->width; + } + + public function height(int $height = null): int|World + { + if ($height) { + $this->height = $height; + return $this; + } + + return $this->height; + } + + public function name(string $name = null): string|World + { + if ($name) { + $this->name = $name; + return $this; + } + + return $this->name; + } + + protected function generateName() + { + return uniqid('world'); + } +} diff --git a/src/bootstrap.php b/src/bootstrap.php new file mode 100644 index 0000000..991ea43 --- /dev/null +++ b/src/bootstrap.php @@ -0,0 +1,3 @@ +<?php + +require __DIR__.'/../vendor/autoload.php'; |