Skip to content

Commit 9844fba

Browse files
akapkotelakapkotel
and
akapkotel
authored
Issue #782 Using shapely to find line of sight (#783)
* issue #782 faster checking for line of sight between Sprites * issue #782 faster checking for line of sight between Sprites 1. shapely and setuptools removed from requirements.txt * Update requirements.txt removed all versioning. Co-authored-by: akapkotel <[email protected]>
1 parent 094e28d commit 9844fba

File tree

3 files changed

+37
-38
lines changed

3 files changed

+37
-38
lines changed

arcade/paths.py

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,51 +2,48 @@
22
Path-related functions.
33
44
"""
5+
from shapely import speedups
6+
from shapely.geometry import LineString, Polygon
7+
58
from arcade import Point
6-
from arcade import get_distance
7-
from arcade import lerp_vec
8-
from arcade import get_sprites_at_point
99
from arcade import check_for_collision_with_list
1010
from arcade import Sprite
1111
from arcade import SpriteList
1212

13+
14+
speedups.enable()
15+
16+
1317
def has_line_of_sight(point_1: Point,
1418
point_2: Point,
1519
walls: SpriteList,
16-
max_distance: int = -1,
17-
check_resolution: int = 2):
20+
max_distance: int = -1):
1821
"""
19-
Determine if we have line of sight between two points. Try to make sure
20-
that spatial hashing is enabled on the wall SpriteList or this will be
21-
very slow.
22-
23-
:param Point point_1: Start position
24-
:param Point point_2: End position position
25-
:param SpriteList walls: List of all blocking sprites
26-
:param int max_distance: Max distance point 1 can see
27-
:param int check_resolution: Check every x pixels for a sprite. Trade-off
28-
between accuracy and speed.
22+
Determine if we have line of sight between two points. Having a line of
23+
sight means, that you can connect both points with straight line without
24+
intersecting any obstacle.
25+
Thanks to the shapely efficiency and speedups boost, this method is very
26+
fast. It can easily test 10 000 lines_of_sight.
27+
28+
:param point_1: tuple -- coordinates of first position (x, y)
29+
:param point_2: tuple -- coordinates of second position (x, y)
30+
:param walls: list -- Obstacle objects to check against
31+
:param max_distance: int --
32+
:return: tuple -- (bool, list)
2933
"""
30-
distance = get_distance(point_1[0], point_1[1],
31-
point_2[0], point_2[1])
32-
steps = int(distance // check_resolution)
33-
for step in range(steps + 1):
34-
step_distance = step * check_resolution
35-
u = step_distance / distance
36-
midpoint = lerp_vec(point_1, point_2, u)
37-
if max_distance != -1 and step_distance > max_distance:
38-
return False
39-
# print(point_1, point_2, step, u, step_distance, midpoint)
40-
sprite_list = get_sprites_at_point(midpoint, walls)
41-
if len(sprite_list) > 0:
42-
return False
43-
return True
34+
if not walls:
35+
return True
36+
line_of_sight = LineString([point_1, point_2])
37+
if 0 < max_distance < line_of_sight.length:
38+
return False
39+
return not any((Polygon(o.get_adjusted_hit_box()).crosses(line_of_sight) for o in walls))
4440

4541

4642
"""
4743
Classic A-star algorithm for path finding.
4844
"""
4945

46+
5047
def _spot_is_blocked(position, moving_sprite, blocking_sprites):
5148
original_pos = moving_sprite.position
5249
moving_sprite.position = position

arcade/texture.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,16 @@ def reset(self):
3838
return self
3939

4040
def multiply(self, o: List[float]):
41-
self.v = [self.v[0] * o[0] + self.v[3] * o[1] + self.v[6] * o[2],
42-
self.v[1] * o[0] + self.v[4] * o[1] + self.v[7] * o[2],
43-
self.v[2] * o[0] + self.v[5] * o[1] + self.v[8] * o[2],
44-
self.v[0] * o[3] + self.v[3] * o[4] + self.v[6] * o[5],
45-
self.v[1] * o[3] + self.v[4] * o[4] + self.v[7] * o[5],
46-
self.v[2] * o[3] + self.v[5] * o[4] + self.v[8] * o[5],
47-
self.v[0] * o[6] + self.v[3] * o[7] + self.v[6] * o[8],
48-
self.v[1] * o[6] + self.v[4] * o[7] + self.v[7] * o[8],
49-
self.v[2] * o[6] + self.v[5] * o[7] + self.v[8] * o[8]]
41+
v = self.v
42+
self.v = [v[0] * o[0] + v[3] * o[1] + v[6] * o[2],
43+
v[1] * o[0] + v[4] * o[1] + v[7] * o[2],
44+
v[2] * o[0] + v[5] * o[1] + v[8] * o[2],
45+
v[0] * o[3] + v[3] * o[4] + v[6] * o[5],
46+
v[1] * o[3] + v[4] * o[4] + v[7] * o[5],
47+
v[2] * o[3] + v[5] * o[4] + v[8] * o[5],
48+
v[0] * o[6] + v[3] * o[7] + v[6] * o[8],
49+
v[1] * o[6] + v[4] * o[7] + v[7] * o[8],
50+
v[2] * o[6] + v[5] * o[7] + v[8] * o[8]]
5051
return self
5152

5253
def scale(self, sx: float, sy: float):

tests/unit2/test_line_of_sight.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import arcade
22

3+
34
def test_line_of_sight():
45
player = arcade.Sprite(":resources:images/animated_characters/female_person/femalePerson_idle.png")
56
player.center_x = 50

0 commit comments

Comments
 (0)