annotate src/parpg/grease/collision.py @ 35:d07c8f891089

Added dict and list as possible component field types
author KarstenBock@gmx.net
date Sun, 31 Jul 2011 21:53:38 +0200
parents 09b581087d68
children
rev   line source
27
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
1 #############################################################################
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
2 #
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
3 # Copyright (c) 2010 by Casey Duncan and contributors
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
4 # All Rights Reserved.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
5 #
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
6 # This software is subject to the provisions of the MIT License
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
7 # A copy of the license should accompany this distribution.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
8 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
9 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
10 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
11 #
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
12 #############################################################################
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
13 """
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
14 **Grease collision detection systems**
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
15
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
16 Grease uses two-phase broad and narrow collision detection. *Broad-phase*
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
17 collision systems are used to efficiently identify pairs that may be colliding
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
18 without resorting to a brute-force check of all possible pairs. *Narrow-phase*
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
19 collision systems use the pairs generated by the broad-phase and perform more
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
20 precise collision tests to determine if a collision has actually occurred. The
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
21 narrow-phase system also calculates more details about each collision,
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
22 including collision point and normal vector for use in collision response.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
23
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
24 A typical collision detection system consists of a narrow-phase system that
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
25 contains a broad-phased system. The narrow-phase system is usually the only
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
26
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
27 one that the application directly interacts with, though the application is
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
28 free to use the broad-phased system directly if desired. This could be
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
29 useful in cases where speed, rather than precision is paramount.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
30
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
31 The narrow-phase system can be assigned handler objects to run after
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
32 collision detection. These can perform tasks like handling collision response
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
33 or dispatching collision events to application handlers.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
34
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
35 Note that broad-phase systems can return false positives, though they should
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
36 never return false negatives. Do not assume that all pairs returned by a
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
37 broad-phase system are actually in collision.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
38 """
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
39
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
40 __version__ = '$Id$'
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
41
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
42 from grease.geometry import Vec2d
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
43 from bisect import bisect_right
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
44
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
45
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
46 class Pair(tuple):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
47 """Pair of entities in collision. This is an ordered sequence of two
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
48 entities, that compares and hashes unordered.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
49
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
50 Also stores additional collision point and normal vectors
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
51 for each entity.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
52
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
53 Sets of ``Pair`` objects are exposed in the ``collision_pairs``
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
54 attribute of collision systems to indicate the entity pairs in
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
55 collision.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
56 """
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
57 info = None
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
58 """A sequence of (entity, collision point, collision normal)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
59 for each entity in the pair
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
60 """
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
61
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
62 def __new__(cls, entity1, entity2, point=None, normal=None):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
63 pair = tuple.__new__(cls, (entity1, entity2))
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
64 return pair
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
65
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
66 def __hash__(self):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
67 return hash(self[0]) ^ hash(self[1])
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
68
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
69 def __eq__(self, other):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
70 other = tuple(other)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
71 return tuple(self) == other or (self[1], self[0]) == other
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
72
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
73 def __repr__(self):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
74 return '%s%r' % (self.__class__.__name__, tuple(self))
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
75
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
76 def set_point_normal(self, point0, normal0, point1, normal1):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
77 """Set the collision point and normal for both entities"""
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
78 self.info = (
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
79 (self[0], point0, normal0),
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
80 (self[1], point1, normal1),
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
81 )
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
82
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
83
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
84 class BroadSweepAndPrune(object):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
85 """2D Broad-phase sweep and prune bounding box collision detector
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
86
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
87 This algorithm is efficient for collision detection between many
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
88 moving bodies. It has linear algorithmic complexity and takes
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
89 advantage of temporal coherence between frames. It also does
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
90 not suffer from bad worst-case performance (like RDC can).
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
91 Unlike spacial hashing, it does not need to be optimized for
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
92 specific space and body sizes.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
93
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
94 Other algorithms may be more efficient for collision detection with
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
95 stationary bodies, bodies that are always evenly distributed, or ad-hoc
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
96 queries.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
97
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
98 :param collision_component: Name of the collision component used by this
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
99 system, defaults to 'collision'. This component supplies each
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
100 entities' aabb and collision masks.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
101 :type collision_component: str
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
102 """
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
103 world = None
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
104 """|World| object this system belongs to"""
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
105
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
106 collision_component = None
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
107 """Name of world's collision component used by this system"""
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
108
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
109 LEFT_ATTR = "left"
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
110 RIGHT_ATTR = "right"
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
111 TOP_ATTR = "top"
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
112 BOTTOM_ATTR = "bottom"
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
113
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
114 def __init__(self, collision_component='collision'):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
115 self.collision_component = collision_component
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
116 self._by_x = None
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
117 self._by_y = None
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
118 self._collision_pairs = None
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
119
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
120 def set_world(self, world):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
121 """Bind the system to a world"""
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
122 self.world = world
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
123
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
124 def step(self, dt):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
125 """Update the system for this time step, updates and sorts the
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
126 axis arrays.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
127 """
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
128 component = getattr(self.world.components, self.collision_component)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
129 LEFT = self.LEFT_ATTR
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
130 RIGHT = self.RIGHT_ATTR
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
131 TOP = self.TOP_ATTR
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
132 BOTTOM = self.BOTTOM_ATTR
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
133 if self._by_x is None:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
134 # Build axis lists from scratch
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
135 # Note we cache the box positions here
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
136 # so that we can perform hit tests efficiently
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
137 # it also isolates us from changes made to the
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
138 # box positions after we run
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
139 by_x = self._by_x = []
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
140 append_x = by_x.append
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
141 by_y = self._by_y = []
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
142 append_y = by_y.append
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
143 for data in component.itervalues():
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
144 append_x([data.aabb.left, LEFT, data])
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
145 append_x([data.aabb.right, RIGHT, data])
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
146 append_y([data.aabb.bottom, BOTTOM, data])
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
147 append_y([data.aabb.top, TOP, data])
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
148 else:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
149 by_x = self._by_x
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
150 by_y = self._by_y
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
151 removed = []
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
152 for entry in by_x:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
153 entry[0] = getattr(entry[2].aabb, entry[1])
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
154 for entry in by_y:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
155 entry[0] = getattr(entry[2].aabb, entry[1])
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
156 # Removing entities is inefficient, but expected to be rare
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
157 if component.deleted_entities:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
158 deleted_entities = component.deleted_entities
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
159 deleted_x = []
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
160 deleted_y = []
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
161 for i, (_, _, data) in enumerate(by_x):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
162 if data.entity in deleted_entities:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
163 deleted_x.append(i)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
164 deleted_x.reverse()
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
165 for i in deleted_x:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
166 del by_x[i]
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
167 for i, (_, _, data) in enumerate(by_y):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
168 if data.entity in deleted_entities:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
169 deleted_y.append(i)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
170 deleted_y.reverse()
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
171 for i in deleted_y:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
172 del by_y[i]
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
173 # Tack on new entities
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
174 for entity in component.new_entities:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
175 data = component[entity]
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
176 by_x.append([data.aabb.left, LEFT, data])
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
177 by_x.append([data.aabb.right, RIGHT, data])
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
178 by_y.append([data.aabb.bottom, BOTTOM, data])
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
179 by_y.append([data.aabb.top, TOP, data])
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
180
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
181 # Tim-sort is highly efficient with mostly sorted lists.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
182 # Because positions tend to change little each frame
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
183 # we take advantage of this here. Obviously things are
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
184 # less efficient with very fast moving, or teleporting entities
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
185 by_x.sort()
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
186 by_y.sort()
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
187 self._collision_pairs = None
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
188
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
189 @property
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
190 def collision_pairs(self):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
191 """Set of candidate collision pairs for this timestep"""
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
192 if self._collision_pairs is None:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
193 if self._by_x is None:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
194 # Axis arrays not ready
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
195 return set()
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
196
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
197 LEFT = self.LEFT_ATTR
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
198 RIGHT = self.RIGHT_ATTR
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
199 TOP = self.TOP_ATTR
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
200 BOTTOM = self.BOTTOM_ATTR
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
201 # Build candidates overlapping along the x-axis
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
202 component = getattr(self.world.components, self.collision_component)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
203 xoverlaps = set()
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
204 add_xoverlap = xoverlaps.add
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
205 discard_xoverlap = xoverlaps.discard
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
206 open = {}
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
207 for _, side, data in self._by_x:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
208 if side is LEFT:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
209 for open_entity, (from_mask, into_mask) in open.iteritems():
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
210 if data.from_mask & into_mask or from_mask & data.into_mask:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
211 add_xoverlap(Pair(data.entity, open_entity))
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
212 open[data.entity] = (data.from_mask, data.into_mask)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
213 elif side is RIGHT:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
214 del open[data.entity]
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
215
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
216 if len(xoverlaps) <= 10 and len(xoverlaps)*4 < len(self._by_y):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
217 # few candidates were found, so just scan the x overlap candidates
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
218 # along y. This requires an additional sort, but it should
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
219 # be cheaper than scanning everyone and its simpler
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
220 # than a separate brute-force check
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
221 entities = set([entity for entity, _ in xoverlaps]
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
222 + [entity for _, entity in xoverlaps])
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
223 by_y = []
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
224 for entity in entities:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
225 data = component[entity]
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
226 # We can use tuples here, which are cheaper to create
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
227 by_y.append((data.aabb.bottom, BOTTOM, data))
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
228 by_y.append((data.aabb.top, TOP, data))
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
229 by_y.sort()
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
230 else:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
231 by_y = self._by_y
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
232
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
233 # Now check the candidates along the y-axis
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
234 open = set()
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
235 add_open = open.add
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
236 discard_open = open.discard
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
237 self._collision_pairs = set()
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
238 add_pair = self._collision_pairs.add
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
239 for _, side, data in by_y:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
240 if side is BOTTOM:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
241 for open_entity in open:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
242 pair = Pair(data.entity, open_entity)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
243 if pair in xoverlaps:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
244 discard_xoverlap(pair)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
245 add_pair(pair)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
246 if not xoverlaps:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
247 # No more candidates, bail
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
248 return self._collision_pairs
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
249 add_open(data.entity)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
250 elif side is TOP:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
251 discard_open(data.entity)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
252 return self._collision_pairs
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
253
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
254 def query_point(self, x_or_point, y=None, from_mask=0xffffffff):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
255 """Hit test at the point specified.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
256
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
257 :param x_or_point: x coordinate (float) or sequence of (x, y) floats.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
258
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
259 :param y: y coordinate (float) if x is not a sequence
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
260
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
261 :param from_mask: Bit mask used to filter query results. This value
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
262 is bit ANDed with candidate entities' ``collision.into_mask``.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
263 If the result is non-zero, then it is considered a hit. By
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
264 default all entities colliding with the input point are
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
265 returned.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
266
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
267 :return: A set of entities where the point is inside their bounding
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
268 boxes as of the last time step.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
269 """
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
270 if self._by_x is None:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
271 # Axis arrays not ready
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
272 return set()
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
273 if y is None:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
274 x, y = x_or_point
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
275 else:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
276 x = x_or_point
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
277 LEFT = self.LEFT_ATTR
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
278 RIGHT = self.RIGHT_ATTR
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
279 TOP = self.TOP_ATTR
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
280 BOTTOM = self.BOTTOM_ATTR
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
281 x_index = bisect_right(self._by_x, [x])
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
282 x_hits = set()
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
283 add_x_hit = x_hits.add
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
284 discard_x_hit = x_hits.discard
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
285 if x_index <= len(self._by_x) // 2:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
286 # closer to the left, scan from left to right
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
287 while (x == self._by_x[x_index][0]
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
288 and self._by_x[x_index][1] is LEFT
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
289 and x_index < len(self._by_x)):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
290 # Ensure we hit on exact left edge matches
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
291 x_index += 1
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
292 for _, side, data in self._by_x[:x_index]:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
293 if side is LEFT and from_mask & data.into_mask:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
294 add_x_hit(data.entity)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
295 else:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
296 discard_x_hit(data.entity)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
297 else:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
298 # closer to the right
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
299 for _, side, data in reversed(self._by_x[x_index:]):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
300 if side is RIGHT and from_mask & data.into_mask:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
301 add_x_hit(data.entity)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
302 else:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
303 discard_x_hit(data.entity)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
304 if not x_hits:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
305 return x_hits
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
306
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
307 y_index = bisect_right(self._by_y, [y])
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
308 y_hits = set()
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
309 add_y_hit = y_hits.add
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
310 discard_y_hit = y_hits.discard
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
311 if y_index <= len(self._by_y) // 2:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
312 # closer to the bottom
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
313 while (y == self._by_y[y_index][0]
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
314 and self._by_y[y_index][1] is BOTTOM
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
315 and y_index < len(self._by_y)):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
316 # Ensure we hit on exact bottom edge matches
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
317 y_index += 1
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
318 for _, side, data in self._by_y[:y_index]:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
319 if side is BOTTOM:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
320 add_y_hit(data.entity)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
321 else:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
322 discard_y_hit(data.entity)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
323 else:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
324 # closer to the top
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
325 for _, side, data in reversed(self._by_y[y_index:]):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
326 if side is TOP:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
327 add_y_hit(data.entity)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
328 else:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
329 discard_y_hit(data.entity)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
330 if y_hits:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
331 return x_hits & y_hits
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
332 else:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
333 return y_hits
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
334
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
335
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
336 class Circular(object):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
337 """Basic narrow-phase collision detector which treats all entities as
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
338 circles with their radius defined in the collision component.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
339
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
340 :param handlers: A sequence of collision handler functions that are invoked
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
341 after collision detection.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
342 :type handlers: sequence of functions
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
343
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
344 :param collision_component: Name of collision component for this system,
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
345 defaults to 'collision'. This supplies each entity's collision
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
346 radius and masks.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
347 :type collision_component: str
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
348
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
349 :param position_component: Name of position component for this system,
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
350 defaults to 'position'. This supplies each entity's position.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
351 :type position_component: str
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
352
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
353 :param update_aabbs: If True (the default), then the entities'
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
354 `collision.aabb` fields will be updated using their position
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
355 and collision radius before invoking the broad phase system.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
356 Set this False if another system updates the aabbs.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
357 :type update_aabbs: bool
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
358
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
359 :param broad_phase: A broad-phase collision system to use as a source
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
360 for collision pairs. If not specified, a :class:`BroadSweepAndPrune`
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
361 system will be created automatically.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
362 """
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
363 world = None
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
364 """|World| object this system belongs to"""
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
365
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
366 position_component = None
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
367 """Name of world's position component used by this system"""
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
368
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
369 collision_component = None
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
370 """Name of world's collision component used by this system"""
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
371
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
372 update_aabbs = True
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
373 """Flag to indicate whether the system updates the entities' `collision.aabb`
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
374 field before invoking the broad phase collision system
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
375 """
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
376
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
377 handlers = None
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
378 """A sequence of collision handler functions invoke after collision
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
379 detection
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
380 """
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
381
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
382 broad_phase = None
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
383 """Broad phase collision system used as a source for collision pairs"""
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
384
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
385 def __init__(self, handlers=(), position_component='position',
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
386 collision_component='collision', update_aabbs=True, broad_phase=None):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
387 self.handlers = tuple(handlers)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
388 if broad_phase is None:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
389 broad_phase = BroadSweepAndPrune(collision_component)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
390 self.collision_component = collision_component
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
391 self.position_component = position_component
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
392 self.update_aabbs = bool(update_aabbs)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
393 self.broad_phase = broad_phase
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
394 self._collision_pairs = None
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
395
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
396 def set_world(self, world):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
397 """Bind the system to a world"""
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
398 self.world = world
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
399 self.broad_phase.set_world(world)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
400 for handler in self.handlers:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
401 if hasattr(handler, 'set_world'):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
402 handler.set_world(world)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
403
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
404 def step(self, dt):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
405 """Update the collision system for this time step and invoke
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
406 the handlers
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
407 """
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
408 if self.update_aabbs:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
409 for position, collision in self.world.components.join(
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
410 self.position_component, self.collision_component):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
411 aabb = collision.aabb
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
412 x, y = position.position
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
413 radius = collision.radius
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
414 aabb.left = x - radius
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
415 aabb.right = x + radius
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
416 aabb.bottom = y - radius
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
417 aabb.top = y + radius
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
418 self.broad_phase.step(dt)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
419 self._collision_pairs = None
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
420 for handler in self.handlers:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
421 handler(self)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
422
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
423 @property
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
424 def collision_pairs(self):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
425 """The set of entity pairs in collision in this timestep"""
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
426 if self._collision_pairs is None:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
427 position = getattr(self.world.components, self.position_component)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
428 collision = getattr(self.world.components, self.collision_component)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
429 pairs = self._collision_pairs = set()
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
430 for pair in self.broad_phase.collision_pairs:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
431 entity1, entity2 = pair
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
432 position1 = position[entity1].position
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
433 position2 = position[entity2].position
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
434 radius1 = collision[entity1].radius
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
435 radius2 = collision[entity2].radius
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
436 separation = position2 - position1
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
437 if separation.get_length_sqrd() <= (radius1 + radius2)**2:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
438 normal = separation.normalized()
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
439 pair.set_point_normal(
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
440 normal * radius1 + position1, normal,
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
441 normal * -radius2 + position2, -normal)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
442 pairs.add(pair)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
443 return self._collision_pairs
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
444
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
445 def query_point(self, x_or_point, y=None, from_mask=0xffffffff):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
446 """Hit test at the point specified.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
447
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
448 :param x_or_point: x coordinate (float) or sequence of (x, y) floats.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
449
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
450 :param y: y coordinate (float) if x is not a sequence
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
451
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
452 :param from_mask: Bit mask used to filter query results. This value
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
453 is bit ANDed with candidate entities' ``collision.into_mask``.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
454 If the result is non-zero, then it is considered a hit. By
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
455 default all entities colliding with the input point are
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
456 returned.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
457
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
458 :return: A set of entities where the point is inside their collision
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
459 radii as of the last time step.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
460
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
461 """
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
462 if y is None:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
463 point = Vec2d(x_or_point)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
464 else:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
465 point = Vec2d(x_or_point, y)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
466 hits = set()
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
467 position = getattr(self.world.components, self.position_component)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
468 collision = getattr(self.world.components, self.collision_component)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
469 for entity in self.broad_phase.query_point(x_or_point, y, from_mask):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
470 separation = point - position[entity].position
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
471 if separation.get_length_sqrd() <= collision[entity].radius**2:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
472 hits.add(entity)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
473 return hits
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
474
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
475
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
476 def dispatch_events(collision_system):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
477 """Collision handler that dispatches `on_collide()` events to entities
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
478 marked for collision by the specified collision system. The `on_collide()`
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
479 event handler methods are defined by the application on the desired entity
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
480 classes. These methods should have the following signature::
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
481
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
482 def on_collide(self, other_entity, collision_point, collision_normal):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
483 '''Handle A collision between this entity and `other_entity`
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
484
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
485 - other_entity (Entity): The other entity in collision with
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
486 `self`
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
487
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
488 - collision_point (Vec2d): The point on this entity (`self`)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
489 where the collision occurred. Note this may be `None` for
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
490 some collision systems that do not report it.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
491
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
492 - collision_normal (Vec2d): The normal vector at the point of
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
493 collision. As with `collision_point`, this may be None for
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
494 some collision systems.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
495 '''
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
496
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
497 Note the arguments to `on_collide()` are always passed positionally, so you
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
498 can use different argument names than above if desired.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
499
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
500 If a pair of entities are in collision, then the event will be dispatched
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
501 to both objects in arbitrary order if all of their collision masks align.
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
502 """
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
503 collision = getattr(collision_system.world.components,
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
504 collision_system.collision_component)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
505 for pair in collision_system.collision_pairs:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
506 entity1, entity2 = pair
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
507 if pair.info is not None:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
508 args1, args2 = pair.info
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
509 else:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
510 args1 = entity1, None, None
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
511 args2 = entity2, None, None
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
512 try:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
513 on_collide = entity1.on_collide
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
514 masks_align = collision[entity2].from_mask & collision[entity1].into_mask
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
515 except (AttributeError, KeyError):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
516 pass
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
517 else:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
518 if masks_align:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
519 on_collide(*args2)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
520 try:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
521 on_collide = entity2.on_collide
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
522 masks_align = collision[entity1].from_mask & collision[entity2].into_mask
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
523 except (AttributeError, KeyError):
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
524 pass
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
525 else:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
526 if masks_align:
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
527 on_collide(*args1)
09b581087d68 Added base files for grease
KarstenBock@gmx.net
parents:
diff changeset
528