def get_colliders(self, bounding_shape, position, ignored=[], typefilter=None): """ Returns a list of game objects in the world that are currently colliding with the given bounding_shape at the given position. This method performs no collision resolution. This method is useful for collision between game objects in the world and some bounding shape that may not be "in" the world (e.g., a temporary bounding shape used for abilities). Arguments: bounding_shape -- The shape to check objects against. position -- The position of the shape to check objects against. ignored -- A list of game objects to ignore collision with. typefilter -- A class type that the colliding object must an instance (or derived instance) of. """ colliders = [] for object in self.objects: if object.bounding_shape is None: # Can't collide with an object that has no bounding shape. continue if typefilter is not None and not isinstance(object, typefilter): # Only collide with filtered objects. continue result = CollisionDetector.check_collision(bounding_shape, position, object.bounding_shape, object.position) if result is not False and object not in ignored: colliders.append(object) return colliders
def run(self): AbilityInstance.run(self) if self.player.world.is_master: # create the bounding circle to check collision against bounding_cone = collision.BoundingCone(self.hit_radius, self.player.rotation, self.hit_angle) # get a list of colliding players self.targets = self.player.world.get_colliders( bounding_cone, self.player.position, [self.player], objects.Player) # for each player, apply effects for player in self.targets: # get force vector for other player force_vector = ((player.position[0] - self.player.position[0], player.position[1] - self.player.position[1])) force_vector = CollisionDetector.normalise_vector(force_vector) player.force_vector = (force_vector[0] * self.starting_strength, force_vector[1] * self.starting_strength) print "Gust of wind collided with another player!" # end the effect self.expire()
def apply_force(self, vector, strength, acceleration_factor=1, duration=False): self.force_vector = CollisionDetector.normalise_vector(vector) self.force_strength = strength self.force_duration = duration self.force_acceleration = acceleration_factor self.force_applied = True
def update(self, dt): AbilityInstance.update(self, dt) if self.player.world.is_master: if self.player_hooked is None: return if collision.CollisionDetector.check_collision(collision.BoundingCircle(8), self.player_hooked.position, self.player.bounding_shape, self.player.position): self.player_hooked.is_hooked = False self.player_hooked.force_vector = (0, 0) self.expire() else: fv = (self.player.position[0] - self.player_hooked.position[0], self.player.position[1] - self.player_hooked.position[1]) fv = CollisionDetector.normalise_vector(fv) fv = (fv[0] * self.retraction_speed, fv[1] * self.retraction_speed) self.player_hooked.force_vector = fv
def run(self): AbilityInstance.run(self) if self.player.world.is_master: # create the bounding circle to check collision against bounding_cone = collision.BoundingCone(self.hit_radius, self.player.rotation, self.hit_angle) # get a list of colliding players self.targets = self.player.world.get_colliders(bounding_cone, self.player.position, [self.player], objects.Player) # for each player, apply effects for player in self.targets: # get force vector for other player force_vector = ((player.position[0] - self.player.position[0], player.position[1] - self.player.position[1])) force_vector = CollisionDetector.normalise_vector(force_vector) player.force_vector = (force_vector[0] * self.starting_strength, force_vector[1] * self.starting_strength) # print "Gust of wind collided with another player!" # end the effect self.expire()
def _move(self, move_vector, already_collided=None): """ Moves the object by the given movement vector (relative to the current position and performs collision detection and resolution. Arguments: move_vector -- The vector containing the x and z components to move the object in (relative to the current position). already_collided -- A set of objects previously collided with in this gamestate update that need to persist through _move() calls. """ # If the movement vector is 0, we don't have to do anything. if move_vector == (0, 0): return # Calculate the new position we want to move to. new_pos = (self._position[0] + move_vector[0], self._position[1] + move_vector[1]) # If the object doesn't have a bounding shape then we don't need to # worry about collision detection & resolution and can simply update # the position and return. if self.bounding_shape is None: self.position = new_pos return # Otherwise we need to do collision detection. # @todo: possible optimizations: # - Check un-passable objects first so we can restart _move sooner (if needed). # - Check only against nearby objects (quadtree?) # Initialize the set of objects we collide with in this object's # update (for later use in collision resolution). if already_collided is None: # If already_collided (a function argument) was not pased then no # objects have already collided with this object during this # object's update, so initialize it to an empty set. collided_objects = set() else: # Otherwise we already have some objects we have collided with (but # not performed resolution on), so initialize our set to those # previously collided with objects. collided_objects = already_collided # Loop over all objects in the world to test against. for object in self.world.objects: if self == object: # Can't collide with ourself. continue if object.bounding_shape is None: # Can't collide with an object that has no bounding shape. continue # Cast a ray from where we are to where we are moving to and check # if this ray collides with the object. This is to look for any # objects that may be between our old position and our new # position. This result will be True if the ray collides with the # object and False if not. rayResult = CollisionDetector.is_between(object.bounding_shape, object.position, self.position, new_pos) # Check if our bounding shape at our new position would overlap # with the object's bounding shape. The result will be None if # there is no overlap, or if there is a collision it will be the # position we should reset to if the object is not passable as a # part of collision resolution. shapeResult = CollisionDetector.check_collision_and_resolve(self.bounding_shape, new_pos, self.position, object.bounding_shape, object.position) if rayResult is not False and shapeResult is False: # The object collided with our ray, but not with our shape, # so we must have jumped over it. # If the object is not passable, then this is a critical error # and we will completely deny the move by returning. if not object.isPassable: return # Otherwise add the object to our set of collided objects. collided_objects.add(object) if shapeResult is not False: # Our new bounding shape will be overlapping with another # object's bounding shape. # Add the object to our set of collided objects. collided_objects.add(object) # If the object is not passable, then we need to move to the # new position that is provided by the result and redo the # collision detection based on that new position. Call # self._move() to do this and then return. if not object.isPassable: # We will use the shapeResult value (a corrected movement # vector) returned from check_collision to move ourself # flush against the object we collided with. move_mm = (move_vector[0] + shapeResult[0],move_vector[1] + shapeResult[1]) self._move((move_vector[0] + shapeResult[0], move_vector[1] + shapeResult[1]), set([object])) return # Now that collision detection is complete, update our position to the # previously calculated new position. self.position = new_pos # We now have a set of objects that we have collided with. Call # .collide() on each of those objects to perform collision resolution. for object in collided_objects: object.collide(self)