summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Collision/Collision.php141
-rw-r--r--src/Main.php22
-rw-r--r--src/World/Boid.php76
-rw-r--r--src/World/World.php57
-rw-r--r--src/bootstrap.php3
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';