def draw_rectangle_filled(center_x: float, center_y: float, width: float, height: float, color: Color, tilt_angle: float = 0): """ Draw a filled-in rectangle. :param float center_x: x coordinate of rectangle center. :param float center_y: y coordinate of rectangle center. :param float width: width of the rectangle. :param float height: height of the rectangle. :param Color color: color, specified in a list of 3 or 4 bytes in RGB or RGBA format. :param float tilt_angle: rotation of the rectangle. Defaults to zero. """ p1 = [-width // 2 + center_x, -height // 2 + center_y] p2 = [width // 2 + center_x, -height // 2 + center_y] p3 = [width // 2 + center_x, height // 2 + center_y] p4 = [-width // 2 + center_x, height // 2 + center_y] if tilt_angle != 0: p1 = rotate_point(p1[0], p1[1], center_x, center_y, tilt_angle) p2 = rotate_point(p2[0], p2[1], center_x, center_y, tilt_angle) p3 = rotate_point(p3[0], p3[1], center_x, center_y, tilt_angle) p4 = rotate_point(p4[0], p4[1], center_x, center_y, tilt_angle) _generic_draw_line_strip((p1, p2, p4, p3), color, gl.GL_TRIANGLE_STRIP)
def _create_rects(rect_list: Iterable[Sprite]) -> List[float]: """ Create a vertex buffer for a set of rectangles. """ v2f = [] for shape in rect_list: x1 = -shape.width / 2 + shape.center_x x2 = shape.width / 2 + shape.center_x y1 = -shape.height / 2 + shape.center_y y2 = shape.height / 2 + shape.center_y p1 = [x1, y1] p2 = [x2, y1] p3 = [x2, y2] p4 = [x1, y2] if shape.angle: p1 = rotate_point(p1[0], p1[1], shape.center_x, shape.center_y, shape.angle) p2 = rotate_point(p2[0], p2[1], shape.center_x, shape.center_y, shape.angle) p3 = rotate_point(p3[0], p3[1], shape.center_x, shape.center_y, shape.angle) p4 = rotate_point(p4[0], p4[1], shape.center_x, shape.center_y, shape.angle) v2f.extend([p1[0], p1[1], p2[0], p2[1], p3[0], p3[1], p4[0], p4[1]]) return v2f
def _set_angle(self, new_value: float): """ Set the angle of the sprite's rotation. """ if new_value != self._angle: old_angle = 0.0 if self.rot_point_relative: old_angle = self._angle self.clear_spatial_hashes() self._angle = new_value self._point_list_cache = None self.add_spatial_hashes() if self.rotation_point: rotate_x, rotate_y = self.rotation_point self_x, self_y = self.center_x, self.center_y if old_angle: rotate_x += self_x rotate_y += self_y rotate_x, rotate_y = rotate_point(rotate_x, rotate_y, self_x, self_y, old_angle) sprite_rotate = rotate_point(self_x, self_y, rotate_x, rotate_y, new_value - old_angle) self.set_position(sprite_rotate[0], sprite_rotate[1]) for sprite_list in self.sprite_lists: sprite_list.update_angle(self)
def get_points(self) -> Tuple[Tuple[float, float]]: """ Get the corner points for the rect that makes up the sprite. """ if self._point_list_cache is not None: return self._point_list_cache if self._points is not None: point_list = [] for point in range(len(self._points)): point = (self._points[point][0] + self.center_x, self._points[point][1] + self.center_y) point_list.append(point) self._point_list_cache = tuple(point_list) else: x1, y1 = arcade.rotate_point(self.center_x - self.width / 4, self.center_y - self.width / 4, self.center_x, self.center_y, self.angle) x2, y2 = arcade.rotate_point(self.center_x + self.width / 4, self.center_y - self.height / 4, self.center_x, self.center_y, self.angle) x3, y3 = arcade.rotate_point(self.center_x + self.width / 4, self.center_y + self.height / 4, self.center_x, self.center_y, self.angle) x4, y4 = arcade.rotate_point(self.center_x - self.width / 4, self.center_y + self.height / 4, self.center_x, self.center_y, self.angle) self._point_list_cache = ((x1, y1), (x2, y2), (x3, y3), (x4, y4)) return self._point_list_cache
def update(self, delta_time, main): # Movimiento en mi mismo self.a += 10 * math.sin(main.frame_count / 4) # Movimiento para mantenerlo donde corresponde self.x, self.y = arcade.rotate_point(self.x, self.y, win.CENTER_W + main.view_left, win.CENTER_H + main.view_bottom, main.change_angle) # Movimiento para alcanzar al circulo self.t += delta_time if (self.t > 0): # seg self.t = 0 # Position the start at the enemy's current location start_x = self.x start_y = self.y # Get the destination location for the bullet dest_x = main.circle.x dest_y = main.circle.y # Do math to calculate how to get the bullet to the destination. # Calculation the angle in radians between the start points # and end points. This is the angle the bullet will travel. x_diff = dest_x - start_x y_diff = dest_y - start_y self.d = math.atan2(y_diff, x_diff) self.x += math.cos(self.d) * 3 self.y += math.sin(self.d) * 3
def get_adjusted_hit_box(self) -> List[List[float]]: """ Get the points that make up the hit box for the rect that makes up the sprite, including rotation and scaling. """ # If we've already calculated the adjusted hit box, use the cached version if self._point_list_cache is not None: return self._point_list_cache # If there is no hitbox, use the width/height to get one if self._points is None and self._texture: self._points = self._texture.hit_box_points if self._points is None and self._width: x1, y1 = -self._width / 2, -self._height / 2 x2, y2 = +self._width / 2, -self._height / 2 x3, y3 = +self._width / 2, +self._height / 2 x4, y4 = -self._width / 2, +self._height / 2 self._points = [[x1, y1], [x2, y2], [x3, y3], [x4, y4]] if self._points is None and self.texture is not None: self._points = self.texture.hit_box_points if self._points is None: raise ValueError( "Error trying to get the hit box of a sprite, when no hit box is set.\nPlease make sure the " "Sprite.texture is set to a texture before trying to draw or do collision testing.\n" "Alternatively, manually call Sprite.set_hit_box with points for your hitbox." ) # Adjust the hitbox point_list = [] for point in self._points: # Get a copy of the point point = [point[0], point[1]] # Scale the point if self.scale != 1: point[0] *= self.scale point[1] *= self.scale # Rotate the point if self.angle: point = rotate_point(point[0], point[1], 0, 0, self.angle) # Offset the point point = [point[0] + self.center_x, point[1] + self.center_y] point_list.append(point) # Cache the results self._point_list_cache = point_list # if self.texture: # print(self.texture.name, self._point_list_cache) return self._point_list_cache
def create_rectangle(center_x: float, center_y: float, width: float, height: float, color: Color, border_width: float = 1, tilt_angle: float = 0, filled=True) -> Shape: """ This function creates a rectangle using a vertex buffer object. Creating the rectangle, and then later drawing it with ``render_rectangle`` is faster than calling ``draw_rectangle``. Args: center_x: center_y: width: height: color: border_width: tilt_angle: filled: Returns: """ data: List[Point] = cast(List[Point], get_rectangle_points(center_x, center_y, width, height, tilt_angle)) if filled: shape_mode = gl.GL_TRIANGLE_STRIP data[-2:] = reversed(data[-2:]) else: i_lb = center_x - width / 2 + border_width / 2, center_y - height / 2 + border_width / 2 i_rb = center_x + width / 2 - border_width / 2, center_y - height / 2 + border_width / 2 i_rt = center_x + width / 2 - border_width / 2, center_y + height / 2 - border_width / 2 i_lt = center_x - width / 2 + border_width / 2, center_y + height / 2 - border_width / 2 o_lb = center_x - width / 2 - border_width / 2, center_y - height / 2 - border_width / 2 o_rb = center_x + width / 2 + border_width / 2, center_y - height / 2 - border_width / 2 o_rt = center_x + width / 2 + border_width / 2, center_y + height / 2 + border_width / 2 o_lt = center_x - width / 2 - border_width / 2, center_y + height / 2 + border_width / 2 data = [o_lt, i_lt, o_rt, i_rt, o_rb, i_rb, o_lb, i_lb, o_lt, i_lt] if tilt_angle != 0: point_list_2: List[Point] = [] for point in data: new_point = rotate_point(point[0], point[1], center_x, center_y, tilt_angle) point_list_2.append(new_point) data = point_list_2 border_width = 1 shape_mode = gl.GL_TRIANGLE_STRIP # _generic_draw_line_strip(point_list, color, gl.GL_TRIANGLE_STRIP) # shape_mode = gl.GL_LINE_STRIP # data.append(data[0]) shape = create_line_generic(data, color, shape_mode, border_width) return shape
def test_rotate_point(): x = 0 y = 0 cx = 0 cy = 0 angle = 0 rx, ry = arcade.rotate_point(x, y, cx, cy, angle) assert rx == 0 assert ry == 0 x = 0 y = 0 cx = 0 cy = 0 angle = 90 rx, ry = arcade.rotate_point(x, y, cx, cy, angle) assert rx == 0 assert ry == 0 x = 50 y = 50 cx = 0 cy = 0 angle = 0 rx, ry = arcade.rotate_point(x, y, cx, cy, angle) assert rx == 50 assert ry == 50 x = 50 y = 0 cx = 0 cy = 0 angle = 90 rx, ry = arcade.rotate_point(x, y, cx, cy, angle) assert rx == 0 assert ry == 50 x = 20 y = 10 cx = 10 cy = 10 angle = 180 rx, ry = arcade.rotate_point(x, y, cx, cy, angle) assert rx == 0 assert ry == 10
def draw_arc_outline(center_x: float, center_y: float, width: float, height: float, color: Color, start_angle: float, end_angle: float, border_width: float = 1, tilt_angle: float = 0, num_segments: int = 128): """ Draw the outside edge of an arc. Useful for drawing curved lines. :param float center_x: x position that is the center of the arc. :param float center_y: y position that is the center of the arc. :param float width: width of the arc. :param float height: height of the arc. :param Color color: color, specified in a list of 3 or 4 bytes in RGB or RGBA format. :param float start_angle: start angle of the arc in degrees. :param float end_angle: end angle of the arc in degrees. :param float border_width: width of line in pixels. :param float tilt_angle: angle the arc is tilted. :param int num_segments: float of triangle segments that make up this circle. Higher is better quality, but slower render time. """ unrotated_point_list = [] start_segment = int(start_angle / 360 * num_segments) end_segment = int(end_angle / 360 * num_segments) inside_width = (width - border_width / 2) / 2 outside_width = (width + border_width / 2) / 2 inside_height = (height - border_width / 2) / 2 outside_height = (height + border_width / 2) / 2 for segment in range(start_segment, end_segment + 1): theta = 2.0 * math.pi * segment / num_segments x1 = inside_width * math.cos(theta) y1 = inside_height * math.sin(theta) x2 = outside_width * math.cos(theta) y2 = outside_height * math.sin(theta) unrotated_point_list.append([x1, y1]) unrotated_point_list.append([x2, y2]) if tilt_angle == 0: uncentered_point_list = unrotated_point_list else: uncentered_point_list = [] for point in unrotated_point_list: uncentered_point_list.append(rotate_point(point[0], point[1], 0, 0, tilt_angle)) point_list = [] for point in uncentered_point_list: point_list.append((point[0] + center_x, point[1] + center_y)) _generic_draw_line_strip(point_list, color, gl.GL_TRIANGLE_STRIP)
def update(self, delta_time): """ Movement and game logic """ self.earth_angle += 1 self.moon_angle += 5 earth_center_x, earth_center_y = arcade.rotate_point( self.sun_x + self.earth_dist, self.sun_y, self.sun_x, self.sun_y, self.earth_angle) self.moon_shape_list.center_x = earth_center_x self.moon_shape_list.center_y = earth_center_y self.earth_shape_list.angle = self.earth_angle self.moon_shape_list.angle = self.moon_angle
def get_rectangle_points(center_x: float, center_y: float, width: float, height: float, tilt_angle: float = 0) -> PointList: """ Utility function that will return all four coordinate points of a rectangle given the x, y center, width, height, and rotation. Args: center_x: center_y: width: height: tilt_angle: Returns: """ x1 = -width / 2 + center_x y1 = -height / 2 + center_y x2 = -width / 2 + center_x y2 = height / 2 + center_y x3 = width / 2 + center_x y3 = height / 2 + center_y x4 = width / 2 + center_x y4 = -height / 2 + center_y if tilt_angle: x1, y1 = rotate_point(x1, y1, center_x, center_y, tilt_angle) x2, y2 = rotate_point(x2, y2, center_x, center_y, tilt_angle) x3, y3 = rotate_point(x3, y3, center_x, center_y, tilt_angle) x4, y4 = rotate_point(x4, y4, center_x, center_y, tilt_angle) data = [(x1, y1), (x2, y2), (x3, y3), (x4, y4)] return data
def create_ellipse_filled_with_colors(center_x: float, center_y: float, width: float, height: float, outside_color: Color, inside_color: Color, tilt_angle: float = 0, num_segments: int = 32) -> Shape: """ Draw an ellipse, and specify inside/outside color. Used for doing gradients. The function returns a Shape object that can be drawn with ``my_shape.draw()``. Don't create the shape in the draw method, create it in the setup method and then draw it in ``on_draw``. For even faster performance, add multiple shapes into a ShapeElementList and draw that list. This allows nearly unlimited shapes to be drawn just as fast as one. :param float center_x: :param float center_y: :param float width: :param float height: :param Color outside_color: :param float inside_color: :param float tilt_angle: :param int num_segments: :Returns Shape: """ # Create an array with the vertex data # Create an array with the vertex point_list point_list = [(center_x, center_y)] for segment in range(num_segments): theta = 2.0 * 3.1415926 * segment / num_segments x = width * math.cos(theta) + center_x y = height * math.sin(theta) + center_y if tilt_angle: x, y = rotate_point(x, y, center_x, center_y, tilt_angle) point_list.append((x, y)) point_list.append(point_list[1]) color_list = [inside_color] + [outside_color] * (num_segments + 1) return create_line_generic_with_colors(point_list, color_list, gl.GL_TRIANGLE_FAN)
def update(self, delta_time, main): # Actualizar la direccion self.d += math.radians(main.change_angle) # Movimiento para mantenerse en el lugar self.x, self.y = arcade.rotate_point(self.x, self.y, win.CENTER_W + main.view_left, win.CENTER_H + main.view_bottom, main.change_angle) # Avanzar en linea recta self.x += math.cos(self.d) * 5 self.y += math.sin(self.d) * 5 """ Special shot
def get_adjusted_hit_box(self) -> List[List[float]]: """ Get the points that make up the hit box for the rect that makes up the sprite, including rotation and scaling. """ # If we've already calculated the adjusted hit box, use the cached version if self._point_list_cache is not None: return self._point_list_cache # If there is no hitbox, use the width/height to get one if self._points is None and self._texture: self._points = self._texture.unscaled_hitbox_points if self._points is None and self._width: x1, y1 = -self._width / 2, -self._height / 2 x2, y2 = +self._width / 2, -self._height / 2 x3, y3 = +self._width / 2, +self._height / 2 x4, y4 = -self._width / 2, +self._height / 2 self._points = [[x1, y1], [x2, y2], [x3, y3], [x4, y4]] if self._points is None: raise ValueError( "Trying to get the hit box of a sprite that doesn't have one.") # Adjust the hitbox point_list = [] for point_idx in range(len(self._points)): # Get the point point = [self._points[point_idx][0], self._points[point_idx][1]] # Scale the point if self.scale != 1: point[0] *= self.scale point[1] *= self.scale # Rotate the point if self.angle: point = rotate_point(point[0], point[1], 0, 0, self.angle) # Offset the point point = [point[0] + self.center_x, point[1] + self.center_y] point_list.append(point) # Cache the results self._point_list_cache = point_list # if self.texture: # print(self.texture.name, self._point_list_cache) return self._point_list_cache
def draw_arc_filled(center_x: float, center_y: float, width: float, height: float, color: Color, start_angle: float, end_angle: float, tilt_angle: float = 0, num_segments: int = 128): """ Draw a filled in arc. Useful for drawing pie-wedges, or Pac-Man. :param float center_x: x position that is the center of the arc. :param float center_y: y position that is the center of the arc. :param float width: width of the arc. :param float height: height of the arc. :param Color color: color, specified in a list of 3 or 4 bytes in RGB or RGBA format. :param float start_angle: start angle of the arc in degrees. :param float end_angle: end angle of the arc in degrees. :param float tilt_angle: angle the arc is tilted. :param float num_segments: Number of line segments used to draw arc. """ unrotated_point_list = [[0.0, 0.0]] start_segment = int(start_angle / 360 * num_segments) end_segment = int(end_angle / 360 * num_segments) for segment in range(start_segment, end_segment + 1): theta = 2.0 * 3.1415926 * segment / num_segments x = width * math.cos(theta) / 2 y = height * math.sin(theta) / 2 unrotated_point_list.append([x, y]) if tilt_angle == 0: uncentered_point_list = unrotated_point_list else: uncentered_point_list = [] for point in unrotated_point_list: uncentered_point_list.append( rotate_point(point[0], point[1], 0, 0, tilt_angle)) point_list = [] for point in uncentered_point_list: point_list.append((point[0] + center_x, point[1] + center_y)) _generic_draw_line_strip(point_list, color, gl.GL_TRIANGLE_FAN)
def _set_angle(self, new_value: float): """ Set the angle of the sprite's rotation. """ if new_value != self._angle: self.clear_spatial_hashes() self._angle = new_value self._point_list_cache = None self.add_spatial_hashes() rotate_x, rotate_y = self.rotation_point if rotate_x or rotate_y: sprite_rotate = rotate_point(self.center_x, self.center_y, rotate_x, rotate_y, new_value) self.set_position(sprite_rotate[0], sprite_rotate[1]) for sprite_list in self.sprite_lists: sprite_list.update_angle(self)
def create_arc_outline(center_x: float, center_y: float, width: float, height: float, color: arcade.Color, start_angle: float, end_angle: float, border_width: float = 1, tilt_angle: float = 0, num_segments: int = 256): """ Creates arc outline """ unrotated_point_list = [] inside_width = width - border_width / 2 outside_width = width + border_width / 2 inside_height = height - border_width / 2 outside_height = height + border_width / 2 for segment in range(num_segments + 1): theta = math.pi / 180 * (start_angle + segment * (end_angle - start_angle) / num_segments) x1 = inside_width * math.cos(theta) y1 = inside_height * math.sin(theta) x2 = outside_width * math.cos(theta) y2 = outside_height * math.sin(theta) unrotated_point_list.append([x1, y1]) unrotated_point_list.append([x2, y2]) if tilt_angle == 0: uncentered_point_list = unrotated_point_list else: uncentered_point_list = [] for point in unrotated_point_list: uncentered_point_list.append( arcade.rotate_point(point[0], point[1], 0, 0, tilt_angle)) point_list = [] for point in uncentered_point_list: point_list.append((point[0] + center_x, point[1] + center_y)) shape_mode = gl.GL_LINE_STRIP return arcade.create_line_generic(point_list, color, shape_mode, border_width)
def create_ellipse(center_x: float, center_y: float, width: float, height: float, color: Color, border_width: float = 1, tilt_angle: float = 0, num_segments: int = 32, filled=True) -> Shape: """ This creates an ellipse vertex buffer object (VBO). The function returns a Shape object that can be drawn with ``my_shape.draw()``. Don't create the shape in the draw method, create it in the setup method and then draw it in ``on_draw``. For even faster performance, add multiple shapes into a ShapeElementList and draw that list. This allows nearly unlimited shapes to be drawn just as fast as one. """ # Create an array with the vertex point_list point_list = [] for segment in range(num_segments): theta = 2.0 * 3.1415926 * segment / num_segments x = width * math.cos(theta) + center_x y = height * math.sin(theta) + center_y if tilt_angle: x, y = rotate_point(x, y, center_x, center_y, tilt_angle) point_list.append((x, y)) if filled: half = len(point_list) // 2 interleaved = itertools.chain.from_iterable( itertools.zip_longest(point_list[:half], reversed(point_list[half:]))) point_list = [p for p in interleaved if p is not None] shape_mode = gl.GL_TRIANGLE_STRIP else: point_list.append(point_list[0]) shape_mode = gl.GL_LINE_STRIP return create_line_generic(point_list, color, shape_mode, border_width)
def draw_ellipse_filled(center_x: float, center_y: float, width: float, height: float, color: Color, tilt_angle: float = 0, num_segments: int = 128): """ Draw a filled in ellipse. :param float center_x: x position that is the center of the circle. :param float center_y: y position that is the center of the circle. :param float width: width of the ellipse. :param float height: height of the ellipse. :param Color color: color, specified in a list of 3 or 4 bytes in RGB or RGBA format. :param float tilt_angle: Angle in degrees to tilt the ellipse. :param int num_segments: float of triangle segments that make up this circle. Higher is better quality, but slower render time. """ unrotated_point_list = [] for segment in range(num_segments): theta = 2.0 * 3.1415926 * segment / num_segments x = (width / 2) * math.cos(theta) y = (height / 2) * math.sin(theta) unrotated_point_list.append([x, y]) if tilt_angle == 0: uncentered_point_list = unrotated_point_list else: uncentered_point_list = [] for point in unrotated_point_list: uncentered_point_list.append( rotate_point(point[0], point[1], 0, 0, tilt_angle)) point_list = [] for point in uncentered_point_list: point_list.append((point[0] + center_x, point[1] + center_y)) _generic_draw_line_strip(point_list, color, gl.GL_TRIANGLE_FAN)
def create_ellipse_filled_with_colors(center_x: float, center_y: float, width: float, height: float, outside_color: Color, inside_color: Color, tilt_angle: float = 0, num_segments: int = 32) -> Shape: """ Draw an ellipse, and specify inside/outside color. Used for doing gradients. :param float center_x: :param float center_y: :param float width: :param float height: :param Color outside_color: :param float inside_color: :param float tilt_angle: :param int num_segments: :Returns Shape: """ # Create an array with the vertex data # Create an array with the vertex point_list point_list = [(center_x, center_y)] for segment in range(num_segments): theta = 2.0 * 3.1415926 * segment / num_segments x = width * math.cos(theta) + center_x y = height * math.sin(theta) + center_y if tilt_angle: x, y = rotate_point(x, y, center_x, center_y, tilt_angle) point_list.append((x, y)) point_list.append(point_list[1]) color_list = [inside_color] + [outside_color] * (num_segments + 1) return create_line_generic_with_colors(point_list, color_list, gl.GL_TRIANGLE_FAN)
def create_ellipse(center_x: float, center_y: float, width: float, height: float, color: Color, border_width: float = 1, tilt_angle: float = 0, num_segments: int = 32, filled=True) -> Shape: """ This creates an ellipse vertex buffer object (VBO). It can later be drawn with ``render_ellipse_filled``. This method of drawing an ellipse is much faster than calling ``draw_ellipse_filled`` each frame. Note: This can't be unit tested on Appveyor because its support for OpenGL is poor. """ # Create an array with the vertex point_list point_list = [] for segment in range(num_segments): theta = 2.0 * 3.1415926 * segment / num_segments x = width * math.cos(theta) + center_x y = height * math.sin(theta) + center_y if tilt_angle: x, y = rotate_point(x, y, center_x, center_y, tilt_angle) point_list.append((x, y)) if filled: half = len(point_list) // 2 interleaved = itertools.chain.from_iterable( itertools.zip_longest(point_list[:half], reversed(point_list[half:]))) point_list = [p for p in interleaved if p is not None] shape_mode = gl.GL_TRIANGLE_STRIP else: point_list.append(point_list[0]) shape_mode = gl.GL_LINE_STRIP return create_line_generic(point_list, color, shape_mode, border_width)
def draw_rectangle_outline(center_x: float, center_y: float, width: float, height: float, color: Color, border_width: float = 1, tilt_angle: float = 0): """ Draw a rectangle outline. :param float center_x: x coordinate of top left rectangle point. :param float center_y: y coordinate of top left rectangle point. :param float width: width of the rectangle. :param float height: height of the rectangle. :param Color color: color, specified in a list of 3 or 4 bytes in RGB or RGBA format. :param float border_width: width of the lines, in pixels. :param float tilt_angle: rotation of the rectangle. Defaults to zero. """ i_lb = center_x - width / 2 + border_width / 2, center_y - height / 2 + border_width / 2 i_rb = center_x + width / 2 - border_width / 2, center_y - height / 2 + border_width / 2 i_rt = center_x + width / 2 - border_width / 2, center_y + height / 2 - border_width / 2 i_lt = center_x - width / 2 + border_width / 2, center_y + height / 2 - border_width / 2 o_lb = center_x - width / 2 - border_width / 2, center_y - height / 2 - border_width / 2 o_rb = center_x + width / 2 + border_width / 2, center_y - height / 2 - border_width / 2 o_rt = center_x + width / 2 + border_width / 2, center_y + height / 2 + border_width / 2 o_lt = center_x - width / 2 - border_width / 2, center_y + height / 2 + border_width / 2 point_list: List[Point] = [ o_lt, i_lt, o_rt, i_rt, o_rb, i_rb, o_lb, i_lb, o_lt, i_lt ] if tilt_angle != 0: point_list_2: List[Point] = [] for point in point_list: new_point = rotate_point(point[0], point[1], center_x, center_y, tilt_angle) point_list_2.append(new_point) point_list = point_list_2 _generic_draw_line_strip(point_list, color, gl.GL_TRIANGLE_STRIP)
def on_draw(self): ade.start_render() for shape in self.g_space.shapes: (x, y) = shape.body.position type = shape.type if (type == "circle"): ade.draw_circle_filled(x, y, shape.radius, shape.color) rx, ry = ade.rotate_point(x + shape.radius, y, x, y, shape.body.angle * (180 / 3.1415)) ade.draw_line(x, y, rx, ry, ade.color.GRAY, 2) if (type == "segment"): s_x, s_y = shape.a e_x, e_y = shape.b ade.draw_line(s_x, s_y, e_x, e_y, shape.color, shape.radius)
def draw_hit_box(self, color: Color = BLACK, line_thickness: float = 1): """ Draw a sprite's hit-box. The 'hit box' drawing is cached, so if you change the color/line thickness later, it won't take. :param color: Color of box :param line_thickness: How thick the box should be """ if self._hit_box_shape is None: # Adjust the hitbox point_list = [] for point in self.hit_box: # Get a copy of the point point = [point[0], point[1]] # Scale the point if self.scale != 1: point[0] *= self.scale point[1] *= self.scale # Rotate the point if self.angle: point = rotate_point(point[0], point[1], 0, 0, self.angle) point_list.append(point) shape = create_line_loop(point_list, color, line_thickness) self._hit_box_shape = ShapeElementList() self._hit_box_shape.append(shape) self._hit_box_shape.center_x = self.center_x self._hit_box_shape.center_y = self.center_y self._hit_box_shape.angle = self.angle self._hit_box_shape.draw()
def get_adjusted_hit_box(self) -> PointList: """ Get the points that make up the hit box for the rect that makes up the sprite, including rotation and scaling. """ # If we've already calculated the adjusted hit box, use the cached version if self._point_list_cache is not None: return self._point_list_cache # Adjust the hitbox point_list = [] for point in self.hit_box: # Get a copy of the point point = [point[0], point[1]] # Scale the point if self.scale != 1: point[0] *= self.scale point[1] *= self.scale # Rotate the point if self.angle: point = rotate_point(point[0], point[1], 0, 0, self.angle) # Offset the point point = [point[0] + self.center_x, point[1] + self.center_y] point_list.append(point) # Cache the results self._point_list_cache = point_list # if self.texture: # print(self.texture.name, self._point_list_cache) return self._point_list_cache
def get_adjusted_hit_box(self) -> Tuple[Tuple[float, float], ...]: """ Get the points that make up the hit box for the rect that makes up the sprite, including rotation and scaling. """ if self._point_list_cache is not None: return self._point_list_cache if self._points is None: x1, y1 = -self.width / 2, -self.height / 2 x2, y2 = +self.width / 2, -self.height / 2 x3, y3 = +self.width / 2, +self.height / 2 x4, y4 = -self.width / 2, +self.height / 2 self._points = ((x1, y1), (x2, y2), (x3, y3), (x4, y4)) point_list = [] for point_idx in range(len(self._points)): # Get the point point = [self._points[point_idx][0], self._points[point_idx][1]] # Rotate the point if self.angle: point = rotate_point(point[0], point[1], 0, 0, self.angle) # Scale the point if self.scale != 1: point[0] *= self.scale point[1] *= self.scale # Offset the point point = (point[0] + self.center_x, point[1] + self.center_y) point_list.append(point) self._point_list_cache = tuple(point_list) return self._point_list_cache
def get_adjusted_hit_box(self) -> List[List[float]]: """ Get the points that make up the hit box for the rect that makes up the sprite, including rotation and scaling. """ # If we've already calculated the adjusted hit box, use the cached version if self._point_list_cache is not None: return self._point_list_cache # If there is no hitbox, use the width/height to get one if self._points is None and self._texture: self._points = self._texture.hit_box_points # Infer points from texture properties if self._points is None and self._texture and self._texture.width: self._points = points_from_dimensions( self._texture.width, self.texture.height) self._inferred_points_by_texture = True # Infer points from sprite properties if self._points is None and self._width: self._points = points_from_dimensions(self._width, self._height) if self._points is None and self.texture is not None: self._points = self.texture.hit_box_points if self._points is None: raise ValueError("Error trying to get the hit box of a sprite, when no hit box is set.\nPlease make sure the " "Sprite.texture is set to a texture before trying to draw or do collision testing.\n" "Alternatively, manually call Sprite.set_hit_box with points for your hitbox.") # Adjust the hitbox point_list = [] # only apply width and height ratio if we get our points from the texture width_ratio = 0. height_ratio = 0. if self._texture: # Points should have been gotten from the texture # Apply dimensions ratio. # Todo: reset _points if texture is set after _points. width_ratio = self._width / self._texture.width height_ratio = self._height / self._texture.height for point in self._points: # Get a copy of the point point = [point[0], point[1]] # take height and width into account if width_ratio: point[0] *= width_ratio if height_ratio: point[1] *= height_ratio # Rotate the point if self.angle: point = rotate_point(point[0], point[1], 0, 0, self.angle) # Offset the point point = [point[0] + self.center_x, point[1] + self.center_y] point_list.append(point) # Cache the results self._point_list_cache = point_list # if self.texture: # print(self.texture.name, self._point_list_cache) return self._point_list_cache
def test_rotate_point(mock_window): from arcade import rotate_point x, y = rotate_point(1, 1, 0, 0, 90) assert (-1.0, 1.0) == (x, y)
def create_rectangle(center_x: float, center_y: float, width: float, height: float, color: Color, border_width: float = 1, tilt_angle: float = 0, filled=True) -> Shape: """ This function creates a rectangle using a vertex buffer object. The function returns a Shape object that can be drawn with ``my_shape.draw()``. Don't create the shape in the draw method, create it in the setup method and then draw it in ``on_draw``. For even faster performance, add multiple shapes into a ShapeElementList and draw that list. This allows nearly unlimited shapes to be drawn just as fast as one. :param float center_x: :param float center_y: :param float width: :param float height: :param Color color: :param float border_width: :param float tilt_angle: :param bool filled: """ data: List[Point] = cast(List[Point], get_rectangle_points(center_x, center_y, width, height, tilt_angle)) if filled: shape_mode = gl.GL_TRIANGLE_STRIP data[-2:] = reversed(data[-2:]) else: i_lb = center_x - width / 2 + border_width / 2, center_y - height / 2 + border_width / 2 i_rb = center_x + width / 2 - border_width / 2, center_y - height / 2 + border_width / 2 i_rt = center_x + width / 2 - border_width / 2, center_y + height / 2 - border_width / 2 i_lt = center_x - width / 2 + border_width / 2, center_y + height / 2 - border_width / 2 o_lb = center_x - width / 2 - border_width / 2, center_y - height / 2 - border_width / 2 o_rb = center_x + width / 2 + border_width / 2, center_y - height / 2 - border_width / 2 o_rt = center_x + width / 2 + border_width / 2, center_y + height / 2 + border_width / 2 o_lt = center_x - width / 2 - border_width / 2, center_y + height / 2 + border_width / 2 data = [o_lt, i_lt, o_rt, i_rt, o_rb, i_rb, o_lb, i_lb, o_lt, i_lt] if tilt_angle != 0: point_list_2: List[Point] = [] for point in data: new_point = rotate_point(point[0], point[1], center_x, center_y, tilt_angle) point_list_2.append(new_point) data = point_list_2 border_width = 1 shape_mode = gl.GL_TRIANGLE_STRIP # _generic_draw_line_strip(point_list, color, gl.GL_TRIANGLE_STRIP) # shape_mode = gl.GL_LINE_STRIP # data.append(data[0]) shape = create_line_generic(data, color, shape_mode, border_width) return shape
def draw_ellipse_outline(center_x: float, center_y: float, width: float, height: float, color: Color, border_width: float = 1, tilt_angle: float = 0, num_segments: int = 128): """ Draw the outline of an ellipse. :param float center_x: x position that is the center of the circle. :param float center_y: y position that is the center of the circle. :param float width: width of the ellipse. :param float height: height of the ellipse. :param Color color: color, specified in a list of 3 or 4 bytes in RGB or RGBA format. :param float border_width: Width of the circle outline in pixels. :param float tilt_angle: Angle in degrees to tilt the ellipse. :param int num_segments: Number of line segments used to make the ellipse """ if border_width == 1: unrotated_point_list = [] for segment in range(num_segments): theta = 2.0 * 3.1415926 * segment / num_segments x = (width / 2) * math.cos(theta) y = (height / 2) * math.sin(theta) unrotated_point_list.append([x, y]) if tilt_angle == 0: uncentered_point_list = unrotated_point_list else: uncentered_point_list = [] for point in unrotated_point_list: uncentered_point_list.append( rotate_point(point[0], point[1], 0, 0, tilt_angle)) point_list = [] for point in uncentered_point_list: point_list.append((point[0] + center_x, point[1] + center_y)) _generic_draw_line_strip(point_list, color, gl.GL_LINE_LOOP) else: unrotated_point_list = [] start_segment = 0 end_segment = num_segments inside_width = (width / 2) - border_width / 2 outside_width = (width / 2) + border_width / 2 inside_height = (height / 2) - border_width / 2 outside_height = (height / 2) + border_width / 2 for segment in range(start_segment, end_segment + 1): theta = 2.0 * math.pi * segment / num_segments x1 = inside_width * math.cos(theta) y1 = inside_height * math.sin(theta) x2 = outside_width * math.cos(theta) y2 = outside_height * math.sin(theta) unrotated_point_list.append([x1, y1]) unrotated_point_list.append([x2, y2]) if tilt_angle == 0: uncentered_point_list = unrotated_point_list else: uncentered_point_list = [] for point in unrotated_point_list: uncentered_point_list.append( rotate_point(point[0], point[1], 0, 0, tilt_angle)) point_list = [] for point in uncentered_point_list: point_list.append((point[0] + center_x, point[1] + center_y)) _generic_draw_line_strip(point_list, color, gl.GL_TRIANGLE_STRIP)