def circle_collision(self, object): from scripts.gamecomponents.Disc import Disc if self._pos.get_distance(object.pos) <= self._radius + object.radius: Logger.debug("KINEMATICS: border_collision distance=%s self.radius=%s object.radius=%s", str(self._pos.get_distance(object.pos)), str(self._radius), str(object.radius)) vec_pos_diff = object.pos - self._pos vec_to = self._vel.projection(vec_pos_diff) obj_vec_to = object._vel.projection(vec_pos_diff) vec_side = self._vel - vec_to obj_vec_side = object._vel - obj_vec_to after_vec_to = (vec_to * (self._mass - object._mass) + (2 * object._mass * obj_vec_to)) / ( self._mass + object._mass) after_obj_vec_to = (obj_vec_to * (object._mass - self._mass) + (2 * self._mass * vec_to)) / ( self._mass + object._mass) # Change velocity only if it is Disc if isinstance(self, Disc): self._vel = after_vec_to + vec_side if isinstance(object, Disc): object._vel = after_obj_vec_to + obj_vec_side self.apply_speed_limit() self.correct_position_post_collision(object)
def __init__(self,pitch_name): """ define constructor of class Pitch. """ Logger.info("PITCH: Initializing pitch") self.i_min = 42 self.i_max = 762 self.j_min = 154 self.j_max = 562 self.i_border = 50 Logger.debug("PITCH: init i_min=%s i_max=%s j_min=%s j_max=%s i_border=%s", str(self.i_min), str(self.i_max), str(self.j_min), str(self.j_max), str(self.i_border)) goal_width = 150 j_middle = 0.5 * (self.j_min + self.j_max) self.goals = [Goal(self.i_min, j_middle, goal_width), Goal(self.i_max, j_middle, goal_width)] # drawable part # TODO better pitch image Logger.info("PITCH: loading image") # self._image = pygame.image.load("resources/graphics/pitch.png") self._image = pygame.image.load(pitch_name) self._pos = Vector(0, 0)
def collision_effect(self): # TODO: a proper calculation of momentum and change in speed after collisions Logger.debug("KINEMATICS: collision_effect vel before = %s", str(self._vel)) self._vel.length *= self.COEFFICIENT_OF_BORDER_COLLISION Logger.debug("KINEMATICS: collision_effect vel after = %s", str(self._vel))
def __init__(self, x_init, y_init, mass, radius, borders): Logger.debug("KINEMATICS: PhysicsObject init(x_init=%s, y_init=%s, mass=%s, radius=%s, borders=%s)", str(x_init), str(y_init), str(mass), str(radius), str(borders)) self._pos = Vector(x_init, y_init) self._mass = mass self._radius = radius self._vel = Vector(0, 0) self._borders = borders
def __init__(self, image, imagerect, position): """ :param image: shape or image to be drawn :param position: position on screen (of type Point) :param imagerect: rectangle of image to be displayed """ Logger.debug("DRAWABLE: init(position=(%s)", str(position)) self._image = image self._pos = position
def border_collision(self, axis): from scripts.gamecomponents.Disc import Disc Logger.debug("KINEMATICS: border_collision axis=%s _vel=%s", str(axis), str(self._vel)) if isinstance(self, Disc): if axis == 'x': self._vel.x = -self._vel.x self.collision_effect() self.correct_position_in_borders() if axis == 'y': self._vel.y = -self._vel.y self.collision_effect() self.correct_position_in_borders() Logger.debug("KINEMATICS: _vel=%s", str(self._vel))
def in_goal(self, i, j, r): """ :param i: x coordinates of disk :param j: y coordinates of disk :param r: radius of disk :raise: WrongTypeException if i, j or r is not type of int, OutOfRangeException if disk is out of pitch """ if abs(i - self.i) < 1.2 * r and self.j_min < j < self.j_max: Logger.debug("GOAL: in_goal returned True") return True else: Logger.debug("GOAL: in_goal returned False") return False
def correct_position_post_collision(self, obj): """ Dislodges objects stuck in each other. """ distance_vector = self.pos - obj.pos if distance_vector.length < self.radius + obj.radius: distance_vector.length = self.radius + obj.radius self._pos = obj.pos + distance_vector self.correct_position_in_borders() Logger.debug("KINEMATICS: correct_position_post_collision distance_vector=%s self.radius=%s obj.radius=%s", str(distance_vector), str(self.radius), str(obj.radius)) distance_vector = obj.pos - self.pos if distance_vector.length < obj.pos - self.pos: distance_vector.length = self.radius + obj.radius obj._pos = self._pos + distance_vector obj.correct_position_in_borders() Logger.debug("KINEMATICS: correct_position_post_collision distance_vector=%s self.radius=%s obj.radius=%s", str(distance_vector), str(self.radius), str(obj.radius))
def __init__(self, x, y_center, width): """ define constructor of class Goal. If the value will not be equal 'L' or 'R', the function raise the ValueError :param x: x position :param y_center: y coordinate of the center of goal :param width: width of goal which is measured along y axis. :param goal_type: 'l' for left and 'r' for right goal :return: none :raise: WrongTypeException if v is not type of int """ self.j_min = y_center - 0.5 * width self.j_max = y_center + 0.5 * width self.i = x Logger.debug("GOAL: init(jmin=%s, jmax=%s, width=%s)", str(self.j_min), str(self.j_max), str(self.i))
def correct_position_in_borders(self): """ Dislodges objects stuck in the pitch borders """ x_min, x_max = self._borders[0] y_min, y_max = self._borders[1] log = False if self.pos.x - self.radius < x_min: self.pos.x = x_min + self.radius log = True if self.pos.x + self.radius > x_max: self.pos.x = x_max - self.radius log = True if self.pos.y - self.radius < y_min: self.pos.y = y_min + self.radius log = True if self.pos.y + self.radius > y_max: self.pos.y = y_max - self.radius log = True if log: Logger.debug("KINEMATICS: correct_position_in_borders pos.x=%s pos.y=%s", str(self.pos.x), str(self.pos.y))
def circle_collision(self, object): from scripts.gamecomponents.Disc import Disc if self._pos.get_distance( object.pos) <= self._radius + object.radius: # impact Logger.debug( "KINEMATICS: border_collision distance=%s self.radius=%s object.radius=%s", str(self._pos.get_distance(object.pos)), str(self._radius), str(object.radius)) vec_pos_diff = object.pos - self._pos vec_to = self._vel.projection(vec_pos_diff) obj_vec_to = object._vel.projection(vec_pos_diff) vec_side = self._vel - vec_to obj_vec_side = object._vel - obj_vec_to after_vec_to = (vec_to * (self._mass - object._mass) + (2 * object._mass * obj_vec_to)) / (self._mass + object._mass) after_obj_vec_to = (obj_vec_to * (object._mass - self._mass) + (2 * self._mass * vec_to)) / (self._mass + object._mass) dx = self._pos[0] - object._pos[0] dy = self._pos[1] - object._pos[1] distance = math.hypot(dx, dy) tangent = math.atan2(dy, dx) # self._radius = 2*tangent - self._radius # object._radius = 2*tangent - object._radius (self._vel, object._vel) = (object._vel, self._vel) angle = 0.5 * math.pi + tangent # Change velocity only if it is Disc if isinstance(self, Disc): self._vel = after_vec_to + vec_side if isinstance(object, Disc): object._vel = after_obj_vec_to + obj_vec_side self.apply_speed_limit() self.correct_position_post_collision(object) self._pos[0] += math.sin(angle) self._pos[1] -= math.cos(angle) object._pos[0] -= math.sin(angle) object._pos[1] += math.cos(angle)
def load_image(self, image1, image2): """ Method used to load sprite for Mallet according to Player. :return: None """ from Player import Player if self._player.playerColor == Player.PLAYER_BLUE: Logger.debug("MALLET: load_image playerColor = PLAYER_BLUE") image = image1 elif self._player.playerColor == Player.PLAYER_RED: Logger.debug("MALLET: load_image playerColor = PLAYER_RED") image = image2 else: Logger.error("MALLET: Invalid value for player (" + self._player.playerColor + ")") raise ValueError('Invalid value for player (' + self._player.playerColor + ')') self._image = pygame.transform.scale( pygame.image.load(image), (int(2 * self.radius), int(2 * self.radius)))
def apply_speed_limit(self): from scripts.gamecomponents.Disc import Disc from scripts.gamecomponents.Mallet import Mallet Logger.debug("KINEMATICS: apply_speed_limit MAX_DISC_VELOCITY=%s MAX_MALLET_VELOCITY=%s vel=%s", str(self.MAX_DISC_VELOCITY), str(self.MAX_MALLET_VELOCITY), str(self._vel.length)) if isinstance(self, Disc) and self._vel.length > self.MAX_DISC_VELOCITY: Logger.debug("KINEMATICS: apply_speed_limit is a Disc") self._vel.length = self.MAX_DISC_VELOCITY if isinstance(self, Mallet) and self._vel.length > self.MAX_MALLET_VELOCITY: Logger.debug("KINEMATICS: apply_speed_limit is a Mallet") self._vel.length = self.MAX_MALLET_VELOCITY
def move_to(self, x, y): from scripts.gamecomponents.Kinematics import Vector Logger.debug("MALLET: move_to(%s,%s) pos before =%s", str(x), str(y), str(self._pos)) move_vector = Vector(x, y) - self._pos if move_vector.length > PhysicsObject.MAX_MALLET_VELOCITY: move_vector.length = PhysicsObject.MAX_MALLET_VELOCITY self.pos.state = (self._pos.x + move_vector.x, self._pos.y + move_vector.y) Logger.debug("MALLET: move_to(%s,%s) pos after =%s", str(x), str(y), str(self._pos)) self.correct_position_in_borders() Logger.debug("MALLET: move_to(%s,%s) pos after position correction=%s", str(x), str(y), str(self._pos))
def is_border_collision(self, object): """ check a collision between disk and a border of the pitch :param object: object with x,y,radius parameters :return: 'x' or 'y' if the collision between a disk/mallet and the border of pitch have taken place, false - if it haven't :raise: WrongTypeException if object is not type of disc/mallet """ # TODO: Is there a way to do it better ? if not isinstance(object, Disc) and not isinstance(object, Mallet): Logger.error("PITCH: is_border_collision raised WrongTypeException") raise WrongTypeException if object.pos.x - object.radius < self.i_min or object.pos.x + object.radius > self.i_max: Logger.debug("PITCH: is_border_collision return x") return 'x' if object.pos.y - object.radius < self.j_min or object.pos.y + object.radius > self.j_max: Logger.debug("PITCH: is_border_collision return y") return 'y' Logger.debug("PITCH: is_border_collision return False") return False
def friction(self): Logger.debug("KINEMATICS: friction vel before = %s", str(self._vel)) self._vel.length *= self.COEFFICIENT_OF_FRICTION self._vel.length = 0 if self._vel.length < self.STOPPING_VELOCITY else self._vel.length Logger.debug("KINEMATICS: friction vel after = %s", str(self._vel))