From 19ac90147cec55bad5a76d4c69a13a47474d1980 Mon Sep 17 00:00:00 2001 From: akapkotel Date: Fri, 6 Nov 2020 11:57:46 +0100 Subject: [PATCH 1/3] issue #782 faster checking for line of sight between Sprites --- arcade/paths.py | 55 +++++++++++++++---------------- arcade/texture.py | 19 ++++++----- requirements.txt | 15 +++++---- tests/unit2/test_line_of_sight.py | 1 + 4 files changed, 46 insertions(+), 44 deletions(-) diff --git a/arcade/paths.py b/arcade/paths.py index 2ac0a2969..ed51a8857 100644 --- a/arcade/paths.py +++ b/arcade/paths.py @@ -2,51 +2,48 @@ Path-related functions. """ +from shapely import speedups +from shapely.geometry import LineString, Polygon + from arcade import Point -from arcade import get_distance -from arcade import lerp_vec -from arcade import get_sprites_at_point from arcade import check_for_collision_with_list from arcade import Sprite from arcade import SpriteList + +speedups.enable() + + def has_line_of_sight(point_1: Point, point_2: Point, walls: SpriteList, - max_distance: int = -1, - check_resolution: int = 2): + max_distance: int = -1): """ - Determine if we have line of sight between two points. Try to make sure - that spatial hashing is enabled on the wall SpriteList or this will be - very slow. - - :param Point point_1: Start position - :param Point point_2: End position position - :param SpriteList walls: List of all blocking sprites - :param int max_distance: Max distance point 1 can see - :param int check_resolution: Check every x pixels for a sprite. Trade-off - between accuracy and speed. + Determine if we have line of sight between two points. Having a line of + sight means, that you can connect both points with straight line without + intersecting any obstacle. + Thanks to the shapely efficiency and speedups boost, this method is very + fast. It can easily test 10 000 lines_of_sight. + + :param point_1: tuple -- coordinates of first position (x, y) + :param point_2: tuple -- coordinates of second position (x, y) + :param walls: list -- Obstacle objects to check against + :param max_distance: int -- + :return: tuple -- (bool, list) """ - distance = get_distance(point_1[0], point_1[1], - point_2[0], point_2[1]) - steps = int(distance // check_resolution) - for step in range(steps + 1): - step_distance = step * check_resolution - u = step_distance / distance - midpoint = lerp_vec(point_1, point_2, u) - if max_distance != -1 and step_distance > max_distance: - return False - # print(point_1, point_2, step, u, step_distance, midpoint) - sprite_list = get_sprites_at_point(midpoint, walls) - if len(sprite_list) > 0: - return False - return True + if not walls: + return True + line_of_sight = LineString([point_1, point_2]) + if 0 < max_distance < line_of_sight.length: + return False + return not any((Polygon(o.get_adjusted_hit_box()).crosses(line_of_sight) for o in walls)) """ Classic A-star algorithm for path finding. """ + def _spot_is_blocked(position, moving_sprite, blocking_sprites): original_pos = moving_sprite.position moving_sprite.position = position diff --git a/arcade/texture.py b/arcade/texture.py index cf8008bc5..9e2121c3f 100644 --- a/arcade/texture.py +++ b/arcade/texture.py @@ -38,15 +38,16 @@ def reset(self): return self def multiply(self, o: List[float]): - self.v = [self.v[0] * o[0] + self.v[3] * o[1] + self.v[6] * o[2], - self.v[1] * o[0] + self.v[4] * o[1] + self.v[7] * o[2], - self.v[2] * o[0] + self.v[5] * o[1] + self.v[8] * o[2], - self.v[0] * o[3] + self.v[3] * o[4] + self.v[6] * o[5], - self.v[1] * o[3] + self.v[4] * o[4] + self.v[7] * o[5], - self.v[2] * o[3] + self.v[5] * o[4] + self.v[8] * o[5], - self.v[0] * o[6] + self.v[3] * o[7] + self.v[6] * o[8], - self.v[1] * o[6] + self.v[4] * o[7] + self.v[7] * o[8], - self.v[2] * o[6] + self.v[5] * o[7] + self.v[8] * o[8]] + v = self.v + self.v = [v[0] * o[0] + v[3] * o[1] + v[6] * o[2], + v[1] * o[0] + v[4] * o[1] + v[7] * o[2], + v[2] * o[0] + v[5] * o[1] + v[8] * o[2], + v[0] * o[3] + v[3] * o[4] + v[6] * o[5], + v[1] * o[3] + v[4] * o[4] + v[7] * o[5], + v[2] * o[3] + v[5] * o[4] + v[8] * o[5], + v[0] * o[6] + v[3] * o[7] + v[6] * o[8], + v[1] * o[6] + v[4] * o[7] + v[7] * o[8], + v[2] * o[6] + v[5] * o[7] + v[8] * o[8]] return self def scale(self, sx: float, sy: float): diff --git a/requirements.txt b/requirements.txt index a96c74a2b..34ab4bb0f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1,10 @@ -numpy -Pillow +numpy~=1.19.1 +Pillow~=7.2.0 Pyglet>=1.5.4,<2 pytiled-parser==0.9.4a3 -pytest -pymunk -matplotlib +pytest~=6.0.1 +pymunk~=5.6.0 +matplotlib~=3.3.1 wheel twine sphinx-sitemap @@ -15,4 +15,7 @@ zstandard mypy coverage tox -pyyaml +pyyaml~=5.3.1 + +Shapely~=1.7.1 +setuptools~=49.6.0 \ No newline at end of file diff --git a/tests/unit2/test_line_of_sight.py b/tests/unit2/test_line_of_sight.py index 42f8c4b7a..810974620 100644 --- a/tests/unit2/test_line_of_sight.py +++ b/tests/unit2/test_line_of_sight.py @@ -1,5 +1,6 @@ import arcade + def test_line_of_sight(): player = arcade.Sprite(":resources:images/animated_characters/female_person/femalePerson_idle.png") player.center_x = 50 From 25999b10e134836e688e204fdcf028fee41673fe Mon Sep 17 00:00:00 2001 From: akapkotel Date: Sat, 7 Nov 2020 18:53:49 +0100 Subject: [PATCH 2/3] issue #782 faster checking for line of sight between Sprites 1. shapely and setuptools removed from requirements.txt --- requirements.txt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/requirements.txt b/requirements.txt index 34ab4bb0f..af532468e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,7 +15,4 @@ zstandard mypy coverage tox -pyyaml~=5.3.1 - -Shapely~=1.7.1 -setuptools~=49.6.0 \ No newline at end of file +pyyaml~=5.3.1 \ No newline at end of file From 944c98fc0636c775d1796eddb3ae07d7862fdab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Tr=C4=85bski?= Date: Sat, 7 Nov 2020 21:23:37 +0100 Subject: [PATCH 3/3] Update requirements.txt removed all versioning. --- requirements.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/requirements.txt b/requirements.txt index af532468e..a96c74a2b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,10 +1,10 @@ -numpy~=1.19.1 -Pillow~=7.2.0 +numpy +Pillow Pyglet>=1.5.4,<2 pytiled-parser==0.9.4a3 -pytest~=6.0.1 -pymunk~=5.6.0 -matplotlib~=3.3.1 +pytest +pymunk +matplotlib wheel twine sphinx-sitemap @@ -15,4 +15,4 @@ zstandard mypy coverage tox -pyyaml~=5.3.1 \ No newline at end of file +pyyaml